osv scanner cover
Figure 1. OSV Scanner

Security is a critical aspect of software development, and staying ahead of vulnerabilities is essential for us application developers. Google’s OSV Scanner is a powerful tool that helps detect vulnerabilities in open-source dependencies.

This article will guide us through setting up and using OSV Scanner to secure our projects, scan for invalid licenses, scan OCI images and finally how to fix findings via guided remediation.

What to scan

There are two categories of files that can be scanned, artifacts and lockfiles/manifests:

Artifacts that may be scanned are …​

  • Alpine APK Packages

  • Debian/Ubuntu dpkg/apt Packages

  • Go Binaries

  • Java Uber Jars

  • Node Modules

  • Python wheels

Lockfiles/manifests that may be scanned are…​

  • C/C++: conan.lock + commit scanning

  • Dart: pubspeck.lock

  • Elixir: mix.lock

  • Go: go.mod

  • Haskell: cabal.project.freeze, stack.yaml.lock

  • Java: buildscript-gradle.lockfile, gradle.lockfile, gradle/verification-metadata.xml, pom.xml

  • Javascript: package-lock.json, pnpm-lock.yaml, yarn.lock

  • .NET: deps.json

  • PHP: composer.lock

  • Python: Pipfile.lock, poetry.lock, requirements.txt*, pdm.lock, uv.lock

  • R: renv.lock

  • Ruby: Gemfile.lock

  • Rust: cargo.lock

For a complete list of supported artifacts, lockfiles and manifests please consulte the OSV Scanner Docs: Supported Languages and Lockfiles.

Installation

There are several ways to install the scanner:

Using go
go install github.com/google/osv-scanner/cmd/osv-scanner@v1
Using Homebrew
brew install osv-scanner
Using apk on Alpine
apk add osv-scanner
For other installation variants, please take a look at the OSV Docs: Installation

CVE Scanning

Different environments and locations can contain vulnerabilities or invalid licenses so we proceed step by step…​

Project Sources Scanning

To demonstrate the scan process for a typical Java™ project using Maven or Gradle, we’re creating an empty sample project and add a dependency with known vulnerabilities to it:

Generating a sample Java project with Maven
mkdir osv-sample-project && cd osv-sample-project &&
mvn archetype:generate -DgroupId=com.example -DartifactId=osv-sample -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false &&
cd osv-sample

There, we add the vulnerable dependency com.fasterxml.jackson.core:jackson-databind:2.9.0 to the pom.xml:

pom.xml
<dependencies>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.9.0</version>
    </dependency>
</dependencies>

Now we may scan our fresh project like this..

Scanning by single pom.xml

Scanning the project by its pom.xml
osv-scanner --lockfile=pom.xml

In the response, we receive an interesting list of CVEs:

Scanned /private/tmp/hascode-osv-sample-project/hascode-osv-sample/pom.xml file and found 3 packages
╭─────────────────────────────────────┬──────┬───────────┬─────────────────────────────────────────────┬─────────┬─────────╮
│ OSV URL                             │ CVSS │ ECOSYSTEM │ PACKAGE                                     │ VERSION │ SOURCE  │
├─────────────────────────────────────┼──────┼───────────┼─────────────────────────────────────────────┼─────────┼─────────┤
│ https://osv.dev/GHSA-27xj-rqx5-2255 │ 8.1  │ Maven     │ com.fasterxml.jackson.core:jackson-databind │ 2.9.0   │ pom.xml │
│ https://osv.dev/GHSA-288c-cq4h-88gq │ 7.5  │ Maven     │ com.fasterxml.jackson.core:jackson-databind │ 2.9.0   │ pom.xml │
│ https://osv.dev/GHSA-4gq5-ch57-c2mg │ 9.8  │ Maven     │ com.fasterxml.jackson.core:jackson-databind │ 2.9.0   │ pom.xml │
│ https://osv.dev/GHSA-4w82-r329-3q67 │ 9.8  │ Maven     │ com.fasterxml.jackson.core:jackson-databind │ 2.9.0   │ pom.xml │
│ https://osv.dev/GHSA-57j2-w4cx-62h2 │ 7.5  │ Maven     │ com.fasterxml.jackson.core:jackson-databind │ 2.9.0   │ pom.xml │
│ https://osv.dev/GHSA-58pp-9c76-5625 │ 8.8  │ Maven     │ com.fasterxml.jackson.core:jackson-databind │ 2.9.0   │ pom.xml │
│ https://osv.dev/GHSA-5949-rw7g-wx7w │ 8.1  │ Maven     │ com.fasterxml.jackson.core:jackson-databind │ 2.9.0   │ pom.xml │
│ https://osv.dev/GHSA-5p34-5m6p-p58g │ 9.8  │ Maven     │ com.fasterxml.jackson.core:jackson-databind │ 2.9.0   │ pom.xml │
│ https://osv.dev/GHSA-5r5r-6hpj-8gg9 │ 8.1  │ Maven     │ com.fasterxml.jackson.core:jackson-databind │ 2.9.0   │ pom.xml │
│ https://osv.dev/GHSA-5ww9-j83m-q7qx │ 7.5  │ Maven     │ com.fasterxml.jackson.core:jackson-databind │ 2.9.0   │ pom.xml │
│ https://osv.dev/GHSA-645p-88qh-w398 │ 9.8  │ Maven     │ com.fasterxml.jackson.core:jackson-databind │ 2.9.0   │ pom.xml │
...

Scanning Project Directory

Way more interesting because our OSV scanner analyzes all SBOMs, lockfiles, and git directories in the given path…​

osv-scanner scan source -r /path/to/project
Example given the project above
osv-scanner scan source -r hascode-osv-sample
Scanning dir hascode-osv-sample
Scanned /private/tmp/hascode-osv-sample-project/hascode-osv-sample/pom.xml file and found 3 packages
╭─────────────────────────────────────┬──────┬───────────┬─────────────────────────────────────────────┬─────────┬────────────────────────────╮
│ OSV URL                             │ CVSS │ ECOSYSTEM │ PACKAGE                                     │ VERSION │ SOURCE                     │
├─────────────────────────────────────┼──────┼───────────┼─────────────────────────────────────────────┼─────────┼────────────────────────────┤
│ https://osv.dev/GHSA-27xj-rqx5-2255 │ 8.1  │ Maven     │ com.fasterxml.jackson.core:jackson-databind │ 2.9.0   │ hascode-osv-sample/pom.xml │
│ https://osv.dev/GHSA-288c-cq4h-88gq │ 7.5  │ Maven     │ com.fasterxml.jackson.core:jackson-databind │ 2.9.0   │ hascode-osv-sample/pom.xml │
│ https://osv.dev/GHSA-4gq5-ch57-c2mg │ 9.8  │ Maven     │ com.fasterxml.jackson.core:jackson-databind │ 2.9.0   │ hascode-osv-sample/pom.xml │
│ https://osv.dev/GHSA-4w82-r329-3q67 │ 9.8  │ Maven     │ com.fasterxml.jackson.core:jackson-databind │ 2.9.0   │ hascode-osv-sample/pom.xml │
│ https://osv.dev/GHSA-57j2-w4cx-62h2 │ 7.5  │ Maven     │ com.fasterxml.jackson.core:jackson-databind │ 2.9.0   │ hascode-osv-sample/pom.xml │
│ https://osv.dev/GHSA-58pp-9c76-5625 │ 8.8  │ Maven     │ com.fasterxml.jackson.core:jackson-databind │ 2.9.0   │ hascode-osv-sample/pom.xml │
│ https://osv.dev/GHSA-5949-rw7g-wx7w │ 8.1  │ Maven     │ com.fasterxml.jackson.core:jackson-databind │ 2.9.0   │ hascode-osv-sample/pom.xml │
│ https://osv.dev/GHSA-5p34-5m6p-p58g │ 9.8  │ Maven     │ com.fasterxml.jackson.core:jackson-databind │ 2.9.0   │ hascode-osv-sample/pom.xml │
[...]
For more detailed information about the scan process, its configuration, how to ignore configurations or enable scanning with call analysis, please consult the OSV Scanner Docs: Scan Source.

License Scanning

Using the wrong licenses can cause us a lot of trouble but luckily the OSV Scanner includes a license scan for us…​

Display license information

osv-scanner --licenses /path/to/repository

Using our sample project, this is the output of running the license check:

Example
osv-scanner --licenses ./hascode-osv-sample
[...]
╭────────────┬─────────────────────────╮
│ LICENSE    │ NO. OF PACKAGE VERSIONS │
├────────────┼─────────────────────────┤
│ Apache-2.0 │                       3 │
╰────────────┴─────────────────────────╯

Check against a given Allow-List

osv-scanner --licenses="allowed-license-1,allowed-license-2" /path/to/directory
The licenses must be entered as defined in the SPDX License List!

As an example, we want to run the license check with only the GNU Lesser General Public License v2.1 only as allowed license which gives us a nice warning about the licenses violated:

osv-scanner --licenses="LGPL-2.1-only" hascode-osv-sample
Scanning dir hascode-osv-sample
[...]
╭───────────────────┬───────────┬────────────────────────────────────────────────┬─────────┬────────────────────────────╮
│ LICENSE VIOLATION │ ECOSYSTEM │ PACKAGE                                        │ VERSION │ SOURCE                     │
├───────────────────┼───────────┼────────────────────────────────────────────────┼─────────┼────────────────────────────┤
│ Apache-2.0        │ Maven     │ com.fasterxml.jackson.core:jackson-annotations │ 2.9.0   │ hascode-osv-sample/pom.xml │
│ Apache-2.0        │ Maven     │ com.fasterxml.jackson.core:jackson-core        │ 2.9.0   │ hascode-osv-sample/pom.xml │
│ Apache-2.0        │ Maven     │ com.fasterxml.jackson.core:jackson-databind    │ 2.9.0   │ hascode-osv-sample/pom.xml │
╰───────────────────┴───────────┴────────────────────────────────────────────────┴─────────┴────────────────────────────╯

Container Image Scans

Also important is the ability to scan container images for known vulnerabilities.

Basic syntax for container images scans
osv-scanner scan image <image-name>:<tag>

As an example, we want to scan an old Docker image for Confluent Kafka:

Scanning Kafka Docker Image
osv-scanner scan image confluentinc/cp-kafka:5.4.3
[...]
Container Scanning Result (Debian GNU/Linux 8 (jessie)):
Total 20 packages affected by 55 known vulnerabilities (3 Critical, 23 High, 24 Medium, 5 Low, 0 Unknown) from 1 ecosystem.
55 vulnerabilities can be fixed.


Maven
╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Source:artifact:etc/confluent/docker/docker-utils.jar                                                                                   │
├─────────────────────────────────────────────┬───────────────────┬───────────────┬────────────┬──────────────────┬───────────────────────┤
│ PACKAGE                                     │ INSTALLED VERSION │ FIX AVAILABLE │ VULN COUNT │ INTRODUCED LAYER │ IN BASE IMAGE         │
├─────────────────────────────────────────────┼───────────────────┼───────────────┼────────────┼──────────────────┼───────────────────────┤
│ com.fasterxml.jackson.core:jackson-databind │ 2.10.5            │ Fix Available │          5 │ # 26 Layer       │ confluentinc/cp-kafka │
│ com.google.code.gson:gson                   │ 2.8.5             │ Fix Available │          1 │ # 26 Layer       │ confluentinc/cp-kafka │
│ io.netty:netty-codec                        │ 4.1.48.Final      │ Fix Available │          2 │ # 26 Layer       │ confluentinc/cp-kafka │
│ io.netty:netty-common                       │ 4.1.48.Final      │ Fix Available │          2 │ # 26 Layer       │ confluentinc/cp-kafka │
│ io.netty:netty-handler                      │ 4.1.48.Final      │ Fix Available │          1 │ # 26 Layer       │ confluentinc/cp-kafka │
│ org.apache.zookeeper:zookeeper              │ 3.5.8             │ Fix Available │          1 │ # 26 Layer       │ confluentinc/cp-kafka │
│ org.yaml:snakeyaml                          │ 1.26              │ Fix Available │          7 │ # 26 Layer       │ confluentinc/cp-kafka │
╰─────────────────────────────────────────────┴───────────────────┴───────────────┴────────────┴──────────────────┴───────────────────────╯
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Source:artifact:usr/share/java/kafka/avro-1.9.2.jar                                                              │
├──────────────────────┬───────────────────┬───────────────┬────────────┬──────────────────┬───────────────────────┤
│ PACKAGE              │ INSTALLED VERSION │ FIX AVAILABLE │ VULN COUNT │ INTRODUCED LAYER │ IN BASE IMAGE         │
├──────────────────────┼───────────────────┼───────────────┼────────────┼──────────────────┼───────────────────────┤
│ org.apache.avro:avro │ 1.9.2             │ Fix Available │          2 │ # 48 Layer       │ confluentinc/cp-kafka │
╰──────────────────────┴───────────────────┴───────────────┴────────────┴──────────────────┴───────────────────────╯
╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Source:artifact:usr/share/java/kafka/commons-compress-1.19.jar                                                                  │
├─────────────────────────────────────┬───────────────────┬───────────────┬────────────┬──────────────────┬───────────────────────┤
│ PACKAGE                             │ INSTALLED VERSION │ FIX AVAILABLE │ VULN COUNT │ INTRODUCED LAYER │ IN BASE IMAGE         │
├─────────────────────────────────────┼───────────────────┼───────────────┼────────────┼──────────────────┼───────────────────────┤
│ org.apache.commons:commons-compress │ 1.19              │ Fix Available │          5 │ # 48 Layer       │ confluentinc/cp-kafka │
╰─────────────────────────────────────┴───────────────────┴───────────────┴────────────┴──────────────────┴───────────────────────╯
╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Source:artifact:usr/share/java/kafka/guava-20.0.jar                                                                │
├────────────────────────┬───────────────────┬───────────────┬────────────┬──────────────────┬───────────────────────┤
│ PACKAGE                │ INSTALLED VERSION │ FIX AVAILABLE │ VULN COUNT │ INTRODUCED LAYER │ IN BASE IMAGE         │
├────────────────────────┼───────────────────┼───────────────┼────────────┼──────────────────┼───────────────────────┤
│ com.google.guava:guava │ 20.0              │ Fix Available │          3 │ # 48 Layer       │ confluentinc/cp-kafka │
╰────────────────────────┴───────────────────┴───────────────┴────────────┴──────────────────┴───────────────────────╯
[...]

Guided Remediation

Guided remediation is there to help us developers fix our findings by providing actionable steps.

Supported Strategies

Remediation is still experimental and only supported for the following files:

Ecosystem Config-File Remediation Strategies

npm

package-lock.json

in-place

npm

package.json

relock

Maven

pom.xml

override

There are different remediation strategies, a full list and more detailed information can be found in the OSV Scanner Docs: Remediation Strategies.

The general syntax for remediation is this:

General syntax for remediation
osv-scanner fix --strategy=STRATEGY

So if we wanted to fix our affected dependency in our sample project we do this:

Fixing a CVE in the sample Maven project
osv-scanner fix --strategy=override -M hascode-osv-sample/pom.xml
Resolving hascode-osv-sample/pom.xml...
Found 67 vulnerabilities matching the filter
Can fix 67/67 matching vulnerabilities by overriding 1 dependencies
OVERRIDE-PACKAGE: com.fasterxml.jackson.core:jackson-databind,2.12.7.1
FIXED-VULN-IDS: GHSA-27xj-rqx5-2255,GHSA-288c-cq4h-88gq,GHSA-4gq5-ch57-c2mg,GHSA-4w82-r329-3q67,GHSA-57j2-w4cx-62h2,GHSA-58pp-9c76-5625,GHSA-5949-rw7g-wx7w,GHSA-5p34-5m6p-p58g,GHSA-5r5r-6hpj-8gg9,GHSA-5ww9-j83m-q7qx,GHSA-645p-88qh-w398,GHSA-6fpp-rgj9-8rwc,GHSA-6wqp-v4v6-c87c,GHSA-758m-v56v-grj4,GHSA-85cw-hj65-qqv9,GHSA-89qr-369f-5m5x,GHSA-8c4j-34r4-xr8g,GHSA-8w26-6f25-cm9x,GHSA-95cm-88f5-f2c7,GHSA-9gph-22xh-8x98,GHSA-9m6f-7xcq-8vf8,GHSA-9mxf-g3x6-wv74,GHSA-9vvp-fxw6-jcxr,GHSA-c265-37vj-cwcc,GHSA-c2q3-4qrh-fm48,GHSA-c8hm-7hpq-7jhg,GHSA-cf6r-3wgc-h863,GHSA-cggj-fvv3-cqwv,GHSA-cjjf-94ff-43w7,GHSA-cmfg-87vq-g5g4,GHSA-cvm9-fjm9-3572,GHSA-f3j5-rmmp-3fc5,GHSA-f9hv-mg5h-xcw9,GHSA-f9xh-2qgp-cq57,GHSA-fmmc-742q-jg75,GHSA-fqwf-pjwf-7vqv,GHSA-gjmw-vf9h-g25v,GHSA-gwp4-hfv6-p7hw,GHSA-gww7-p5w4-wrfv,GHSA-h3cw-g4mq-c5x2,GHSA-h4rc-386g-6m85,GHSA-h592-38cm-4ggp,GHSA-h822-r4r5-v8jg,GHSA-j823-4qch-3rgm,GHSA-jjjh-jjxp-wpff,GHSA-m6x4-97wx-4q27,GHSA-mc6h-4qgp-37qh,GHSA-mph4-vhrx-mv67,GHSA-mx7p-6679-8g3q,GHSA-mx9v-gmh4-mgqw,GHSA-p43x-xfjf-5jhr,GHSA-q93h-jc49-78gg,GHSA-qjw2-hr98-qgfh,GHSA-qmqc-x3r4-6v39,GHSA-qr7j-h6gg-jmgc,GHSA-r3gr-cxrf-hg25,GHSA-r695-7vr9-jgc2,GHSA-rf6r-2c4q-2vwg,GHSA-rfx6-vp9g-rh7v,GHSA-rgv9-q543-rqg4,GHSA-rpr3-cw39-3pxh,GHSA-v3xw-c963-f5hc,GHSA-v585-23hc-c647,GHSA-vfqx-33qm-g869,GHSA-w3f4-3q6j-rh82,GHSA-wh8g-3j2c-rqj5,GHSA-x2w5-5m2g-7h5m
REMAINING-VULNS: 0
UNFIXABLE-VULNS: 0
Rewriting hascode-osv-sample/pom.xml...

When we inspect now our changed pom.xml, we can see, that the version of our dependency jackson-databind was changed from 2.9.0 to 2.12.7.1.

OSV Schema

The advisories in the OSV database all use the Open Source Vulnerability format, which is specified in the following schema: https://ossf.github.io/osv-schema/

There is also a JSON Schema that may be used for validations: https://github.com/ossf/osv-schema/blob/main/validation/schema.json

View the complete schema
{
	"schema_version": string,
	"id": string,
	"modified": string,
	"published": string,
	"withdrawn": string,
	"aliases": [ string ],
	"upstream": [ string ],
	"related": [ string ],
	"summary": string,
	"details": string,
	"severity": [ {
		"type": string,
		"score": string
	} ],
	"affected": [ {
		"package": {
			"ecosystem": string,
			"name": string,
			"purl": string
		},
		"severity": [ {
			"type": string,
			"score": string
		} ],
		"ranges": [ {
			"type": string,
			"repo": string,
			"events": [ {
				"introduced": string,
				"fixed": string,
				"last_affected": string,
				"limit": string
			} ],
			"database_specific": { see description }
		} ],
		"versions": [ string ],
		"ecosystem_specific": { see description },
		"database_specific": { see description }
	} ],
	"references": [ {
		"type": string,
		"url": string
	} ],
	"credits": [ {
		"name": string,
		"contact": [ string ],
		"type": string
	} ],
	"database_specific": { see description }
}

Tutorial Sources

Please feel free to download the sample project for the scans from my GitHub repository, fork it there or clone it using Git:

git clone https://github.com/hascode/sample-project-to-scan.git