The Range's package.json pins twelve deliberately old packages. That makes it a clean bench for the question every team argues about eventually: are we missing vulnerabilities because we chose the free scanner?
The answer here is measurable, and smaller than most people expect. What separates these tools is not detection.
Verified — Snyk CLI 1.1306.3 and Trivy 0.72.0, against
app/package-lock.jsonin the Range. Output copied from real runs.
Step 1 — Run both against the same lockfile
git clone https://github.com/jaybilgaye/aiopsone-range
cd aiopsone-range
trivy fs --scanners vuln app/
snyk test --file=app/package-lock.jsonTrivy 54 findings CRITICAL 3 HIGH 21 MEDIUM 23 LOW 7
Snyk 63 findings critical 2 high 22 medium 35 low 4Snyk reports 17% more. Trivy reports 50% more criticals. Both of those framings are true and neither is useful, for the reason the Grype versus Trivy lesson established: compare the sets.
Step 2 — Compare the sets, not the totals
trivy fs --scanners vuln app/ -f json -o trivy-fs.json
snyk test --file=app/package-lock.json --json-file-output=snyk-oss.json
python3 - <<'PY'
import json
t = {v['VulnerabilityID']
for r in json.load(open('trivy-fs.json')).get('Results', [])
for v in (r.get('Vulnerabilities') or [])}
s = {c for v in json.load(open('snyk-oss.json'))['vulnerabilities']
for c in (v.get('identifiers', {}).get('CVE') or [])}
print(f"both : {len(t & s)}")
print(f"trivy only: {len(t - s)} {sorted(t - s)}")
print(f"snyk only : {len(s - t)} {sorted(s - t)}")
PYboth : 51
trivy only: 3 ['CVE-2026-42043', 'GHSA-7q8q-rj6j-mhjq', 'GHSA-mmx7-hfxf-jppx']
snyk only : 5 ['CVE-2025-58754', 'CVE-2026-44494', 'CVE-2026-67316',
'CVE-2026-67319', 'CVE-2026-67321']Fifty-one of roughly fifty-six shared. The overlap is around 90%, and the commercial tool's exclusive set is five CVEs.
Two details worth noticing:
Trivy's exclusives include two GHSA- identifiers with no CVE. Those are GitHub Security Advisories that were never assigned a CVE — a real category, and the CVE-keyed comparison above cannot even see them properly. Matching findings across scanners is harder than it looks when the tools do not share an identifier space.
Snyk reported 63 findings but only 56 CVEs. Some of its findings carry Snyk's own advisory IDs with no CVE at all — its research team publishes ahead of, or instead of, CVE assignment. Part of the gap is genuinely earlier disclosure; part is one CVE counted as several distinct issues.
Step 3 — They also disagree about severity
Same lodash@4.17.4, same axios@0.21.0, different bands. Trivy called 3 findings CRITICAL; Snyk called 2. Snyk put 35 in MEDIUM where Trivy put 23.
This is the Snyk IaC lesson's point again in a different chapter: severity is a vendor's calibration, not a property of the dependency. A --severity CRITICAL gate blocks on three findings with Trivy and two with Snyk, on an identical lockfile.
Step 4 — The number that actually matters
Buried in the Snyk output:
upgradable: 63 patchable: 1Every single finding is fixable by upgrading. Not one requires a patch, a workaround, or waiting on a maintainer.
That reframes the whole exercise. The question was never "did we find 54 or 63". It is "how many of these can somebody fix this afternoon, and what is the smallest set of changes that does it" — and the answer here is all of them, by bumping twelve packages.
Trivy has the same information and expresses it differently — --ignore-unfixed drops anything with no available patch, which is the flag that keeps a gate passable:
trivy fs --scanners vuln --ignore-unfixed --severity HIGH,CRITICAL app/A gate that blocks on unfixable findings gets bypassed, and a bypassed gate is worth less than no gate. That was true in the container chapter and it is true here.
Step 5 — Dependabot is not competing with either of these
Dependabot belongs in this comparison because everyone puts it here, and it does not belong in the same column.
Disclosure: Dependabot was not run for this lesson. It requires the repository to be on GitHub with the feature enabled, and it does its work through pull requests rather than a CLI — there is nothing to execute locally and no output to paste. The Range is currently private, so this section describes its documented model rather than a measured run. It gets its own lesson, with a real pull-request cycle, once the repo is public.
The distinction that matters:
| Trivy | Snyk | Dependabot | |
|---|---|---|---|
| Tells you what is vulnerable | yes | yes | yes |
| Opens the pull request that fixes it | no | on paid tiers | yes, free |
| Runs offline | yes | no | no (GitHub-hosted) |
| Needs an account | no | yes | GitHub |
| Where results live | CI log | hosted project record | pull requests |
Trivy and Snyk are detection. Dependabot is remediation. Given that all 63 findings here are upgradable, the tool that opens twelve upgrade pull requests is doing the part that changes the outcome — and it is free.
The sensible arrangement is not to choose:
# .github/dependabot.yml — remediation, continuous
version: 2
updates:
- package-ecosystem: npm
directory: /app
schedule:
interval: weekly
open-pull-requests-limit: 10# .github/workflows/sca.yml — detection, blocking
- name: Trivy (gate)
run: |
trivy fs --scanners vuln app/ \
--ignore-unfixed \
--severity HIGH,CRITICAL \
--exit-code 1Dependabot proposes the upgrades; Trivy makes sure nothing vulnerable merges. They are answering different questions and neither substitutes for the other.
One warning that belongs with the config above: an auto-merge rule on Dependabot pull requests is only as safe as your test suite. The whole value of an automated dependency upgrade is that it lands without a human, which is also exactly how a breaking minor version reaches production at 2am. Auto-merge patch updates if your tests are good; review minors.
Step 6 — So does Snyk earn the money here
On this evidence, for dependency scanning specifically: not on detection. Five exclusive CVEs against a free tool that also scans your Dockerfile, your Terraform, your images and your filesystem in the same pass is not a purchasing argument.
What is not in Trivy's output:
- Reachability. Whether your code calls the vulnerable function. Thirty-five mediums where five are reachable is a completely different afternoon, and no free scanner tells you which five. This is the real differentiator, and it is the honest answer to "why pay when Trivy is free".
- A durable project record.
--reportsends results to a project with an owner and a history. CI logs expire; CPS 234 evidence is the record of assessment and remediation, not the scan. - Fix pull requests on paid tiers, overlapping what Dependabot does free.
Recommendation: Trivy to gate, Dependabot to remediate, and buy Snyk when you need reachability or the audit record — not because you are worried about the five CVEs. Below roughly twenty repositories the free pair is the correct answer, and the budget is better spent on somebody to action the pull requests.
What you learned
- 63 versus 54 findings, 51 CVEs shared. Around 90% overlap; the commercial tool's exclusive set was five CVEs.
- Trivy's exclusives included two
GHSA-advisories with no CVE — scanners do not share an identifier space, which makes cross-tool matching harder than it looks. - Snyk reported 63 findings from 56 CVEs; some carry Snyk-only advisory IDs published ahead of CVE assignment.
- Severities diverge again: 3 criticals versus 2 on an identical lockfile.
- All 63 were
upgradable. The useful question is not how many were found but how many can be fixed today. - Dependabot is remediation, not detection — it opens the pull request, free. Not measured here; it needs a public repo and a real PR cycle.
- Gate with
--ignore-unfixed. Blocking on unfixable findings is how gates get bypassed. - Pay for reachability and the audit record, not for five CVEs.