Safeguard
Software Supply Chain Security

Package Firewall: Blocking Malicious Dependencies at Inst...

Malicious npm and PyPI packages are published daily. See why a package firewall that blocks at install time stops attacks that post-hoc scanners catch too late.

Daniel Chen
Security Engineer
8 min read

On September 8, 2025, an attacker phished a maintainer of chalk, debug, and 16 other npm packages with a combined 2.6 billion weekly downloads, then pushed versions laced with a crypto-clipper. Nine days later, a self-propagating worm dubbed "Shai-Hulud" compromised over 500 npm packages, stole developer credentials, and republished itself through infected maintainers' own accounts. Neither attack required a known CVE. Neither showed up in a vulnerability scan. Both were live on the registry, one npm install away from production, for hours before anyone noticed.

This is the gap a package firewall is built to close. Instead of scanning code after it lands in a repository, it sits in the install path — npm, pip, Maven, Go modules — and decides, in real time, whether a package or version is safe to pull down at all. Below, we walk through how that model works, how it differs from the reachability-based approach popularized by Endor Labs, and where each falls short on its own.

What is a package firewall, and how is it different from a scanner?

A package firewall is a control point that intercepts install requests — npm install, pip install, go get — and blocks the request before the package reaches disk, versus a scanner that reads code that is already there. Traditional SCA tools (Snyk, early Dependabot, OSS Index) generate a bill of materials after node_modules or site-packages already exists, then match it against CVE databases. That workflow is built for known vulnerabilities in legitimate packages, not for packages that are malicious by design and have no CVE at all — typosquats, dependency-confusion uploads, or compromised maintainer accounts pushing a new version of a package everyone already trusts.

A firewall proxies the registry itself. Every request from a developer laptop or CI runner routes through a policy engine that checks the package name, version, publish age, maintainer reputation, and static/behavioral signals (does the install script phone home, does it read ~/.aws/credentials, does it obfuscate a payload) before the artifact is ever fetched. If it fails policy, the install fails — not a Slack alert three days later after the package has run its postinstall script on forty engineers' machines.

How often do malicious packages actually reach npm and PyPI in practice?

Malicious packages are now published to open source registries at a rate of hundreds per day, not as rare exceptions. Sonatype's 2024 State of the Software Supply Chain report counted over 512,000 malicious open source packages published in 2024 alone, pushing the cumulative total the firm has tracked since 2019 past 700,000. Socket's research team has separately reported detecting and reporting thousands of malicious npm and PyPI packages per year, many designed to survive only long enough to exfiltrate environment variables or SSH keys during postinstall.

The pattern is old but the volume is new. The 2018 event-stream incident — where a maintainer handed off a popular package to an attacker who added a dependency, flatmap-stream, that targeted the Copay Bitcoin wallet — took months to discover. The October 2021 ua-parser-js compromise, affecting a library with roughly 7 million weekly downloads, installed a cryptominer and a Windows password stealer within versions pushed directly to the registry. What has changed since is speed and automation: registries now see attack campaigns that publish, propagate, and get pulled within a single business day, which is faster than most quarterly or even weekly SCA scan cycles can react.

What did the September 2025 npm attacks prove about install-time risk?

They proved that trust in a package's past reputation is not a safety guarantee for its next version. The chalk/debug compromise hit packages with no history of prior incidents and download counts in the billions — exactly the dependencies most organizations allowlist by default because "everyone uses them." The Shai-Hulud worm went further: it used stolen npm tokens to publish trojanized versions of packages from the compromised maintainers' own accounts, then harvested secrets from CI environments (GitHub Actions, GitLab CI) using tools like TruffleHog, and attempted to propagate to any other package those credentials could publish to.

In both cases, the malicious code executed the moment the package was installed, via postinstall lifecycle scripts, well before any code review, SAST scan, or SBOM diff would have flagged it. Teams running nightly or even hourly dependency scans still had a multi-hour to multi-day exposure window. A control that evaluates the package before the install completes is the only model that closes that window to effectively zero, because there is nothing to detect after the fact — the bad artifact never lands.

How does Endor Labs approach dependency blocking today?

Endor Labs's core differentiator is reachability analysis: rather than flagging every CVE in every dependency, it uses call-graph analysis to determine whether vulnerable or risky code is actually reachable from an application's own code paths, which the company has marketed as reducing alert volume by roughly 90%+ in customer environments. That is a genuinely useful answer to alert fatigue on known-CVE findings, and Endor Labs has extended the same risk-scoring engine to flag malicious and low-reputation packages (abandoned maintainers, suspicious install scripts, typosquat naming) as part of its "OSS risk" scoring.

Where this differs from a firewall model is timing and enforcement point. Endor's scoring is primarily applied to code that has already been resolved into a manifest or lockfile — it tells you a dependency is risky, and increasingly can gate a CI pipeline or pull request on that finding, but it is evaluating a dependency graph, not intercepting the registry fetch on a developer's laptop before npm install completes locally. For CI-gated workflows, that's a narrow gap. For local development — where a large share of maintainer-account and worm-style attacks actually execute, on individual engineers running npm install outside of any pipeline — reachability scoring alone doesn't stop the fetch from happening in the first place.

Can install-time blocking actually stop an attack before any code runs?

Yes, when the firewall sits ahead of the package manager rather than behind it, but only if it also controls lifecycle scripts, not just the initial download. Blocking the install request itself is table stakes; several 2024-2025 incidents (including xz-utils, CVE-2024-3094, discovered by Andres Freund on March 29, 2024) showed that malicious behavior can also be smuggled into build-time artifacts and test fixtures rather than the top-level package alone, so a firewall needs visibility into transitive dependencies and build scripts, not just the direct install target.

The practical mechanism looks like this: a private registry proxy (npm registry, PyPI index, or a Maven/Go module proxy) evaluates every resolved package — direct and transitive — against a continuously updated threat feed and a policy set (block on unpublished-then-republished versions, block on new maintainer + no 2FA, block on postinstall scripts making outbound network calls, quarantine anything published in the last 24-72 hours until it clears a hold window). Because the check happens at resolution time, a compromised version published five minutes ago that hasn't yet been reviewed by any human can still be held in quarantine automatically, which is exactly the multi-hour gap that let Shai-Hulud spread in September 2025.

Does blocking at install time create friction for developers?

It does unless the firewall is tuned to fail closed only on high-confidence signals and fail open (with an audit trail) on ambiguous ones, which is the design tradeoff that determines whether teams actually keep it turned on. A firewall that blocks every new package version pending manual review will get disabled by engineers within a week. The workable pattern, used by mature registry-proxy deployments, is tiered: hard-block on deterministic indicators (known-malicious hash match, typosquat of a top-1000 package, publish from a newly created account with no prior packages), soft-quarantine with a time delay on medium-confidence signals (brand-new package, first release from an existing maintainer after a long gap), and pass-through with logging for everything else. That keeps the median npm install fast while still catching the specific attack pattern — new or newly-hijacked publish, executed immediately — that scanners consistently miss.

How Safeguard Helps

Safeguard's package firewall sits directly in the install path for npm, PyPI, and Maven, proxying every dependency resolution — direct and transitive — through a policy engine before the artifact reaches a developer machine or CI runner. Packages are checked against a continuously updated malicious-package feed, maintainer and publish-age heuristics, and behavioral analysis of install-time scripts, with high-confidence matches blocked outright and ambiguous new releases held in a short quarantine window rather than passed through silently.

Because policy is enforced identically on a laptop and in CI, Safeguard closes the exact gap exposed by the September 2025 npm incidents: an engineer running npm install locally gets the same real-time protection as a pipeline gated on a lockfile scan, without waiting for a nightly SBOM diff to notice a compromised version after it has already executed. Policies are configurable per team — hard-block deterministic threats, quarantine time-boxed on medium-confidence signals, log-and-allow on the long tail — so the control point stays fast enough for daily development while still stopping the specific pattern that scanner-only tooling structurally can't: an attack that only exists for a few hours between publish and detection. Combined with SBOM generation and policy-as-code so blocking rules are versioned and auditable, Safeguard gives security teams a control they can point to for SOC 2 and supply-chain compliance evidence, not just a dashboard of findings to triage after the fact.

Never miss an update

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