Dependency Scanning
Your dependencies are your attack surface. Modern applications rely on hundreds or thousands of third-party packages, each one a potential entry point for attackers. A single vulnerable dependency — one you never wrote, never reviewed, and maybe never even knew existed — can compromise your entire system. Dependency scanning automates the process of finding known vulnerabilities in the packages your application uses.
The Dependency Problem
The average Node.js application installs over 1,000 transitive dependencies. A Python web application typically pulls in 50-200 packages. Each of these packages has its own dependencies, creating a tree that no human can manually review.
# A simple Express app's dependency tree
express@4.18.2
accepts@1.3.8
mime-types@2.1.35
mime-db@1.52.0
negotiator@0.6.3
body-parser@1.20.1
bytes@3.1.2
content-type@1.0.5
...
# 30+ more direct dependencies, 200+ transitive
You are responsible for vulnerabilities in every package in this tree. When a vulnerability is discovered in mime-db — a package you have never heard of — your application is vulnerable too.
Language-Specific Audit Tools
Every major package ecosystem provides a built-in audit command.
npm audit (JavaScript/Node.js)
$ npm audit
found 12 vulnerabilities (3 low, 5 moderate, 3 high, 1 critical)
Critical: Prototype Pollution in lodash
Package: lodash
Patched in: >=4.17.21
Dependency of: my-app
Path: my-app > old-library > lodash
$ npm audit fix
fixed 9 of 12 vulnerabilities
3 vulnerabilities required manual review
npm audit fix automatically updates packages to patched versions when possible. Some fixes require major version bumps that could break compatibility — these require manual intervention with npm audit fix --force.
pip-audit (Python)
$ pip-audit
Found 3 known vulnerabilities in 2 packages
Name Version ID Fix Versions
requests 2.25.0 PYSEC-2023-74 2.31.0
urllib3 1.26.5 PYSEC-2023-212 1.26.18, 2.0.7
urllib3 1.26.5 PYSEC-2023-135 1.26.17, 2.0.6
pip-audit checks packages against the Python Advisory Database and the OSV database. It works with requirements files, Poetry lock files, and virtual environments.
cargo-audit (Rust)
$ cargo audit
Crate: chrono
Version: 0.4.19
Warning: unsound
Title: Potential segfault in localtime_r invocations
Date: 2020-11-10
ID: RUSTSEC-2020-0159
URL: https://rustsec.org/advisories/RUSTSEC-2020-0159
Cargo-audit checks Cargo.lock against the RustSec Advisory Database. Rust's strong type system prevents many vulnerability classes, but logic bugs and unsafe code blocks remain sources of vulnerabilities.
Automated Update Tools
Manual dependency updates do not scale. Automated tools create pull requests when new versions are available, especially security patches.
Dependabot
GitHub's built-in dependency update tool. It scans your dependency files daily and opens pull requests for outdated or vulnerable packages.
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
reviewers:
- "security-team"
Dependabot groups related updates and provides compatibility scores based on how many other projects successfully updated to the same version.
Snyk
Snyk provides deeper vulnerability analysis than built-in audit tools. It maps vulnerability reachability — determining whether your code actually calls the vulnerable function, not just whether the package is installed. This dramatically reduces false positives.
Snyk also scans container images, Infrastructure as Code files, and custom code. It integrates with CI/CD pipelines and provides fix pull requests with detailed explanations.
Renovate
Renovate is an open-source alternative to Dependabot with more configuration options. It supports monorepos, custom versioning schemes, and complex update strategies.
# renovate.json
{
"extends": ["config:base"],
"packageRules": [
{
"matchUpdateTypes": ["patch"],
"automerge": true
},
{
"matchPackagePatterns": ["^@types/"],
"automerge": true
}
],
"vulnerabilityAlerts": {
"enabled": true,
"labels": ["security"]
}
}
Renovate can auto-merge patch updates that pass CI, reducing the manual burden of dependency management.
Software Bill of Materials (SBOM)
An SBOM is a complete inventory of every component in your software. It answers the question: "What exactly is in this application?"
# CycloneDX SBOM format (simplified)
{
"bomFormat": "CycloneDX",
"components": [
{
"type": "library",
"name": "express",
"version": "4.18.2",
"purl": "pkg:npm/express@4.18.2"
},
{
"type": "library",
"name": "lodash",
"version": "4.17.21",
"purl": "pkg:npm/lodash@4.17.21"
}
]
}
SBOMs are increasingly required by regulation. US Executive Order 14028 mandates SBOMs for software sold to federal agencies. When a new vulnerability is disclosed, an SBOM lets you instantly determine whether you are affected — without scanning every system from scratch.
Generate SBOMs with tools like Syft, CycloneDX CLI, or SPDX tools. Store them alongside your build artifacts.
CVE Databases
The Common Vulnerabilities and Exposures (CVE) system assigns unique identifiers to publicly known vulnerabilities.
NVD (National Vulnerability Database). The US government's comprehensive database, with severity scores (CVSS) and affected version ranges.
OSV (Open Source Vulnerabilities). Google's aggregated database that pulls from language-specific databases and provides a unified API.
GitHub Advisory Database. Curated by GitHub's security team, integrated directly into Dependabot and code scanning.
Each CVE entry includes affected versions, a severity score, a description of the vulnerability, and references to patches or workarounds. Dependency scanners check your installed versions against these databases.
The Log4j Lesson
In December 2021, a critical vulnerability (CVE-2021-44228) was discovered in Log4j, a Java logging library used by virtually every Java application on the planet. The vulnerability allowed remote code execution — an attacker could take over any server running Log4j by sending a single crafted log message.
The impact was unprecedented. Major services including Minecraft, iCloud, Twitter, Steam, and Amazon were affected. Organizations spent weeks determining which of their systems used Log4j — many did not even know they had it as a transitive dependency buried four levels deep in their dependency tree.
Key lessons from Log4j:
- Know your dependencies. Without an SBOM, you cannot quickly determine your exposure.
- Transitive dependencies matter. Log4j was rarely a direct dependency — it was pulled in by other libraries.
- Patch speed is critical. Organizations with automated dependency scanning and update pipelines patched within hours. Others took weeks.
- Minimize dependencies. Every dependency is a liability. If you can accomplish something with standard library code, prefer that.
Keeping Dependencies Minimal & Updated
Audit before adding. Before installing a new package, check its maintenance status, download count, dependency count, and security track record. A package that pulls in 50 transitive dependencies for a simple utility function is not worth the risk.
Remove unused dependencies. Regularly audit for packages that are imported but never used, or that were added for a feature that was later removed. Tools like depcheck (npm) help identify unused packages.
Pin versions in production. Use lock files (package-lock.json, Pipfile.lock, Cargo.lock) to ensure reproducible builds. Never deploy with floating version ranges.
Update regularly. Do not let dependencies go months without updates. The longer you wait, the harder updates become and the longer you are exposed to known vulnerabilities.
Common Pitfalls
- Ignoring audit output. Running
npm auditand seeing 50 vulnerabilities becomes background noise if never addressed. Set a policy: zero critical and high vulnerabilities in production. - Updating only direct dependencies. Transitive dependency vulnerabilities are just as dangerous. Tools like
npm auditand Snyk trace the full dependency tree. - Auto-merging major version updates. Only auto-merge patch updates. Major and minor updates may include breaking changes that require code modifications.
- Not generating SBOMs. When the next Log4j happens, you need to know within minutes whether you are affected, not within weeks.
- Treating dependency updates as low priority. Security patches are time-sensitive. A known vulnerability with a published CVE is actively being exploited within days of disclosure.
Key Takeaways
- Your dependencies are your attack surface — every transitive package is a potential vulnerability.
- Use ecosystem-specific audit tools: npm audit, pip-audit, cargo-audit.
- Automate updates with Dependabot, Snyk, or Renovate to keep dependencies patched.
- Generate and maintain SBOMs so you can quickly assess exposure when new vulnerabilities are disclosed.
- The Log4j incident proved that a single transitive dependency can compromise the entire internet.
- Minimize dependencies, pin versions, remove unused packages, and update regularly.
- Dependency scanning complements SAST and pentesting — it covers a different part of the attack surface.