Safeguard
Open Source Security

Software Dependencies: How to Manage Them at Scale

Most apps run 10-20x more dependencies than engineers chose. Here's how reachability analysis and automation manage that risk at scale.

James
Principal Security Architect
6 min read

The average application pulls in hundreds of open source packages it never directly chose. A React app scaffolded in 2024 with Create React App or Vite ships with 1,000+ transitive dependencies before a developer writes a single line of business logic; a typical Java service built on Spring Boot resolves 150–400 JARs through Maven alone. Each one is a potential entry point. The xz-utils backdoor discovered in March 2024 (CVE-2024-3094) was buried three layers deep in a compression library used by OpenSSH, and most teams running affected Debian testing or Fedora 40/41 builds had no idea it was even in their dependency tree until a Microsoft engineer noticed a 500-millisecond SSH login delay. Managing dependencies at scale isn't a quarterly CVE scan — it's knowing exactly what's running in production, which of those packages your code actually calls, and how fast you can ship a fix when the next log4j-scale incident hits. Here's how that works in practice.

How many dependencies does a typical production application actually have?

Most production applications carry 10–20x more dependencies than the ones engineers deliberately installed. Sonatype's 2023 State of the Software Supply Chain report found that 90% of the vulnerable components pulled into a build are transitive — dependencies of dependencies that no developer explicitly selected or reviewed. A single npm install express pulls in over 60 packages; a mid-sized microservices fleet with 50 services can easily aggregate 15,000–30,000 unique package versions across its manifests. This is why grep-based audits and manual spreadsheet tracking break down almost immediately past a handful of repositories — the surface area scales faster than headcount ever will.

Why do transitive dependencies create more risk than direct ones?

Transitive dependencies create more risk because nobody on the team chose them, reviewed their maintainers, or knows when they change. The event-stream incident in November 2018 is the canonical example: a popular npm package with 2 million weekly downloads was handed off to an unknown contributor who added a malicious dependency (flatmap-stream) designed to steal cryptocurrency wallet credentials from a downstream project, Copay. It sat live for over two months before anyone flagged it. More recently, the node-ipc "protestware" incident in March 2022 showed a maintainer intentionally shipping destructive code — deleting files on machines with Russian or Belarusian IP addresses — through an indirect dependency of the widely used vue-cli tooling. Neither incident showed up in a direct package.json diff; both required visibility several layers deep.

How often do serious vulnerabilities show up in open source packages?

Serious vulnerabilities in open source packages are now a weekly occurrence, not a rare event. The GitHub Advisory Database logged over 20,000 new advisories in 2023 alone, and the NVD's own processing backlog — which the agency publicly acknowledged in February 2024 — has meant that thousands of CVEs sat unanalyzed for weeks, leaving severity scoring to catch up after exploitation had already started. Log4Shell (CVE-2021-44228), disclosed December 9, 2021, remains the reference point: a single logging library used in an estimated 3 billion devices had a trivially exploitable remote code execution flaw, and Check Point reported over 800,000 exploitation attempts within 72 hours of disclosure. Three years later, Sonatype's research still found log4j downloads of vulnerable versions continuing well into 2023, because dependency trees are large and patch propagation is slow without automation.

What's the difference between having an SBOM and actually managing dependency risk?

An SBOM tells you what's in your software; it does not tell you what's dangerous. Since Executive Order 14028 (May 2021) and the NTIA's minimum elements guidance pushed SBOM generation into procurement requirements across the U.S. federal supply chain, most vendors can now produce a CycloneDX or SPDX document listing every component and version. But an SBOM with 4,000 entries and no exploitability context just moves the triage problem downstream — security teams still have to figure out which of those 4,000 packages are actually reachable from running code, internet-facing, and tied to a live exploit. CISA's own 2023 guidance on SBOM consumption explicitly flags this gap, noting that inventory without vulnerability and reachability correlation "provides limited security value" on its own.

How should teams prioritize which dependency vulnerabilities to fix first?

Teams should prioritize by reachability, not by CVSS score alone, because most flagged vulnerabilities are never actually exploitable in a given application. Research from application security vendors analyzing real codebases has repeatedly found that 80–90% of vulnerabilities reported in a dependency scan live in code paths the application never calls — a vulnerable XML parser function that a given service imports but never invokes, for example. A CVSS 9.8 in a function nobody calls is lower real-world risk than a CVSS 7.5 in a function that processes every incoming HTTP request. Without call-graph-level reachability analysis, security teams end up triaging thousands of "critical" tickets a quarter when only a fraction represent genuine exposure — and engineering trust in the scanner erodes fast once a few false-priority fire drills prove unnecessary.

How can teams patch dependencies fast without breaking production?

Teams patch fast without breaking production by automating the pull request, not just the alert. Manually bumping a transitive dependency three levels deep in a lockfile, then re-running a full test suite, is exactly the kind of task that stalls for weeks on a backlog — which is precisely the window attackers exploit; the average time-to-patch for a critical CVE across enterprise environments has historically run 60–150 days depending on the sector, according to multiple Ponemon and Edgescan benchmarking studies over the past several years. Auto-generated fix PRs that pin to the minimum safe version, run against existing CI, and surface a clean diff cut that cycle from weeks to hours, because the engineering decision shrinks from "figure out what changed and if it's safe" to "review and merge."

How Safeguard Helps

Safeguard closes the gap between knowing your dependencies and actually managing the risk they carry. Our reachability analysis traces vulnerable functions through your real call graphs, so teams triage the fraction of alerts tied to exploitable code paths instead of every CVE a scanner surfaces. Griffin AI, our security reasoning engine, correlates that reachability data with exploit intelligence and your deployment context to rank fixes by actual exposure, not raw severity score. Safeguard generates and ingests SBOMs in CycloneDX and SPDX formats to keep a live, queryable inventory across every repo and container image, and when a fix is confirmed safe, Safeguard opens an auto-fix pull request with the minimum version bump and passing CI checks already attached — turning a multi-week patch cycle into a same-day merge.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.