Your application has 47 direct dependencies. Those pull in 400 transitive dependencies. One of them — json5@2.1.0, four levels deep in your lock file, dragged in by a Babel preset that a Webpack plugin depends on — just got a CVE for prototype pollution. Your team didn't install it, didn't choose it, and doesn't know it exists. But it's in your production bundle, and your scanner just flagged it alongside 83 other findings, 79 of which will never be exploited by anyone.
This is the daily reality of modern software development. The average application carries hundreds of third-party packages, each one a potential entry point for attackers. Dependency vulnerability scanning exists to find these known security flaws before they reach production. But finding vulnerabilities is only half the problem — the harder challenge is figuring out which ones actually matter.
Most teams either ignore scanner output entirely (too noisy) or treat every finding as urgent (too exhausting). Both approaches fail. What works is scanning that tells you not just what's vulnerable, but what's actively being exploited in the wild. That's the gap between basic scanning and practical security.
TL;DR: Dependency vulnerability scanning identifies known security flaws in your project's third-party packages by matching dependency versions against vulnerability databases. The critical insight: at most about 6% of CVEs are ever exploited, so raw CVSS scores generate overwhelming noise. Effective scanning enriches results with EPSS (exploitation probability) and CISA KEV (confirmed exploitation) to surface the vulnerabilities that actually threaten your application. Every major ecosystem has a built-in scanner, but none of them provide this enrichment.
What We'll Cover
- What dependency vulnerability scanning actually is
- How the scanning pipeline works, step by step
- Why CVSS alone produces more noise than signal
- Comparison of native scanners across 8 ecosystems
- Types of security scanning and where SCA fits
- When and where to run scans in your workflow
- Getting started with your first scan
- Frequently asked questions
What Is Dependency Vulnerability Scanning?
Dependency vulnerability scanning is the process of analyzing your project's third-party packages — both direct dependencies and their transitive sub-dependencies — against databases of known security vulnerabilities to identify components with published CVEs, security advisories, or other disclosed flaws. It is a core practice within Software Composition Analysis (SCA), focused specifically on the open-source and third-party code that makes up 70-90% of modern applications.
In practical terms, a scanner reads your project's manifest or lock file (package-lock.json, poetry.lock, go.sum, pom.xml, etc.), resolves the full dependency tree including transitive packages, and checks each package-version pair against vulnerability databases like OSV, NVD, and ecosystem-specific advisory feeds. The output is a list of known vulnerabilities affecting your dependency tree, ideally ranked by actual risk rather than theoretical severity.
The distinction between "theoretical severity" and "actual risk" is where most built-in ecosystem scanners fall short — and where the real value of modern scanning tools emerges.
How Dependency Scanning Works
The scanning pipeline follows a consistent pattern regardless of ecosystem or tool. Understanding each stage helps you evaluate what your current scanner does well and where it has gaps.
Lock file --> Parser --> Package List --> Database Match --> Enrichment --> Priority Report
| | | | | |
| | | | | |
manifest ecosystem- resolved OSV, NVD, EPSS score, ranked
or lock aware parse name@version GitHub KEV status, findings
file pairs advisories CVSS vector with context
Step 1: Manifest and lock file parsing. The scanner reads your dependency declaration files. Lock files (package-lock.json, Pipfile.lock, composer.lock) are strongly preferred over manifests (package.json, requirements.txt) because they contain exact resolved versions for the entire transitive tree. Without a lock file, the scanner must either resolve versions itself (slow and potentially inaccurate) or only scan direct dependencies (missing the vast majority of your attack surface).
Different ecosystems use different file formats, and some have multiple competing formats. Python alone has requirements.txt, setup.py, setup.cfg, pyproject.toml, poetry.lock, and Pipfile.lock. A good scanner handles all of them. A mediocre scanner handles requirements.txt and calls it done.
Step 2: Package list resolution. The parser produces a flat list of package-name-at-version pairs. For a typical Node.js application, this might be 400-1,200 entries. For a Java application with Maven, it can exceed 2,000. Each entry needs to be checked against vulnerability databases — which means the database matching step needs to be fast.
Step 3: Vulnerability database matching. The scanner queries one or more vulnerability databases to find advisories that affect the specific versions in your dependency tree. The major databases include:
- OSV (Open Source Vulnerabilities): Google's aggregated database covering multiple ecosystems. Uses precise version range matching rather than CPE-based lookups, which dramatically reduces false positives.
- NVD (National Vulnerability Database): NIST's comprehensive CVE database. Broad coverage but uses CPE identifiers that can produce inaccurate matches for some ecosystems.
- GitHub Advisory Database: Curated advisories with ecosystem-specific version ranges. Good quality but GitHub-ecosystem focused.
- Ecosystem-specific feeds: npm audit uses GitHub's advisory data, PyPI has its own advisory system, RustSec maintains the Rust advisory database.
No single database has complete coverage. OSV aggregates from multiple upstream sources (GitHub, PyPI, RustSec, Go vulnerability database, and others), which makes it the most practical single source — but even OSV has gaps where advisories haven't been submitted upstream.
Step 4: Enrichment. This is where basic scanners stop and effective scanners keep going. Raw advisory data tells you a vulnerability exists and gives you a CVSS severity score. Enrichment adds the context you need to prioritize:
- EPSS (Exploit Prediction Scoring System): A machine-learning model that estimates the probability a vulnerability will be exploited in the next 30 days. Scores range from 0 to 1.0. A CVE with EPSS 0.97 is almost certainly being actively exploited. A CVE with EPSS 0.001 almost certainly is not.
- CISA KEV (Known Exploited Vulnerabilities): A catalog maintained by the US Cybersecurity and Infrastructure Security Agency listing vulnerabilities confirmed to be exploited in the wild. If a CVE is on this list, it's not theoretical — attackers are using it right now.
- CVSS vector details: Beyond the summary score (7.5 HIGH), the full CVSS vector tells you whether exploitation requires network access, user interaction, specific privileges, or unusual configurations.
Step 5: Prioritized reporting. The final output should rank findings by actual risk, not alphabetical order or raw CVSS score. A CVSS 9.8 critical with EPSS 0.0003 and no KEV listing is almost certainly less urgent than a CVSS 7.2 high that's on the KEV catalog with EPSS 0.85. Without enrichment, your team treats both as equally critical — or more likely, burns out from alert fatigue and stops looking at scan results entirely.
Why CVSS Alone Isn't Enough
CVSS (Common Vulnerability Scoring System) measures the theoretical severity of a vulnerability — how bad it could be if exploited, based on the attack vector, complexity, privileges required, and impact. It does not measure how likely the vulnerability is to be exploited.
This distinction matters enormously in practice. Research consistently shows that at most about 6% of published CVEs are ever exploited in the wild, and stricter datasets put it nearer 1–2%. The rest generate scanner alerts, create Jira tickets, and consume engineering time — but never become actual attacks. CVSS cannot distinguish between the exploited slice and the remainder.
Consider a concrete example. In 2025, two high-profile CVEs affected widely-used packages:
- CVE-A: CVSS 9.8 (Critical). Remote code execution in a serialization library. Requires the application to deserialize untrusted input using a specific deprecated method. EPSS: 0.002. Not on CISA KEV.
- CVE-B: CVSS 7.5 (High). Server-side request forgery in a popular HTTP client. Trivially exploitable with a crafted URL parameter. EPSS: 0.89. On CISA KEV since January 2025.
A CVSS-only scanner ranks CVE-A higher. A scanner with EPSS and KEV enrichment correctly identifies CVE-B as the urgent threat. The team that patches CVE-B first is protected against an active attack campaign. The team that patches CVE-A first spent their limited security time on a vulnerability that nobody is exploiting.
This isn't an argument against CVSS — it's an argument for using CVSS alongside exploitation data. For a deeper comparison, see CVSS vs EPSS: Which Vulnerability Score Actually Matters?.
Ecosystem Scanner Comparison
Every major package ecosystem now includes a built-in vulnerability scanning tool. These tools are free, easy to use, and a reasonable starting point. They also share common limitations: none of them provide EPSS enrichment, none check CISA KEV status, and none of them scan across ecosystems.
| Ecosystem | Built-in Tool | EPSS? | KEV? | Multi-ecosystem? | Historical Tracking? |
|---|---|---|---|---|---|
| npm | npm audit | No | No | No | No |
| Python | pip-audit | No | No | No | No |
| Go | govulncheck | No | No | No | No |
| Java | mvn dependency-check | Partial | No | Limited | No |
| Rust | cargo audit | No | No | No | No |
| PHP | composer audit | No | No | No | No |
| Ruby | bundler-audit | No | No | No | No |
| .NET | dotnet list package --vulnerable | No | No | No | No |
npm ships npm audit built into the CLI, making it the most accessible ecosystem scanner. It queries GitHub's advisory database and provides fix suggestions. Limitations: noisy output with many low-severity findings, no exploitation context, and the --fix flag can introduce breaking changes. See npm audit vs GeekWala for a detailed comparison.
Python has pip-audit from the Python Packaging Authority. It queries OSV and PyPI's advisory database. Solid tool, but only supports requirements.txt and pip-installed packages — no native support for poetry.lock or Pipfile.lock without conversion. Python's fragmented advisory ecosystem means no single tool catches everything. See Python Dependency Security.
Go benefits from govulncheck, which is unusually precise because it performs call graph analysis — it tells you not just that a vulnerable function exists in a dependency, but whether your code actually calls that function. This dramatically reduces false positives. The trade-off is slower scan times and Go-only coverage. See Go Module Vulnerability Scanning.
Java has OWASP Dependency-Check, which scans Maven and Gradle projects against NVD. It has partial EPSS support through NVD's data but doesn't use the FIRST EPSS model directly. It can also scan some non-Java dependencies, making it one of the few built-in tools with limited multi-ecosystem support. See Java Maven Dependency Security.
Rust uses cargo audit backed by the RustSec Advisory Database. The Rust security community is small but responsive — advisories tend to be high quality with accurate version ranges. The limitation is database coverage: RustSec is curated rather than aggregated, so some CVEs that affect Rust crates via C bindings may not appear. See Securing Rust Dependencies.
PHP added composer audit in Composer 2.4. It queries the Packagist/FriendsOfPHP security advisories database. Coverage is reasonable for popular packages but thinner for less common ones. The PHP ecosystem has historically been slower to adopt security tooling than JavaScript or Python. See PHP Packagist Dependency Security.
Ruby has bundler-audit, a community tool that checks Gemfile.lock against the ruby-advisory-db. It's reliable and well-maintained, but the advisory database is volunteer-curated and can lag behind NVD disclosures. See Ruby Dependency Security.
.NET provides dotnet list package --vulnerable as a built-in CLI option. It queries GitHub's advisory database. Functional but output is minimal — just package names and advisory links, with no severity ranking or remediation guidance. See .NET NuGet Dependency Security.
The common thread: every built-in tool gives you a list of known vulnerabilities. None of them tell you which ones are being actively exploited. For teams managing projects across multiple ecosystems — which is increasingly common as organizations adopt microservices — running 3-5 separate tools and manually correlating results is unsustainable.
Types of Security Scanning
Dependency vulnerability scanning is one category within a broader landscape of application security testing. Understanding where each type fits helps you build a complete security program without redundant tooling.
Static Application Security Testing (SAST) analyzes your source code for security flaws — SQL injection, cross-site scripting, hardcoded credentials, insecure cryptographic usage. SAST tools read your code and apply pattern matching or data flow analysis to find vulnerabilities you wrote. They don't look at dependencies at all. Examples: Semgrep, SonarQube, CodeQL.
Software Composition Analysis (SCA) analyzes your third-party dependencies for known vulnerabilities. SCA tools read your manifest and lock files and check package versions against vulnerability databases. They don't analyze your code — they analyze everyone else's code that your code depends on. This is the category that dependency vulnerability scanning falls into. Examples: GeekWala, Snyk, Dependabot, Grype.
Dynamic Application Security Testing (DAST) tests your running application by sending it malicious inputs and observing the responses. DAST tools don't need source code — they interact with your application the same way an attacker would. They find vulnerabilities that only manifest at runtime, like misconfigured CORS, exposed admin panels, or authentication bypasses. Examples: OWASP ZAP, Burp Suite.
Runtime Application Self-Protection (RASP) embeds security monitoring inside your running application. RASP agents detect and block attacks in real-time — like a WAF that operates inside your application rather than in front of it. Examples: Sqreen (now Datadog), Contrast Security.
These categories are complementary, not competing. SAST finds bugs in your code. SCA finds bugs in your dependencies. DAST finds bugs in your deployment. Most teams should start with SCA (highest signal-to-noise ratio, easiest to automate) and add SAST and DAST as their security program matures.
GeekWala is an SCA tool. It scans your dependency manifests and lock files across 8 ecosystems, matches against OSV vulnerability data, enriches with EPSS and CISA KEV, and gives you a prioritized list of what to fix first. It does not analyze your source code or test your running application — those are problems for different tools.
When to Scan
The right scanning frequency depends on your risk tolerance and deployment cadence. Most teams benefit from scanning at multiple points in their workflow.
Every pull request (CI/CD integration). This is the highest-value integration point. Scanning on every PR catches new vulnerabilities before they merge into your main branch. It also catches newly disclosed vulnerabilities in existing dependencies if your scanner checks against current advisory databases rather than a cached copy. Configure your CI to fail the build (or at least add a warning comment) when high-risk vulnerabilities are detected. See Dependency Scanning in CI/CD with GitHub Actions for setup instructions.
Scheduled daily or weekly scans. New vulnerabilities are disclosed constantly — roughly 80-100 new CVEs per day across all ecosystems. A dependency that was clean yesterday might have a critical advisory today. Scheduled scans catch these disclosures without waiting for the next PR. Daily scanning is appropriate for production applications. Weekly is reasonable for internal tools and staging environments.
Before deployments. A final scan before deploying to production provides a last checkpoint. This catches the edge case where a vulnerability was disclosed between your last CI scan and deployment. For teams deploying multiple times per day, this may be redundant with PR-level scanning. For teams deploying weekly or less frequently, it's essential.
Continuous monitoring. The most mature approach: your scanner monitors your dependency inventory continuously and alerts you when new advisories affect packages in your production applications. This is the difference between "scan when I remember" and "alert me when something changes." GeekWala's scheduled scanning feature (available on Pro plans) provides this layer. See Automated Dependency Scanning for implementation patterns.
The minimum viable scanning program: scan on every PR and run a weekly scheduled scan. That combination catches both new code changes and new vulnerability disclosures with minimal configuration overhead.
Getting Started
The fastest way to understand dependency vulnerability scanning is to scan something. GeekWala offers three starting points depending on how you prefer to work.
Instant anonymous scan. Go to /scan, paste a manifest or lock file, and get results in seconds. No account required. Supports package.json, requirements.txt, go.mod, pom.xml, Cargo.toml, composer.json, Gemfile, and .csproj (plus their lock file variants). Results include EPSS scores and CISA KEV status alongside CVSS severity. You get 3 free scans per day — enough to evaluate whether the enrichment data changes how you'd prioritize fixes.
Dashboard with history. Create a free account to track projects over time, import from GitHub, and monitor up to 5 projects with 200 packages. Free accounts retain 30 days of scan history, which is enough to see whether your vulnerability posture is improving or degrading.
API and CI/CD integration. The API supports programmatic scanning for CI/CD pipelines. Send a manifest file, get back structured JSON with vulnerability data, EPSS scores, and KEV status. Integrate into GitHub Actions, GitLab CI, or any pipeline that can make HTTP requests. See the getting started guide for step-by-step setup.
FAQ
How does dependency vulnerability scanning work?
Dependency vulnerability scanning reads your project's dependency files (like package-lock.json, requirements.txt, or go.sum), resolves the full tree of direct and transitive dependencies, and checks each package-version pair against vulnerability databases such as OSV, NVD, and GitHub Advisories. When a match is found, the scanner reports the CVE identifier, affected version range, severity score, and — if the scanner supports it — exploitation probability (EPSS) and whether the vulnerability is actively being exploited (CISA KEV). The output is a prioritized list of vulnerabilities in your dependency tree, ideally ranked by actual risk rather than theoretical severity alone.
What tools are used for dependency scanning?
Every major ecosystem has a built-in scanner: npm audit for JavaScript, pip-audit for Python, govulncheck for Go, cargo audit for Rust, composer audit for PHP, bundler-audit for Ruby, and dotnet list package --vulnerable for .NET. These are good starting points but limited to single ecosystems and don't include exploitation enrichment data. Cross-ecosystem SCA tools like GeekWala, Snyk, Grype, and Trivy scan multiple ecosystems from a single interface and add features like EPSS scoring, CISA KEV checking, and historical tracking.
Is Dependabot a dependency scanner?
Dependabot is GitHub's automated dependency update and security alerting tool. It monitors your repositories for vulnerable dependencies and opens pull requests to update them. It functions as a scanner in the sense that it identifies vulnerable packages, but it differs from dedicated SCA tools in several ways: it only works within GitHub, it doesn't provide EPSS enrichment or CISA KEV status, and its alerts are based on GitHub's advisory database alone. Dependabot is effective at automating updates for simple version bumps but can generate a high volume of PRs that overwhelm teams if not configured carefully. For a detailed comparison, see Dependabot Alternative.
What is the difference between SAST and SCA?
SAST (Static Application Security Testing) analyzes your source code for security vulnerabilities — things like SQL injection, cross-site scripting, and insecure API usage. It finds bugs you wrote. SCA (Software Composition Analysis) analyzes your third-party dependencies for known vulnerabilities — things like published CVEs in the packages you import. It finds bugs someone else wrote that ended up in your application. Both are important, but they answer different questions. SAST asks "is my code secure?" SCA asks "are my dependencies secure?" Most teams get higher initial ROI from SCA because third-party code typically makes up 70-90% of a modern application, and SCA findings are more actionable (update to a patched version) than SAST findings (rewrite the vulnerable code).
Ready to see what's in your dependency tree? Run a free scan — paste any manifest or lock file, get prioritized results with EPSS and CISA KEV enrichment in seconds. No signup required.


