The code you didn't write carries risk, just not where you may expect. While open source speeds up development, and hands you the security posture of every package you pull in, plus every package those packages pull in, the danger lurks in the parts you can't see.
Direct dependencies are the ones you chose and can review. The transitive tree below them, the dependencies of your dependencies, is much larger and mostly hidden. Most exposure hides there. According to research by Endor Labs, aproximately 95% of vulnerabilities live in these transitive dependencies.Log4Shell showed the cost: a single logging library buried deep in countless builds detonated across the industry, and most teams discovered their exposure only after the disclosure.
The goal is not zero vulnerabilities. The goal is zero exploitable vulnerabilities in production. These steps get you there.
Inventory what you depend on
You can't secure what you can't see. Start with a complete inventory. List open source components, direct and transitive dependencies, versions, licenses, and known vulnerabilities. This forms your software bill of materials (SBOM).
Generate it in CycloneDX or SPDX, and automate generation in CI/CD so it stays current. Manual tracking drifts out of date and misses dependencies the moment a package updates. The inventory only gains value when it reaches the transitive layer. That is where hidden risk lives.
Prioritize with reachability, not just CVE counts
A scan of a real codebase returns thousands of CVEs. Most do not matter. Your code never calls the vulnerable function. Counting CVEs measures noise, not risk.
Function-level reachability analysis fixes the signal. For each finding, it answers a concrete question: does your application call the vulnerable code, and can it be exploited? Pair that with exploitability signals like EPSS, and the actionable list drops by up to 95%, from thousands of CVEs to the dozens worth fixing. Fix what is reachable first, and stop triaging what is not.
Catch malicious packages before install
Vulnerability scanning catches known CVEs. It does not catch a package that is malicious by design. Those are different problems, and they need a different control.
Attackers target the dependency tree directly through typosquatting, dependency confusion, and package poisoning. Continous, real-time malicious package detection catches these before they land on a developer's laptop orenter the build, which is the only timing that helps, since finding malware after deployment means it already ran. Reinforce it at the source: pull from verified repositories or a private registry, enable package signing and provenance verification, and block any package that fails a security check using a package firewall.
Keep dependencies healthy over time
Securing dependencies is continuous work, not a one-time audit. Five habits keep the tree healthy.
Scan on every commit and pull request, not on a quarterly schedule, and set quality gates that block critical findings in production branches while warning in development. Automate safe upgrades, but run upgrade impact analysis first, because a minor version bump can still break a build. When a full upgrade is not feasible, apply the security patch on its own.
Watch for abandoned packages, since a deprecated-but-popular library like request keeps shipping in projects long after its maintainers stopped patching it. Enforce governance as code, so policies like "no GPL in production," "no critical CVEs," and "nothing unmaintained past two years" run at build time rather than depending on a reviewer to remember them.
This is one spoke of a larger discipline. For the full program, see software supply chain security.
FAQ
How do you secure open source dependencies? Start with a complete SBOM that covers direct and transitive dependencies, scan on every commit in CI/CD, prioritize findings with reachability analysis so you fix exploitable risk first, catch malicious packages before they install with malware detection, and keep the tree healthy with automated safe upgrades and policy-as-code governance.
What is the difference between direct and transitive dependencies? Direct dependencies are the packages you import and declare in your manifest. Transitive dependencies are the packages those dependencies pull in, often several layers deep. The transitive tree is far larger and mostly invisible, which is why it holds most of the risk that teams miss.
Why does reachability matter for dependency security? Most vulnerabilities in your dependencies are not reachable, because your application never calls the affected code. Reachability analysis checks whether your application calls and can reach a vulnerable function, which cuts actionable alerts by up to 95% and lets you focus on findings an attacker can exploit.
How do you catch malicious open source packages? Use malicious package detection that relies on behavioral monitoring, not signatures alone, so it catches typosquatting, dependency confusion, and poisoned updates before they install. Pull from verified repositories or a private registry, enable signing and provenance verification, and block packages that fail security checks at the gate.
To reduce open source security risk, should you stop using it? No. Securing open source does not mean using less of it. With the right inventory, prioritization, and controls, dependencies accelerate development without trading away security. Start with visibility using an SBOM. Add continuous scanning in CI/CD. Then cut noise with reachability. This helps your team fix exploitable issues.
Open source dependencies are an asset, not a liability, when you can see them and prove what is exploitable. See how Endor Labs cuts dependency noise by 95% with reachability analysis and detects and blocks software supply chain attacks by booking a demo.
What's next?
When you're ready to take the next step in securing your software supply chain, here are 3 ways Endor Labs can help:
