SoftLinkers All articles
Engineering Best Practices

What's Actually Hiding in Your node_modules? A Practical Supply Chain Audit Guide

SoftLinkers

Let's be honest: most of us treat npm install like a vending machine. You put in a package name, you get working code out, and you move on. Nobody reads the label. Nobody checks the expiration date. And that's exactly how teams end up with a dependency graph that looks like a plate of spaghetti — tangled, fragile, and one abandoned maintainer away from a serious problem.

Open source is one of the greatest collaborative achievements in software history. But it comes with a cost that rarely shows up on a sprint board: supply chain risk. And right now, that risk is higher than it's ever been.

According to the 2023 State of the Software Supply Chain report from Sonatype, open source component consumption has grown by over 33% year-over-year, while malicious packages have increased at an even faster clip. The SolarWinds breach, the Log4Shell vulnerability, the colors.js incident — these weren't fringe events. They were warnings.

So how do you actually get a handle on what you're carrying? Let's walk through it.

Step One: Map What You Actually Have

Before you can evaluate risk, you need visibility. Most teams are surprised by what a full dependency tree looks like when they flatten it out.

Start by generating a Software Bill of Materials (SBOM) for your project. Tools like Syft, CycloneDX, and SPDX can produce machine-readable manifests of every package in your build — direct and transitive. If you're on a Node.js stack, npm ls --all gives you a quick tree view. For Python, pip-audit and pipdeptree are solid starting points.

The goal here isn't to panic — it's to see clearly. Once you have a full list, you can start asking the right questions about each component.

Step Two: Evaluate Health, Not Just Vulnerabilities

Here's where a lot of teams stop short. They run npm audit or snyk test, patch the CVEs that pop up, and call it a day. That's not a supply chain strategy — that's reactive triage.

A real audit looks at package health, which includes:

Maintenance activity. When was the last commit? Is there an active maintainer? A package that hasn't been touched in two years isn't necessarily broken, but it's also not going to get patched when the next zero-day drops. Tools like OSS Insight and Libraries.io surface this data quickly.

Dependency breadth. How many packages does this one pull in? A utility that drags in 47 transitive dependencies is a liability multiplier. Prefer packages with minimal footprints where you have a choice.

Community signals. GitHub stars are vanity metrics, but issue response time, PR merge rate, and the presence of a SECURITY.md file tell you a lot about how a project is run. A well-governed project is a safer dependency.

License compatibility. This one bites teams late. GPL-licensed code in a commercial product is a legal headache. Tools like FOSSA and License Finder can automate compliance checks across your entire graph.

Step Three: Prioritize by Blast Radius

Not all dependencies carry equal risk. A package that touches your authentication layer is not the same as a dev-only linting utility. Segment your audit findings by potential blast radius.

A simple scoring matrix works well here. For each dependency, rate it on:

Packages that score high on criticality and low on health are your immediate action items. Everything else can go into a backlog for gradual remediation.

Step Four: Build a Lightweight Governance Process

A one-time audit is better than nothing, but it decays fast. The real win is making supply chain awareness part of how your team operates day to day.

A few practices that don't require a lot of overhead:

Pin your versions. Floating version ranges (^1.2.0) let upstream changes slip into your build without your knowledge. Lock files (package-lock.json, Pipfile.lock) aren't optional — they're a baseline control.

Automate dependency updates with review gates. Tools like Dependabot and Renovate can open PRs for dependency updates automatically. Pair this with required CI checks and you've got a workflow that keeps you current without relying on anyone to remember.

Add a pre-merge check for new packages. Before a new dependency gets merged, someone should answer: Is this package actively maintained? Does it have known vulnerabilities? Is there a lighter-weight alternative? A simple checklist in your PR template is enough to build the habit.

Run periodic full audits. Quarterly is a reasonable cadence for most teams. Tie it to a sprint planning cycle so it actually happens.

The Tools Worth Knowing About

You don't have to build this process from scratch. The open source community (somewhat ironically) has produced some excellent tools for this exact problem:

None of these are magic bullets, but layering two or three of them into your pipeline gets you meaningful coverage without a massive investment.

The Bigger Picture

Software development in 2024 is fundamentally collaborative. You're not just writing code — you're linking together the work of thousands of other developers, most of whom you'll never meet. That's the beauty of open source, and it's also the responsibility that comes with it.

Building a supply chain audit practice isn't about distrust. It's about being a good steward of the code your team ships and the users who depend on it. The teams that treat dependency management as a first-class engineering concern are the ones that don't end up in a post-mortem meeting explaining how a three-line utility package took down their production environment.

Start with visibility. Build toward governance. And remember — the best time to audit your supply chain was before you needed to. The second best time is right now.

All Articles

Related Articles

Your Dependencies Are a Liability: Here's How to Stop Letting Them Burn You

Why Fast-Moving Engineering Teams Are Ditching Synchronous Workflows for Event-Driven Design

Why Fast-Moving Engineering Teams Are Ditching Synchronous Workflows for Event-Driven Design

The Developer Who Connects the Dots Will Always Outpace the One Who Just Writes the Code

The Developer Who Connects the Dots Will Always Outpace the One Who Just Writes the Code