OSV-Scanner, Google's open source scanner, shipped v2.7.0 on 12 October 2026. It reads a lockfile, asks the OSV database which versions are known vulnerable, and prints a table. This walkthrough runs it on a real lockfile so you can see every step and reproduce it.
The test project depends on @fastify/jwt 10.2.0, with the lockfile resolved as of 29 July 2026. That pins fast-jwt at 6.3.0, which has two published advisories as of 18 October 2026. We ran version 2.5.1 locally, so your output may differ in small ways from newer releases.
What's affected
In the test lockfile, one package is affected by two advisories:
| Advisory | Severity in output | Fixed in |
|---|---|---|
| GHSA-8wpc-h4q6-8fxv (published 8 October 2026) | CVSS 7.4 | 6.3.1 |
| GHSA-x937-hj6v-793p | CVSS 4.2 | 6.3.4 |
The first is a CVE-2026-107720 signature bypass: createVerifier skips signature verification when the key is an empty string or null and an algorithms list is set. It is mapped to CWE-347, improper verification of a cryptographic signature.
How to check if you're exposed
Recreate the project and scan it:
mkdir demo && cd demo
echo '{"name":"demo","version":"1.0.0","dependencies":{"@fastify/jwt":"10.2.0"}}' > package.json
npm install --before=2026-07-29 --ignore-scripts
osv-scanner scan -L package-lock.json
The --before flag makes npm resolve as if it were that date, which gives a realistic stale lockfile. The scan prints a summary and a table:
Total 1 package affected by 2 known vulnerabilities (0 Critical, 1 High, 1 Medium, 0 Low, 0 Unknown) from 1 ecosystem.
2 vulnerabilities can be fixed.
| OSV URL | CVSS | ECOSYSTEM | PACKAGE | VERSION | FIXED VERSION | SOURCE |
| https://osv.dev/GHSA-8wpc-h4q6-8fxv | 7.4 | npm | fast-jwt | 6.3.0 | 6.3.1 | package-lock.json |
| https://osv.dev/GHSA-x937-hj6v-793p | 4.2 | npm | fast-jwt | 6.3.0 | 6.3.4 | package-lock.json |
Other forms from the official usage docs:
osv-scanner scan -r ./my-project-dir/
osv-scanner scan -L package-lock.json --format json
The first scans a directory recursively. The second emits JSON, which you can filter:
osv-scanner scan -L package-lock.json --format json \
| jq -r '.results[0].packages[] | select(.vulnerabilities | length > 0) | .package.name, (.vulnerabilities[].id)'
The exit code is 1 when vulnerabilities are found and 0 when clean, which makes it usable as a CI gate. In our run it exited 1.
Where the data comes from
OSV-Scanner matches each package name and version in the lockfile against the OSV database, which aggregates advisories from sources such as GitHub's advisory database. That is why the table links to osv.dev pages and why the identifiers are GHSA IDs. The same record is available from the API:
curl -s https://api.osv.dev/v1/vulns/GHSA-8wpc-h4q6-8fxv | jq '{id, aliases, published}'
It shows the alias CVE-2026-107720 and a published date of 8 October 2026. If your policy is written in CVE terms, use the aliases field to translate.
Two other details from the release notes for v2.7.0 are worth knowing. JSON output now includes package URLs where available, and CycloneDX output includes vulnerability severity and rating. The same release made the --offline mode with downloaded databases stop running plugins that need the network. If you scan in an air gapped build, check the release notes for your version.
In the JSON output each affected package has a groups field. The scanner groups advisories that are aliases of one another, so one underlying bug published as both a GHSA and a CVE counts once. In our run each of the two fast-jwt advisories was its own group.
What to do now
- Run the scan on every lockfile you ship, not just the root one. Use
-rfor monorepos. - Read the FIXED VERSION column first. Both advisories here have a fix, and 6.3.4 covers both.
- Check whether your range already allows the fix. Here
@fastify/jwtasks for^6.2.4, sonpm update fast-jwtis enough, with no overrides needed. - Re-run the scan after the update and confirm exit code 0.
- Add the command to CI so a newly published advisory fails the build the next day rather than the next quarter.
Why it matters
A lockfile is a snapshot. The code in it stays the same while the advisory database keeps growing, so a lockfile that passed in July fails in October without a single commit. Scanning on a schedule matters as much as scanning on a pull request.
The scan also tells you what is present, not what is reachable. A vulnerable function that your code never calls is a lower priority than one on a hot path, which is the question reachability analysis answers.
Try it yourself
Run the four setup commands above, then change the date in --before to 2026-10-16 and compare the scan results. The second run should come back clean.
Click through it at your own pace, or open it full screen.
You can also drop a package.json into the free scanner at gold.safeguard.sh/scan. It runs in your browser and the file never leaves your machine.
Quick check
Why does a lockfile that was clean in July fail a scan in October?
The lockfile did not change but the vulnerability database did. New advisories were published against the versions it pins.
What does exit code 1 from osv-scanner mean?
It found at least one known vulnerability, so a CI job running it will fail.