Your Dependencies Are Your Attack Surface. Most Teams Don't Treat Them That Way.
The Log4Shell vulnerability affected hundreds of thousands of applications that didn't know they were running Log4j. Dependency management is a security practice, not a chore.
In December 2021, the Log4Shell vulnerability was disclosed in Apache Log4j, a Java logging library. Within 72 hours, security researchers had identified over 100 million vulnerable instances across the internet. The majority of the affected teams didn't know they were running Log4j — it was a transitive dependency, pulled in by a library they were aware of, which had its own transitive dependency chain leading back to Log4j.
Log4Shell was extreme in its scope but not unusual in its mechanism: a vulnerability in a widely-used library, propagated through transitive dependency chains, affecting systems whose developers had no direct awareness of the vulnerable component. The attack surface created by your dependencies is real, large, and largely invisible to developers who aren't actively managing it.
Direct vs. Transitive Dependencies
Most developers have reasonable awareness of their direct dependencies — the packages they explicitly install and import. Almost no developers have systematic awareness of their transitive dependencies — the packages their dependencies depend on, and the packages those depend on in turn. A typical Node.js project with 30 direct dependencies might have 500-800 transitive dependencies. This entire dependency tree is your attack surface.
Tools like npm audit, pip-audit, and Snyk scan the full transitive dependency tree for known vulnerabilities. Running these tools in CI — not just locally, not just occasionally — ensures that newly-disclosed vulnerabilities in your dependency tree are detected before they become production risks.
The Dependency Addition Review
Every new dependency added to a production codebase should go through a deliberate review that asks: Is this dependency necessary, or could the functionality be implemented more simply inline? Is the package actively maintained? What is the package's download count and community health? What are its transitive dependencies, and do any of them have known issues? Does the package have a history of security vulnerabilities?
This review takes ten minutes and catches two categories of risk: packages that are abandoned and won't receive security updates, and packages that pull in problematic transitive dependencies. The code review of a PR that adds a new dependency should include this review explicitly, documented in the PR description.
Dependency Pinning vs. Range Specifications
The philosophical question of whether to pin exact dependency versions or specify ranges is a genuine tradeoff. Pinned versions give you reproducible builds and protection against unexpected breaking changes in patch updates — but require active work to update. Range specifications give you automatic security patches — but create the risk of automatically pulling in a breaking change or, in the case of supply chain attacks, a maliciously-modified version.
The current security environment tilts the balance toward pinning for production dependencies, with automated tooling (Dependabot, Renovate) to manage the update workflow. Automated dependency updates give you the security benefit of current versions without the risk of unreviewed automatic updates — the update creates a PR that can be reviewed and tested before merging.
What Code Review Misses and Automation Catches
Vulnerability scanning, license compliance checking, and transitive dependency analysis are all better handled by automated tools than by human reviewers. Human reviewers can evaluate whether a dependency is appropriate for the use case and whether it's well-maintained — but they can't efficiently identify that a specific version of a transitive dependency has a CVE published this week. Build the automation. Train reviewers to look for what the automation can't check. The combination covers the dependency security surface more completely than either approach alone.
Try CodeMouse on your next PR
Free AI code review on every pull request. Bring your own API key — no subscription needed.
Install on GitHub — Free