Loading...
Skip to main content
Ecosystem Guide

Dependency Security Across 8 Ecosystems: The Complete Developer Guide

Most teams use 2-3 languages but scan dependencies one ecosystem at a time. This guide maps native audit tools for all 8 major ecosystems and shows what each one misses — plus how to unify scanning across your entire stack.

Sudhir P.
Last updated
17 min read

A backend team ships a Node.js API, a Python data pipeline, and a Go service for infrastructure work. Security asks for a vulnerability report. The team runs npm audit, pip-audit, and govulncheck separately — three different formats, three different severity scales, three dashboards. Nobody can tell the CISO which dependency represents the highest actual risk across the entire platform.

This is the multi-ecosystem problem in practice. Each language ecosystem has a native vulnerability scanner. Each one does its job reasonably well within its own domain. But none of them speak to each other, and none of them answer the question teams need answered: "Which of these 340 findings requires a patch before end of day?"

Key Takeaway

TL;DR: Every major package ecosystem ships a native audit tool. All of them surface CVEs and rank by CVSS severity. None of them include EPSS (exploitation probability) or CISA KEV (confirmed active exploitation) signals. This guide maps the native tool for each of the 8 major ecosystems, shows what each one misses, and explains how to unify scanning across your stack. For a deeper look at how CVSS-only ranking creates alert fatigue, see our vulnerability prioritization guide.

What We'll Cover


Why Ecosystem-Specific Scanning Has a Ceiling

Every native scanner in this guide works the same way at its core:

  1. Parse your manifest or lock file (package-lock.json, go.sum, Cargo.lock, etc.)
  2. Match installed versions against a vulnerability database (OSV, NVD, an ecosystem-specific advisory feed, or some combination)
  3. Return findings sorted by CVSS severity — Critical first, then High, Moderate, Low

This is useful. Running zero tools is worse than running one tool with limitations. But there's a hard ceiling on what CVSS-ranked output tells you.

CVSS measures theoretical severity — how bad a vulnerability could be if a specific attacker exploited it in a specific way against a specific configuration. It doesn't measure whether anyone is actually trying to exploit it. A CVSS 9.8 in a parsing library with no public exploit code and zero PoC activity should not receive the same response urgency as a CVSS 6.5 with an active Metasploit module and a CISA KEV entry.

Two signals close this gap:

EPSS (Exploit Prediction Scoring System): A machine-learning model maintained by FIRST.org that scores every CVE with a probability (0.0–1.0) of exploitation in the next 30 days. It's updated daily as exploit code, threat intelligence, and malware analysis data flows in. A CVE with EPSS 0.03 is unlikely to be exploited anytime soon. A CVE with EPSS 0.78 is actively being weaponized.

CISA KEV (Known Exploited Vulnerabilities): A CISA-curated catalog of vulnerabilities with confirmed active exploitation in the wild. KEV membership means threat actors are using this CVE in live attacks right now — not "could be used," not "has a PoC" — actively being used.

Every ecosystem section below covers the native tool's strengths and the specific gaps EPSS and KEV fill.


npm / Node.js

Native tool: npm audit

npm audit is embedded in the npm CLI and runs automatically on npm install. It queries the npm Security Advisory Database (backed by GitHub Advisory and NVD), matches your package-lock.json against known vulnerable versions, and returns severity-ranked results.

What it does well: Zero setup. Runs on every install without configuration. npm audit fix can automatically resolve many findings within semver constraints. Reports include the full transitive dependency chain, so you know exactly which direct dependency pulled in the vulnerable package.

What it misses:

LimitationImpact
CVSS-only rankingHigh and Critical findings pile up; teams can't distinguish urgent from noise
No EPSS scoresCan't identify which findings are being actively exploited
No CISA KEV integrationNo flag for vulnerabilities with confirmed live exploitation
npm ecosystem onlyDoesn't see your Python or Go dependencies
DevDependency blind spotFlags devDependencies alongside production ones; severity not adjusted for non-production risk

A team running a typical React application will see 30-80 npm audit findings. With EPSS filtering, the number requiring immediate action usually drops to 2-5. The rest are real vulnerabilities worth patching — but on a normal sprint schedule, not emergency response.

Deep dive: npm audit vs GeekWala: Why CVSS Scores Alone Are Misleading


Python / PyPI

Native tool: pip-audit

pip-audit was developed by Google and the Python Security Response Team. It checks installed packages against the OSV database and the Python Packaging Advisory Database (PYSEC advisories). It supports requirements.txt, pyproject.toml (via pip-compile), and virtual environment scanning.

What it does well: Maintained by Google with OSV integration. Supports --fix for automatic resolution. Works with multiple dependency formats. The PYSEC advisory feed captures Python-specific issues faster than NVD propagation.

What it misses:

LimitationImpact
No EPSS or KEVFindings sorted by severity; no exploitation signal
PyPI ecosystem onlyDoesn't see your npm or Go stack
Lock file gapsDoesn't natively parse Pipfile.lock or poetry.lock without conversion
Advisory coverageNot latency — we measured PyPI's NVD-to-advisory gap at a 0.00-day median (p90 0.16 days, n=738). The gap is that ~5.6% of PyPI vulnerability advisories carry no CVE alias at all
Transitive depthDeep dependency chains can obscure which package introduced a vulnerability

Python's multiple competing package formats (pip, poetry, pipenv, conda) and lack of a single authoritative lock file standard create real fragmentation — but not, as we assumed, a timing gap. We measured PyPI's NVD-to-advisory interval at a 0.00-day median (p90 0.16 days, n=738), and in 28.6% of cases the advisory landed first. The fragmentation costs you coverage, not speed: 5.6% of PyPI's genuine vulnerability advisories carry no CVE identifier at all.

Deep dive: Python Dependency Security: What pip-audit Misses


Java / Maven

Native tool: mvn dependency-check (via OWASP Dependency-Check Maven plugin)

Java's vulnerability scanning story is fragmented. Maven ships no built-in advisory scanner — you add the OWASP Dependency-Check plugin to your pom.xml. It queries NVD using CPE (Common Platform Enumeration) matching to identify vulnerable artifacts.

What it does well: Broad artifact coverage for the Maven ecosystem. Generates detailed HTML and XML reports suitable for audit trail requirements. Integrates with Maven and Gradle build lifecycle. Large community documentation and enterprise adoption.

What it misses:

LimitationImpact
CPE matching heuristicsHigh false positive rate, especially with shaded JARs and BOM imports
NVD-only advisory sourceMisses GitHub Advisory (GHSA) entries not yet propagated to NVD
No EPSS or KEVSame CVSS-only ranking problem
NVD API rate limitsWithout an NVD API key, initial database sync takes hours
Transitive shadingShaded JARs (uber-JARs) embed dependencies that scanners often miss

The false positive rate is the biggest practical problem for Java teams. CPE matching is imprecise when the same library appears under different artifact coordinates or when shading changes the internal package structure. Teams spend significant time manually triaging false positives — time that isn't available for genuine vulnerabilities.

Deep dive: Java Dependency Security: What Maven Dependency-Check Misses


Go Modules

Native tool: govulncheck

govulncheck is the official Go vulnerability scanner, built by the Go security team and maintained alongside the language itself. It uses the Go Vulnerability Database and performs call-graph analysis — it can determine whether your code actually calls vulnerable functions, not just whether the package is in your go.sum.

What it does well: Call-graph analysis is unique among native ecosystem tools. Instead of flagging every package with a known CVE, govulncheck checks whether the vulnerable code path is reachable from your application. This reduces false positives significantly. The Go Vulnerability Database is authoritative, well-curated, and maintained by the Go team. Works offline with a local database copy.

What it misses:

LimitationImpact
No EPSS or KEVReachability analysis reduces noise, but not exploitation signal
Conservative advisory databaseGo Vuln DB is smaller than NVD; some CVEs appear there first, others appear only in NVD
Call-graph requires sourceCan't scan from lock file alone — needs full source for reachability analysis
Go ecosystem onlyDoesn't cover your Python or Node.js services
Indirect dependency blindnessgo.sum can have 1,000+ entries; transitive vulnerabilities are easy to miss in monitoring

Go teams have the best native scanner in this list thanks to call-graph analysis. But "best native tool" still means no exploitation signals. A govulncheck finding at CVSS 7.5 could have EPSS 0.8 (patch immediately) or EPSS 0.02 (patch next quarter). Without that data, every finding gets the same triage priority.

Deep dive: Go Module Security: Beyond govulncheck for Production Dependencies


Rust / crates.io

Native tool: cargo audit

cargo audit scans your Cargo.lock against the RustSec Advisory Database, a community-maintained advisory feed specifically for the Rust ecosystem. The companion tool cargo-deny extends this with license compliance checking and duplicate dependency detection.

What it does well: RustSec is exceptionally well-curated — low false positive rate. Community-maintained with active participation from crate authors. Uniquely, cargo audit surfaces warnings for unmaintained crates, not just vulnerable ones. cargo-deny adds policy enforcement useful for enterprise teams. Fast execution, minimal dependencies.

What it misses:

LimitationImpact
No EPSS or KEVAdvisory severity without exploitation signal
Smaller advisory databaseRustSec's conservative curation means some NVD CVEs aren't covered
-sys crate blindnessC binding crates (FFI wrappers) can carry C library vulnerabilities that RustSec doesn't track
crates.io onlyDoesn't see adjacent Node or Python dependencies
Unmaintained warnings are noise-heavyUseful signal, but teams can't easily distinguish "unmaintained but stable" from "unmaintained and dangerous"

Rust's memory safety guarantees eliminate entire vulnerability classes (buffer overflows, use-after-free, format string bugs) that dominate advisories in C and C++ ecosystems. But Rust applications still depend on network libraries, parsing code, cryptography implementations, and database drivers — all of which carry conventional security vulnerabilities. cargo audit catches these; it just can't tell you which ones are being actively weaponized.

Deep dive: Rust Dependency Security: What cargo audit Misses in 2026


Ruby / RubyGems

Native tool: bundler-audit

bundler-audit scans your Gemfile.lock against the Ruby Advisory Database, a community-maintained collection of vulnerabilities affecting RubyGems packages. It's a standalone gem, not a built-in bundle command, and requires explicit installation.

What it does well: Focuses specifically on the Ruby ecosystem. The Ruby Advisory Database includes advisories from multiple sources (NVD, CVE, vendor advisories). Understands Bundler's dependency resolution. Lightweight and fast.

What it misses:

LimitationImpact
No EPSS or KEVCVSS-based severity only
Not built into BundlerRequires separate installation; often not in base CI images
Advisory database sizeSmaller than NVD; some CVEs take longer to appear in Ruby Advisory Database
No transitive path tracingFlags the vulnerable gem but doesn't show the full dependency chain
RubyGems onlyDoesn't surface vulnerabilities in JavaScript assets served by Rails apps

Rails applications commonly bundle both a Gemfile.lock (Ruby dependencies) and a package-lock.json or yarn.lock (JavaScript dependencies via Webpack or Propshaft). bundler-audit sees one half of that picture. A cross-ecosystem scan catches both.

Deep dive: Ruby Dependency Security: What bundler-audit Misses


.NET / NuGet

Native tool: dotnet list package --vulnerable

.NET ships a built-in vulnerability check via the dotnet CLI. Two commands cover this: the older dotnet list package --vulnerable and the newer dotnet audit (available in .NET 8+). Both query Microsoft's NuGet advisory database.

What it does well: Native to the .NET toolchain — no additional installation. Well-maintained NuGet advisory database, especially for Microsoft-published packages. Central Package Management support simplifies vulnerability reporting across large solution files with many projects.

What it misses:

LimitationImpact
No EPSS or KEVSeverity labels without exploitation context
Advisory coverage gapsThird-party NuGet packages outside Microsoft's ecosystem are less consistently covered — 46.8% of NuGet OSV advisories carry no CVE identifier
NuGet ecosystem onlyDoesn't see JavaScript bundles or Python scripts in .NET applications
No automated fixReports vulnerable packages but doesn't suggest upgrade paths or apply patches
packages.config vs PackageReferenceBehavior varies depending on project format; older projects using packages.config may get incomplete results

.NET applications frequently embed JavaScript for frontend (via npm workspaces, Webpack, or client-side Blazor dependencies) and may invoke Python scripts in data-heavy pipelines. The NuGet scanner misses these entirely.

Deep dive: NuGet Vulnerability Scanning: What dotnet audit Misses


PHP / Packagist

Native tool: composer audit

Composer 2.4 shipped a built-in composer audit command that checks your composer.lock against the PHP Security Advisories Database. Earlier Composer versions used the standalone local-php-security-checker tool. Both query the same advisory feed.

What it does well: Built into Composer — no extra installation from Composer 2.4+. The PHP Security Advisories Database is actively maintained by the PHP community. Covers the most widely used Packagist packages including Symfony, Laravel, Drupal, and WordPress components. Fast execution against a well-structured advisory format.

What it misses:

LimitationImpact
No EPSS or KEVAdvisory severity without exploitation signal
PHP Security Advisories onlyDoesn't cross-reference NVD or GitHub Advisory; some CVEs appear only in those databases
Packagist ecosystem onlyDoesn't see npm packages bundled with PHP applications
No transitive path detailLists vulnerable packages without showing the full dependency chain
No scheduled scanningCI-only; no continuous monitoring between deploys

PHP applications — especially WordPress, Drupal, and Laravel — often pair composer.lock with package-lock.json for JavaScript assets. Scanning only one side leaves frontend dependencies unchecked. Additionally, PHP has historically been a high-target ecosystem for web exploits, making the absence of KEV data particularly costly when an advisory hits a widely deployed package like Symfony HttpKernel or Laravel's illuminate/http.

Deep dive: PHP Dependency Security: What composer audit Misses


Multi-Ecosystem Projects: Scanning a Polyglot Stack

Here's what a typical polyglot production application looks like:

SaaS Application
├── frontend/          package-lock.json     (npm)      ~800 packages
├── api/               requirements.txt      (PyPI)     ~120 packages
├── infra-service/     go.sum                (Go)        ~60 modules
├── analytics/         pom.xml               (Maven)    ~200 artifacts
└── cms/               composer.lock         (Packagist) ~90 packages

That's 1,270 dependencies across 5 ecosystems, checked by 5 separate scanners, each producing output in a different format with different severity scales. When a new CVE drops, you're opening five tabs, running five commands, and mentally reconciling five lists.

The operational cost of this compounds at every step:

Triage cost: You can't compare a "High" from npm audit against a "High" from mvn dependency-check — they're calculated from different advisory sources with different CPE matching and CVSS interpretation policies.

Coverage gaps: Each native tool sees only its ecosystem. A vulnerability in lodash (npm) doesn't appear in pip-audit. A compromised Python package isn't flagged by govulncheck.

Monitoring blind spots: Most native tools run in CI on each commit. Between deploys, EPSS scores can change significantly as new exploit code appears or threat actors shift attention. A package that was EPSS 0.05 on Monday can reach EPSS 0.72 by Friday without any code change on your end.

Unified scanning across ecosystems: This is where cross-ecosystem tools like GeekWala close the gap. We scan all 8 ecosystems — npm, PyPI, Maven, Go modules, crates.io, RubyGems, NuGet, and Packagist — from a single dashboard. Upload any manifest or lock file, or connect your GitHub repository to scan the entire dependency tree across all languages at once. Every finding is enriched with EPSS exploitation probability and CISA KEV status, sorted by actual risk rather than theoretical severity.

The practical workflow for polyglot teams:

Local Development           CI/CD Pipeline                 Production Monitoring
─────────────────           ──────────────                 ────────────────────
Native tools                Native tools +                 GeekWala scheduled scans
(fast, zero setup)          GeekWala API scan              (daily / weekly)
                            (gate deploys on                catches EPSS score changes
                             EPSS > 0.8 or KEV)             between deploys
       │                          │                               │
       └──────────────────────────┴───────────────────────────────┘
                                  │
                        GeekWala Dashboard
                     (unified view across all ecosystems,
                      team alerts on EPSS spikes)

The native tools stay in the pipeline for fast, ecosystem-specific checks during development. GeekWala sits above them as a cross-ecosystem prioritization layer — giving your team one ranked list instead of five separate ones.

For a full comparison of how individual ecosystem scanners stack up against each other and GeekWala, see 7 Dependency Vulnerability Scanners Compared.


Ecosystem Comparison at a Glance

EcosystemNative ToolAdvisory SourceEPSSKEVAuto-FixCall-Graph
npm / Node.jsnpm auditnpm + GHSA + NVDNoNoYes (npm audit fix)No
Python / PyPIpip-auditOSV + PyPANoNoYes (--fix)No
Java / MavenOWASP Dependency-CheckNVDNoNoNoNo
Go modulesgovulncheckGo Vuln DBNoNoNoYes
Rust / crates.iocargo auditRustSecNoNoNoNo
Ruby / RubyGemsbundler-auditRuby Advisory DBNoNoNoNo
.NET / NuGetdotnet auditNuGet + MSRCNoNoNoNo
PHP / Packagistcomposer auditPHP Security AdvisoriesNoNoNoNo
All 8 ecosystemsGeekWalaOSV + NVD + GHSA + KEVYesYesNo (guidance)No

The pattern is clear: every native tool provides CVSS-based ranking from its own advisory source. None include exploitation signals. govulncheck is the sole exception to one column — its call-graph analysis filters false positives — but it still doesn't surface EPSS or KEV data.


Frequently Asked Questions

Do I need to replace my ecosystem's native scanner?

No. Keep npm audit, pip-audit, govulncheck, and the rest in your CI pipeline. They're fast, free, and catch issues at development time without requiring any account or API setup. They should be your first line of defense. The gap is prioritization: native tools give you a ranked list based on CVSS severity, but can't tell you which findings are being actively exploited right now. A cross-ecosystem tool with EPSS and KEV data adds that layer on top of — not instead of — your native scanners.

Why don't the native tools include EPSS?

EPSS is maintained by FIRST.org and updated daily — it scores every published CVE (355,000+ as of mid-2026, and growing as new CVE IDs are assigned). Integrating it requires fetching, caching, and correlating EPSS data with each advisory database. Most native tools are designed to be fast, dependency-light, and capable of running offline. Adding EPSS would require daily network calls and a caching layer that conflicts with these design goals. It's not that ecosystem tool maintainers think EPSS is unimportant — it's an architectural tradeoff.

Which ecosystem has the best native vulnerability scanning?

Go's govulncheck is the standout. Its call-graph analysis distinguishes between "this package is installed and has a CVE" versus "your application actually calls the vulnerable function." This meaningfully reduces false positives. RustSec (the advisory database behind cargo audit) is also exceptionally well-curated with low false positive rates. At the other end, Java's CPE-matching approach in OWASP Dependency-Check produces more noise and requires more manual triage, particularly with shaded JARs.

How should I scan a monorepo with multiple languages?

Scan each manifest or lock file separately. Most lock files are small (a few hundred KB even for large projects), so the overhead is minimal. In CI, run native tools in parallel: npm audit, pip-audit, govulncheck, etc. Run a GeekWala scan on all lock files to get a unified prioritized view. For monorepos with dozens of services, the GeekWala API lets you automate this — submit lock files programmatically and gate deploys on KEV status or EPSS threshold.

What's the best starting point for a team that's currently running no dependency scanning?

Start with the native tool for your primary language — it takes 5 minutes to add to CI and requires no account. Then add composer audit or pip-audit or cargo audit for any secondary languages. Once you're running native scans consistently and have a process for reviewing findings, add a cross-ecosystem scan to get EPSS and KEV prioritization. Don't try to do everything at once — running one ecosystem's native tool reliably is more valuable than running eight tools sporadically.

Does scanning dependency files expose our codebase or proprietary information?

Manifest and lock files (package-lock.json, go.sum, Cargo.lock, etc.) contain package names and version numbers — no source code. They're structured lists of public package identifiers. Submitting them to a scanner doesn't expose business logic, database schemas, or API keys. The only information disclosed is which open-source packages you use — the same information that would be visible in your node_modules directory or any compiled artifact.

How often should I run multi-ecosystem scans?

Run native ecosystem scans on every CI build. Run cross-ecosystem scans (with EPSS and KEV enrichment) at least weekly on your production lock files. EPSS scores change daily as exploit code appears, threat intelligence feeds update, and malware analysis data arrives. A package that was EPSS 0.04 last week can spike to 0.85 this week without any changes to your codebase. Scheduled scans catch this drift between deploys.


Eight ecosystems, one dashboard.

Scan your dependencies across npm, PyPI, Maven, Go, Rust, Ruby, NuGet, and PHP → — upload any lock file and see which findings are being actively exploited, ranked by EPSS and CISA KEV. No account needed.