CtrlK
BlogDocsLog inGet started
Tessl Logo
PluginPublic

testland/dependency-vulnerability-scanning

Use when a repo needs dependency CVE scanning (SCA) in CI, a team is choosing between native audits (npm audit, pip-audit, cargo audit), OSV-Scanner and Snyk, or findings need triage. Scans lockfiles with thresholds, checks packages were seen, outputs SARIF and allows only expiring ignores.

Quality

92%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide
SecuritybySnyk

Passed

No findings from the security scan

Overview
Quality
Evals
Security
Files
name:
dependency-vulnerability-scanning
description:
Use when a repo needs dependency CVE scanning (SCA) in CI, a team is choosing between native audits (npm audit, pip-audit, cargo audit), OSV-Scanner and Snyk, or findings need triage. Scans lockfiles with thresholds, checks packages were seen, outputs SARIF and allows only expiring ignores.
metadata:
{"keywords":"sca, dependency-scanning, osv-scanner, snyk, npm-audit, pip-audit, cargo-audit, bundler-audit, owasp-dependency-check","version":"1.0.1"}

dependency-vulnerability-scanning

Overview

Software composition analysis (SCA) matches the dependencies a repo declares (lockfiles, manifests, SBOMs) against vulnerability advisory databases. Each scanner family reads a different database, so their coverage differs:

FamilyDatabaseCost
Native audits (npm audit, pip-audit, cargo audit, bundle-audit, Dependency-Check)The ecosystem's own advisory feed (npm, PyPA, RustSec, RubySec, NVD)Free; usually already installed
OSV-ScannerOSV.dev, aggregated across ecosystems (OSV-Scanner usage)Free, open source
SnykSnyk's own database, plus snyk monitor alerts (Snyk CLI)Commercial license

The workflow below is the same for all three; the per-tool detail is in the references.

When to use

  • A repo has no dependency scanning in CI yet.
  • The team must choose between native audits, OSV-Scanner and Snyk, or layer two of them.
  • A scanner reports findings and someone wants to suppress, waive or gate on them.

Step 1 - Pick the scanner

Repo situationStart withReference
One ecosystem, fastest first gate, nothing extra to installThat ecosystem's native auditreferences/native-audits.md
Several ecosystems, open source only, or an SBOM as inputOSV-Scannerreferences/osv-scanner.md
A Snyk license, or alerts on new CVEs against pinned versionsSnykreferences/snyk.md

For full coverage run one native audit plus one cross-ecosystem scanner (OSV-Scanner or Snyk): each database misses advisories the others carry.

Step 2 - Scan the committed lockfile

Scan lockfiles, not loose manifests: a manifest range resolves to whatever is newest today, a lockfile is what actually ships.

npm audit --audit-level=high                     # npm; also yarn npm audit / pnpm audit
pip-audit -r requirements.txt                    # Python
cargo audit                                      # Rust
bundle-audit check --update                      # Ruby; --update refreshes the advisory DB
osv-scanner scan -L package-lock.json            # one lockfile
osv-scanner scan -r ./                           # every lockfile and SBOM under ./
snyk test --all-projects --severity-threshold=high

SBOM input: OSV-Scanner picks up SBOMs whose names follow the SPDX or CycloneDX patterns (*.spdx.json, bom.json, *.cdx.json) and scans one directly with osv-scanner scan source -L my-app.cdx.json; the components need Package URLs (OSV-Scanner source scanning). Snyk scans one with snyk sbom test --file=my-app.cdx.json (CycloneDX 1.4-1.6 JSON or SPDX 2.3 JSON, Enterprise plans) (Snyk sbom test). syft-generation produces the SBOM.

Step 3 - Check the scan saw packages

A scan that found no lockfile passes silently. Before trusting a green result, confirm the scanner reported the packages you expect.

OSV-Scanner makes this explicit with its exit codes (OSV-Scanner output):

Exit codeMeaningCI action
0Packages found, no known vulnerabilitiesPass
1Packages found, vulnerabilities foundFail (or triage, Step 5)
127General errorFail
128No packages foundFail: the scan did nothing; fix the path or lockfile name

For the other scanners, read the JSON report's dependency count, or run once against a branch with a known-vulnerable pin and confirm the job goes red.

Step 4 - Emit machine-readable output

osv-scanner scan -r ./ --format sarif --output-file osv.sarif
snyk test --sarif-file-output=snyk.sarif
pip-audit --format sarif --output pip-audit.sarif
npm audit --json > npm-audit.json

--format and --output-file are OSV-Scanner's output flags (OSV-Scanner usage); the container image takes the same arguments (installation). Upload SARIF to code scanning, and pass two or more reports to multi-tool-finding-triage (or the security-finding-triager agent) to dedupe findings across scanners.

Step 5 - False-positive triage

Suppress a finding only in a committed file, per advisory, with a reason, an approver and an expiry date, so it comes back for review:

ScannerSuppressionExpiry
Snyk.snyk ignore: entryexpires: (required)
OSV-Scannerosv-scanner.toml [[IgnoredVulns]]ignoreUntil
pip-audit--ignore-vuln <id>Record in a committed ignore list
Dependency-Checkdependency-check-suppressions.xml<suppress until="2026-12-31Z"> (suppression docs)
cargo audit.cargo/audit.toml [advisories] ignoreRecord in the justification
bundler-audit.bundler-audit.yml ignore:Record in the justification

Before suppressing as "not exploitable", prove it: reachability-analyzer checks whether the vulnerable function is called, and cve-exploitability-triage weighs EPSS and KEV. A severity threshold (--audit-level, --severity-threshold) is a scan filter, not a suppression. Templates per tool: references/snyk-policy-and-triage.md, references/osv-scanner-config-and-ci.md, references/ecosystem-config-and-triage.md, references/cargo-bundle-audit.md.

Step 6 - Gate CI

jobs:
  sca:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - if: hashFiles('package-lock.json') != ''
        run: npm audit --audit-level=high
      - if: hashFiles('requirements.txt') != ''
        run: pipx run pip-audit -r requirements.txt
      - name: OSV-Scanner (fails on findings and on exit 128)
        run: |
          docker run --rm -v "$PWD:/src" ghcr.io/google/osv-scanner:latest \
            scan -r /src --format sarif --output-file /src/osv.sarif
      - if: always()
        uses: github/codeql-action/upload-sarif@v3
        with: { sarif_file: osv.sarif }

With a Snyk license, add snyk test --severity-threshold=high on pull requests and snyk monitor on the default branch, which snapshots the dependency tree and alerts on CVEs disclosed later (Snyk CLI); the full job is in references/snyk.md.

Worked example

A Node + Python service has no SCA. Step 1: two ecosystems, no Snyk license, so npm audit and pip-audit as the fast gate plus OSV-Scanner for cross-ecosystem coverage. The first OSV run exits 128: the Python lockfile is requirements-lock.txt, a name OSV-Scanner does not detect, so the job is pointed at it with -L requirements-lock.txt and now exits 1 with two findings. One is a lodash advisory in a function the service never calls; reachability-analyzer confirms it, and an [[IgnoredVulns]] entry with ignoreUntil 90 days out and the approver's name goes into osv-scanner.toml. The other is upgraded. The job goes green, and the ignore resurfaces when it expires.

Anti-patterns

Anti-patternWhy it failsFix
No severity threshold on the first runLow-severity noise; the team turns the job off--audit-level=high / --severity-threshold=high
Treating any non-1 exit as greenOSV exit 128 means nothing was scannedFail on 128 (Step 3)
Suppression with no expiryDebt never comes back for reviewexpires: / ignoreUntil (Step 5)
One scanner onlyEach advisory database has gapsNative audit plus OSV-Scanner or Snyk (Step 1)
npm audit fix --force in CISilently bumps major versionsReview forced upgrades by hand
Token in scriptsLeaks SNYK_TOKENCI secret

Limitations

  • No scanner here does reachability: every advisory on a declared dependency counts, used or not. Use reachability-analyzer.
  • Coverage differs by ecosystem in every database.
  • Container images need trivy-image or the Grype flow in syft-generation.
  • Automated upgrade PRs are dependabot-config and renovate-config.

References

Workspace
testland
Visibility
Public
Created
Last updated
Source
GitHub Actions
Repository
https://github.com/testland/qaVerified
Badge
testland/dependency-vulnerability-scanning badge