You Trust 1000 Strangers Every Time You Deploy
.jpg)
.avif)
.avif)
npm, PyPI, GitHub Actions, container registries — every layer of your supply chain was built on trust that no longer holds. The only question is whether you catch it before production or after.
Every modern application is mostly other people's code. A typical project pulls in hundreds and thousands of transitive dependencies across npm, PyPI, Go modules, container base images, and GitHub Actions. Each one is a decision someone else made about what to run on your machine, in your CI, on your production servers.
For most of the history of package management, that was treated as a trust problem that would sort itself out. It didn't. Supply chain attacks have become the defining security story of 2025–2026; not because the technique is new, but because the scale, automation, and sophistication have fundamentally changed:
Self-replicating worms spread through npm. North Korean state actors compromise packages with 70 million weekly downloads. Attackers forge provenance attestations - the one trust signal the ecosystem was starting to build.
And all of it happens before your code even runs.
The security industry talks a lot about shifting left - catching issues as early as possible in the development lifecycle. Supply chain security is the most literal version of that idea: if malicious code enters your dependency tree, it's already too late to catch it at the application layer. You have to shift left past your own code, into the packages, registries, and CI pipelines that feed it.
This is how we think about it at Daylight, and what we've built.
The Attack Playbook
Before diving into the ecosystems, it's worth understanding the tactics. Supply chain attacks aren't one thing; they're a family of techniques, and they keep evolving:
- Dependency confusion — exploiting the way package managers resolve names. If a company uses an internal package called
utils, an attacker publishes a public package with the same name at a higher version number. The package manager installs the public one. - Account takeover — compromising a maintainer's credentials and publishing a malicious version of a legitimate, trusted package. The package name is real, the version looks normal, and existing users auto-upgrade into the trap.
- CI/CD poisoning — compromising GitHub Actions, build scripts, or CI tooling to inject malicious code during the build process or harvest secrets from the CI environment.
- Typosquatting — registering package names that look like popular ones (
expresss,@types-nodeinstead of@types/node). Developers install the wrong package by mistake, and it runs malicious code.
These aren't academic categories. Every one of them has been used in major incidents in the last 18 months (more on that later). Knowing the playbook matters because each tactic requires a different shift-left response.
A new type of attack: Slopsquatting
Slopsquatting (term coined by PSF Developer-in-Residence Seth Larson) is typosquatting's AI-native cousin: instead of exploiting a developer's typo, it exploits the model's hallucination. AI coding assistants routinely invent plausible-but-nonexistent package names, and an attacker who pre-registers a commonly hallucinated name gets malicious code installed by anyone who trusts the suggestion. What makes this scalable and not theoretical is that the hallucinations are consistent - the same prompts produce the same invented names, so an attacker only needs a handful of outputs to find a viable target.
It's also a clean example of why behavioral scanning is just as critical as CVE matching - more on that topic later.
The Ecosystems Were Never Built for This
The supply chain problem isn't limited to one ecosystem, but npm is the most instructive example of what happens when security is an afterthought.
npm: 14 Years of Default-Allow
For roughly 14 years, npm has allowed every package in your dependency tree to execute arbitrary code on your machine the moment you run npm install. No prompt, no sandbox, no permission model. A postinstall script in a package you've never heard of — buried five levels deep in your dependency graph — runs with full access to your filesystem, network, and environment variables.
This isn't a bug. It's a design decision that was never revisited until it was far too late.
Other ecosystems shifted left on this years ago:
- Deno launched in 2020 with a permission-based sandbox from day one: code can't touch the filesystem or network without explicit
--allow-*flags. Ryan Dahl, who created Node.js, built Deno specifically because he regretted Node's lack of sandboxing. - Bun has blocked lifecycle scripts from untrusted dependencies by default since its early releases, using a
trustedDependenciesallowlist. - pnpm v10 shipped default-deny for lifecycle scripts in late 2025.
npm? The first serious RFC to make install scripts opt-in was proposed in 2021 and rejected as too disruptive. npm v12 finally shipped the hard block in July 2026 - install scripts are opt-in at last. But keyv landed weeks later and still executed: pushing straight to main and cutting a release produced signed, provenance-backed versions, and its preinstall hook ran anyway. That's 14 years of default-allow arbitrary code execution, and the ecosystem is still catching up.
npm's flat, global namespace makes typosquatting trivially easy on top of all this. Anyone can register any unclaimed name; there's no verification that expresss has any relationship to express. Go's URL-based module system (github.com/user/repo) makes namespacing inherent. npm never made that shift.
It's Not Just npm
PyPI shares the flat namespace problem and has been hit by its own waves of malicious uploads — typosquatting campaigns, credential-harvesting packages, and dependency confusion attacks. GitHub Actions became a major attack vector when adversaries discovered they could compromise popular actions and harvest CI secrets from every repository that uses them. Container base images carry their own risks — a compromised or outdated base image propagates vulnerabilities into every service built on top of it. And system-level libraries aren't immune either — the xz-utils backdoor showed that even foundational open-source infrastructure can be patiently, methodically compromised over years.
The common thread: every ecosystem was built on implicit trust, and that trust is being exploited at scale.
Provenance Was Supposed to Help
Go shipped its checksum database in 2019 - a tamper-evident transparency log that records the cryptographic hash of every module version the first time it's downloaded anywhere in the world. From that point on, every go command verifies the hash matches the global record. If an attacker compromises the registry and swaps in malicious code at an existing version number, every client sees a mismatch and refuses to install. It's an integrity guarantee - it can't tell you whether code was malicious to begin with - but it proves no one tampered with it after the fact. It's default-on and ecosystem-wide. npm has no equivalent.
What npm does have is provenance - Sigstore-based attestations that link a published package to its source repo and CI build. It reached GA in September 2023, roughly four years behind Go's integrity guarantee. PyPI shipped trusted publishers in April 2023. npm's trusted publishers didn't land until July 2025.
Adoption tells the real story: only about 12% of qualifying top npm packages have provenance enabled. It remains optional and unenforced. And the TanStack attack in May 2026 demonstrated that provenance attestations could be forged by stealing OIDC tokens from CI runners - undermining the one trust signal the ecosystem had started to build. And keyv (August 2026) showed the flip side: its poisoned versions carried legitimately valid provenance - not forged but abused, published straight from a compromised source repo through trusted publishing. The attestation was true and still meant nothing.
If you can't shift left of the signing infrastructure itself, provenance is a speed bump, not a wall.
What Happens When It Goes Wrong
The last 18 months have produced a volume and severity of supply chain incidents that would have been hard to imagine a few years ago:
- Shai-Hulud (September 2025) - a self-replicating npm worm that harvested
.npmrctokens and GitHub PATs viapostinstallscripts, then automatically published malicious versions of any packages it could access. Hundreds of packages compromised. CISA issued an alert. A second, more aggressive wave hit in November, affecting 25,000+ repositories. - Axios (March 2026) - North Korean state actor Sapphire Sleet published malicious versions of
axios(~70M weekly downloads). Because users commonly specify version ranges like^1.14.0, any project runningnpm installauto-resolved to the compromised version. - TanStack (May 2026) - 84 malicious versions across 42
@tanstack/*packages in six minutes, published with valid provenance attestations. The first supply chain attack to forge the trust signal that was supposed to prevent exactly this. - Mastra AI (June 2026) - Sapphire Sleet again. 144 packages in 88 minutes. Fully automated.
- keyv / cacheable (August 2026) - a maintainer GitHub-account takeover poisoned the entire keyv/cacheable family: ~434 packages, 1,300+ versions, and over 2 billion monthly installs. A Mini Shai-Hulud descendant added a preinstall hook that ran a credential-stealing worm and self-propagated using stolen tokens over OIDC trusted publishing. The poisoned versions shipped with valid GitHub Actions provenance.
The attacks are getting faster, more automated, and increasingly backed by nation-state resources. They exploit the defaults - auto-run scripts, flat namespaces, version range resolution, implicit CI trust - across every ecosystem. The cadence is now multiple significant campaigns per month.
Waiting for each ecosystem to fix its own defaults is not a viable security strategy.
Shifting Left of Your Own Code
The shift-left principle says catch issues as early as possible. For supply chain security, that means catching malicious code before it enters your environment - not after it runs, not after it deploys, not after your detections up the exfiltration. The earlier you catch it, the smaller the blast radius.
The ecosystems need fixing, and that's a community-wide effort. What we can do right now is control what enters our environment and how we respond when something slips through.
The Registry Firewall
We deployed a registry firewall as an in-cluster proxy that intercepts and scans every package download across npm, PyPI, and Go module registries. It runs behind an internal ALB restricted to our VPC, with DNS routed through Twingate - meaning both local development and CI builds pass through the same behavioral analysis layer.
This is shifting left to the earliest possible moment: the package is scanned before it's installed, not after.
The approach we chose is fundamentally different from traditional SCA tools. Instead of just matching CVE databases, it analyzes package behavior: install scripts, network access, filesystem operations, obfuscated code. This catches zero-day supply chain attacks that no CVE database would flag. A freshly published malicious package has no CVE entry - but it does have suspicious behavior, and behavioral analysis catches that.
💡 Tools worth evaluating
The registry firewall space has matured significantly.
- JFrog Curation adds inline firewall capabilities natively on top of Artifactory, especially compelling if you’re already in that ecosystem.
- Sonatype Repository Firewall is the longest-standing option, with AI-powered quarantine now expanded beyond Nexus.
- Veracode Package Firewall (built on Phylum's ML engine) and Endor Labs offer policy-driven blocking with configurable cooldown periods.
- Socket.dev is popular for its behavioral analysis at install time across 8 ecosystems.
- Aikido takes a different approach entirely - device-level kernel interception that blocks malicious installs even when developers bypass the corporate registry.
The right choice depends on your existing toolchain, but the important thing is having something between your developers and the public registries.
Enforced, Not Optional
A registry firewall is only as good as the guarantee that all traffic flows through it. If someone can just change an environment variable or edit their .npmrc to point directly at the public registry, the entire control is bypassed.
We use Iru (formerly Kandji) - a unified IT and security platform with MDM, EDR, and compliance automation - to enforce this at the OS level. DNS and proxy settings are pushed via locked MDM configuration profiles that users cannot override or remove. The endpoint literally cannot resolve package registry traffic outside the firewall path. Iru's audit and remediation loop checks device state in short intervals and auto-corrects any drift, so even if something changes between check-ins, it self-heals.
The risk scales with AI adoption. More people using AI tools means more package installs from more sources by more non-engineers (more on that later). Every new agent and every new user is another path that has to flow through the firewall - and the only way to guarantee that is enforcement at the OS level, not a wiki page asking people to configure their .npmrc correctly.
.png)
Never Install Day-Zero
We enforce a deliberate 7-day cooldown before newly published package versions become available in our environment. This shifts left even further - before behavioral scanning, before CI, before any developer touches it. The package simply doesn't exist in our world for seven days.
This method gives the security community, behavioral analysis tools, and each registry's trust-and-safety team time to identify and yank malicious versions before they ever enter the supply chain. Take the Axios attack: malicious versions were published and available for immediate installation via version range resolution. Our environment never saw them. The 7-day cooldown meant the community identified and removed the compromised versions long before they could
have reached us. The keyv/cacheable compromise weeks later is the sharper example: over 2 billion monthly installs exposed, yet the community yanked the malicious versions within roughly a day - comfortably inside the window our cooldown creates.
CI as a Security Boundary
The shift-left approach extends into CI/CD. Every Docker image is scanned before deployment -container scanning catches vulnerabilities that entered through base images or build-time dependencies, another supply chain vector that's easy to overlook. Wiz posts code review comments on PRs, holds application SBOMs, and blocks builds that fail policy. Security-only Dependabot across all repositories means we only adopt dependency updates that patch
known vulnerabilities - no blind version bumps.
The CI environment itself is fully monitored by Daylight's own detection engine - the same one watching our production infrastructure. And CI workflows run on least-privilege principles: each workflow only has access to the secrets it actually needs, scoped per environment and per service, with short TTLs. Even in the extreme case where a supply chain compromise would reach a CI container, it's exposed to a very limited set of secrets - not the keys to the kingdom.
.png)
The New Supply Chain: AI-Native Means Everyone Installs Packages Now
Here's the part that changes the math. Daylight is AI-native - and that doesn't just mean our engineers use AI tools. Everyone does. Product, security engineers, operations - Claude is embedded across the organization. We're heavily invested in it, and it makes the entire team faster.
It also means the supply chain threat surface has expanded far beyond engineering. Claude Code can install packages. An analyst exploring a data pipeline can trigger a dependency install without ever opening a terminal. A product person prototyping a workflow can pull in a package they've never evaluated. And attackers already know it: the August 2026 keyv worm planted malicious Claude Code and VS Code hooks as part of its payload. AI-assistant install paths are now an explicit target, not a hypothetical one. Gatekeeping engineers is mostly a solved problem; the new challenge is protecting everyone else without killing the speed that makes AI-native work worthwhile.
This is where infrastructure-level controls matter most. The registry firewall and 7-day cooldown don't care who triggered the install - every package download, from every source, passes through the same behavioral analysis layer.
That's the only way to shift left when the attack surface isn't "developers" anymore, it's "anyone with a prompt."
Supply Chain Is One Layer — Not the Whole Story
Everything described here - the registry firewall, the day-zero hold, behavioral scanning, AI tool detections - is one layer in a broader defense-in-depth architecture. It's the layer that shifts left the furthest, catching threats before they enter the environment. But it's not sufficient on its own.
A supply chain compromise that somehow bypasses every control above still has to contend with ingress hardening, WAF rules, and authentication enforced at the edge before application code is reachable. It has to move through a zero-trust network where every resource is a separate access decision and credentials expire in hours, not months.
We put the same emphasis on every layer. Supply chain security is where we shift left the hardest, but it only works because the layers behind it are just as deliberate. No single control is the answer. Defense in depth is.
The ecosystem won't save you. Your architecture has to.






