Software Supply Chain Attacks: Past, Present, and What Comes Next (May 13, 2026)
From event-stream to TanStack: the eight-year evolution of software supply chain threats, the global organized actors involved, and a…
Software Supply Chain Attacks: Past, Present, and What Comes Next (May 13, 2026)
From event-stream to TanStack: the eight-year evolution of software supply chain threats, the global organized actors involved, and a concrete defense guide for the modern developer.

Software Supply Chain Attacks: Past, Present, and What Comes Next (May 13, 2026)
TL;DR
- A supply chain attack means the adversary compromises a component the target trusts rather than attacking the target directly. Since roughly 90% of modern application code comes from external dependencies, compromising a single package effectively reaches millions of applications at once.
- The evolution: 2018’s event-stream was a manual attack by a single actor; 2025’s Shai-Hulud became the first truly self-propagating worm in npm history; 2026’s TanStack compromise even managed to bypass the SLSA attestation chain.
- The actors are now organized: TeamPCP (the March 2026 Trivy → LiteLLM → Bitwarden chain) and North Korea-linked UNC1069 (the axios attack) are the two most prominent groups. Dead-man’s switches, AI-assisted payload generation, and cross-ecosystem propagation are the new techniques.
- Defense has to be layered: registry cooldown (
min-release-age), lockfile and exact version pinning, lifecycle script control, fast response via SBOM discipline, CI/CD hardening (commit SHA pinning, ephemeral runners, OIDC), and mandatory hardware keys. None is sufficient alone; together they shift the attack economics. - The new threat model: “npm install is a safe command” is no longer a valid assumption. This isn’t a paranoid stance — it’s realistic.
The article is long (~6,600 words, ~26 min read). For readers who’d rather query or listen than read straight through — myself included — I prepared a NotebookLM on this topic where you can ask questions or use the built-in audio summaries.
The Invisible Danger
A developer sits down at nine in the morning, types npm install in the terminal, and presses Enter. The command takes two seconds. In those two seconds, with no warning system firing, code written by an attacker thousands of kilometers away may have already started running on that developer's machine. And the developer did nothing wrong: they installed the right package, the package's owner is a familiar maintainer, the package came from the official npmjs.com registry, and its cryptographic signatures verify.
This is where the most insidious threat in modern software lives. Supply chain attacks — where an adversary doesn’t go after the target directly but instead compromises a component the target trusts — have transformed over the past six years from a whispered academic concern into one of the top items on every senior CISO’s agenda. Between the first wild incidents of 2018 and the TanStack compromise of 2026, something fundamental has shifted: it’s no longer individual packages that get targeted, but the entire development ecosystem that has become an attack surface.
This article pulls together the history of how we got here, what is happening now, and the concrete things you can do to defend yourself. The intended audience is both the newcomer to security and the experienced developer curious about the technical details. Early sections introduce concepts; the body dives into attack anatomy and defensive configurations.
I previously discussed this topic on our Turkish-language podcast Dinozorlarla Kafa Ütüleme, episode 12 — “Dinosaurs on a Package Hunt! Welcome to Package Hell” (video, blog post) — with my friend Burak Selim Şenyurt back in April 2026. That conversation covered the broader landscape of the package ecosystem, dependency hell, npm’s absurd “everything” package, the axios attack, and AI’s influence on this ecosystem, all from a developer perspective. This article serves as the technical companion to that conversation: there we discussed the big picture, here I dig into attack anatomy and concrete defense configurations.
What Is a Supply Chain Attack?
In a classic cyberattack, the adversary tries to break into the target’s system directly. They send phishing emails, scan open ports, hunt for zero-days. In a supply chain attack, the logic flips: the adversary breaks into something the target trusts as a supplier, and reaches the target through that trust. In software, this supplier is almost always a third-party component — an npm package, a PyPI library, a NuGet package, a Docker image, a GitHub Action, a build tool, or a CI/CD pipeline.
To understand why this model is so effective, you have to look at the economics of modern software. When you open a Vue or React application, the code the developer actually wrote typically makes up only five to ten percent of the total codebase. The remaining ninety percent is supplied by dependencies — and dependencies of dependencies, and theirs. As Microsoft itself noted in its .NET blog, roughly ninety percent of the code in modern applications comes from open source dependencies [Source 1]. This means that when an attacker compromises a single package, they’re effectively touching millions of applications at once.
Attacks generally follow one of five vectors. First, maintainer account compromise: the attacker uses phishing, credential theft, or social engineering to get into a package owner’s account and publishes a new version. Second, typosquatting: a package is published with a name nearly identical to a popular one (axois instead of axios, colourama instead of colorama), exploiting typing mistakes. Third, dependency confusion: a package with the same name as an internal private package is published to the public registry, abusing the package manager's resolution priorities. Fourth, build pipeline takeover: the source code is clean, but the build process itself has been compromised and the published binary contains malicious code. Fifth, maintainer handoff: an attacker volunteers to take over a project from an exhausted or disengaged original owner.
These five vectors need to be considered separately because the defenses against each are different. Lockfile version pinning offers no protection against typosquatting; two-factor authentication can’t stop a maintainer handoff. An effective defense closes each of these gaps individually.
From Past to Present: Notable Incidents
2018 — event-stream: The Template for Modern Attacks
If you need to pin the birth of modern supply chain attacks to a single incident, it’s the event-stream affair, discovered in November 2018. event-stream was a Node.js package that simplified working with JavaScript data streams, downloaded roughly two million times a week [Source 2]. Its original author, Dominic Tarr, had not been actively maintaining it for years.
In September 2018, a GitHub user calling himself right9ctrl approached Tarr and offered to help maintain the package. Tarr accepted and transferred npm publishing rights to the new volunteer. No credentials were stolen; no phishing occurred. Shortly after, right9ctrl added a new dependency called flatmap-stream. This package contained an encrypted payload that activated only under one specific condition — if event-stream was running inside the build environment of the Copay Bitcoin wallet [Source 3].
The surgical precision of the attack was unnerving. The payload had three layers: the first used event-stream's npm description as a decryption key for the second stage; the second activated only during iOS, Android, or desktop build commands; the third extracted private keys and sent them to a server in Malaysia, but only when the user's wallet balance crossed a specific threshold [Source 4].
The malicious code ran undetected for two and a half months. By the time it was discovered, Tarr couldn’t remove the package from npm himself — he had given up publishing rights. The incident can be summed up in one sentence: no credentials were stolen, the attacker took control of the package through legitimate channels [Source 5]. The template for modern supply chain attacks was born.
2020 — SolarWinds/SUNBURST: Compromising the Build System
event-stream was an attack at the package level. SolarWinds taught the world that supply chain attacks could operate at an entirely different scale. SolarWinds' Orion IT performance monitoring platform was used by roughly 300,000 customers, including U.S. federal agencies [Source 6].
The timeline of the attack is a lesson in patience. The attackers accessed the SolarWinds network in September 2019. In October 2019, they tested code injection into the Orion platform. In February 2020, they integrated the SUNBURST malware into the build process. On March 26, 2020, SolarWinds began distributing certified Orion updates that had gone through its own signing chain to its customers — and those updates contained SUNBURST [Source 7].
The attack went undetected until December 2020. FireEye stumbled upon a backdoor coming through Orion while investigating the theft of its own red team tools [Source 8]. An estimated 18,000 organizations were running vulnerable Orion versions. The affected list included the U.S. Departments of Treasury, Commerce, Interior, and Energy, plus companies like Microsoft, Cisco, and Intel.
SolarWinds’ legacy permanently changed how the industry views the software supply chain. Executive Order 14028, signed in 2021, began requiring Software Bills of Materials (SBOMs) from federal software suppliers. Google proposed the SLSA framework (Supply-chain Levels for Software Artifacts) in the same period. The Sigstore project was born from this same motivation. Supply chain security was no longer an academic topic; it was a national security concern.
2021 — Codecov and ua-parser-js: CI/CD Becomes the Target
2021 was the year attackers shifted their focus from developer machines to CI/CD pipelines. In April 2021, the Bash Uploader script of the popular code coverage tool Codecov was compromised. Attackers exploited a credential leak in a Docker image to modify the script and redirected the environment variables — API keys, tokens, and secrets — from thousands of CI/CD environments to their own servers.
In October 2021, ua-parser-js, a user agent parsing library downloaded seven million times a week, was compromised through a maintainer account takeover. The attackers injected a crypto miner and an info-stealer into the new versions of the package [Source 9]. The compromise went undetected for at least seventeen hours.
These incidents demonstrated that attacks were no longer targeting just package code, but the infrastructure of the processes that produced those packages.
2024 — xz-utils: A Two-Year Social Engineering Operation
The xz-utils attack, discovered in March 2024, was a case study in just how patient social engineering can be. xz-utils is a data compression tool present in virtually every Linux distribution. Its liblzma library sits in the dependency chain of critical services like OpenSSH.
The attack’s origins traced back to November 2021. An account named “Jia Tan” (username JiaT75) began contributing to the project — small patches at first, then performance improvements. During the same period, accounts later identified as sockpuppets (Jigar Kumar, krygorin4545, misoeater91) started pressuring the project on GitHub issues, complaining that “the project isn’t progressing fast enough” and that “a new maintainer is needed” [Source 10]. The project’s exhausted, depressed, lone maintainer Lasse Collin eventually handed authority over to Jia Tan.
In February 2024, Jia Tan released xz-utils version 5.6.0. The release contained a backdoor, but the backdoor was not visible in the GitHub source repository — it was hidden, fragmented, inside test files in the published tarball. Under specific system configurations, the build scripts would reassemble these fragments and link them into liblzma, adding code that intercepted OpenSSH’s RSA authentication mechanism. An attacker with a specific Ed448 private key could connect via any SSH client and execute arbitrary code as root [Source 11]. CVSS score: 10.0, the maximum possible.
This attack was caught almost by miracle, by Microsoft engineer Andres Freund, who noticed that his PostgreSQL benchmark’s SSH connections were taking 500ms longer than expected [Source 12]. Freund spent several days investigating the performance regression and eventually traced it to an unusual M4 macro being invoked in liblzma. Had Freund dismissed that anomaly as a normal bug, xz-utils 5.6.0 would have made it into the stable versions of Debian, Ubuntu, Fedora, and Red Hat within weeks, and a significant slice of the internet would have been backdoored by its own package manager.
xz-utils laid bare the structural fragility of the open source security model. Critical infrastructure is maintained for free by exhausted, sick, isolated people. With enough patience, a state-level actor can wear such a maintainer down over years and seize control of the project.
2024 — Polyfill.io: Domain Hijacking
While xz-utils dominated security headlines, the Polyfill.io incident of June 2024 revealed another flavor of supply chain attack. Polyfill.io was a CDN service that provided JavaScript polyfills for older browsers. After the service was sold to a Chinese company, the CDN — loaded on roughly 100,000 websites — began exploiting browser vulnerabilities, redirecting visitors to gambling sites, and injecting spyware.
Polyfill.io’s mechanic wasn’t a classic package compromise: the code wasn’t even being written at compile time, and didn’t run on the developer’s machine but in the end user’s browser. But the principle was the same — a source the developer trusted (a CDN URL) was compromised, and that trust was exploited end to end.
2025–2026: The Age of Worms Begins
What happened in late 2025 and through 2026 showed that supply chain attacks had taken a qualitative leap. Earlier attacks were manual: an attacker would compromise a package, drop a payload, collect the reward, and disappear. The new generation propagates automatically — it behaves like a worm. When it infects a developer machine, it spreads automatically to every package that developer has publishing rights for, then jumps to other ecosystems and multiplies there too.
September 2025 — The Qix Incident: Phishing’s Modern Face
On September 8, 2025, just a week before Shai-Hulud entered the scene, the npm ecosystem was shaken by a different kind of attack. Josh Junon — known on npm as “Qix-” and the maintainer of foundational libraries like chalk, debug, color-convert, strip-ansi, and ansi-styles — fell victim to a sophisticated phishing attack [Source 35]. Using a fake domain (npmjs[.]help) registered five days earlier, the attacker sent a "2FA reset" email that looked nearly authentic, and captured Qix's username, password, and live TOTP code. Within minutes, the attacker had published new malicious versions of more than 20 of Qix's packages — packages with a combined weekly download count of roughly 2 billion.
The payload ran in the browser context, hooking into window.fetch, XMLHttpRequest, and window.ethereum.request to replace the destination addresses in crypto wallet transactions with the attacker's own addresses. The malicious versions stayed live for about two hours. What this incident really showed was how inadequate TOTP-based 2FA has become against "live phishing" — the attacker can relay the victim's TOTP code in real time and open the account. The Qix incident became a concrete example of why hardware security keys (FIDO2) for high-download package maintainers should no longer be a debate, but a standard.
September 2025 — Shai-Hulud 1.0: The First Self-Propagating Attack
On September 15, 2025, security researchers noticed strange activity on the npm registry. Dozens of packages — including the popular color library chalk, downloaded more than two million times a week — had suddenly published new versions. The versions contained a postinstall script that, at install time, harvested environment variables, GitHub tokens, npm tokens, AWS credentials, and SSH keys from the developer's machine [Source 13].
What was new about this attack was this: the harvested credentials weren’t only sent to the attacker, they were also used for automatic propagation. If a stolen npm token had publishing rights for another popular package, the malware would publish a new version of that package on its own — carrying the same malicious payload. The stolen data was uploaded to public GitHub repositories the attacker created under the name Shai-Hulud. The campaign, named after the giant sandworms of Dune, thereby became the first supply chain attack in npm history to display true worm behavior [Source 14].
Shai-Hulud 1.0 was later traced back to the August 2025 s1ngularity/Nx incident. Attackers had exploited a GitHub Actions vulnerability in the Nx build system to steal an npm publishing token, which then kicked off the Shai-Hulud chain.
November 2025 — Shai-Hulud 2.0: The Scale Explosion
On November 24, 2025, a new wave of Shai-Hulud was detected. This time the campaign’s signature was the phrase “Sha1-Hulud: The Second Coming” appearing in GitHub repository descriptions [Source 15]. Packages from major projects like AsyncAPI, Zapier, PostHog, and Postman were affected.
The technical evolution in the second wave was notable. In the first wave the malicious code ran in postinstall; in the second it had moved to preinstall — meaning before the package's own dependencies even started installing. This dramatically expanded the attack surface on developer machines and CI/CD pipelines [Source 16]. Wiz Research reported that the second wave produced more than 25,000 malicious repositories across approximately 350 different GitHub users, growing at a rate of about 1,000 new repos every 30 minutes [Source 17].
Unit 42’s analysis found signs that an LLM may have been used to write the malicious bash scripts in this wave — the code contained unnecessary explanatory comments and emojis [Source 18]. This was a concrete signal that modern attacks were beginning to incorporate AI-assisted production processes as well.
November 2025 — The NuGet Front: Time Bombs
In the same month, the .NET ecosystem faced its own supply chain attack. Socket’s research team identified nine malicious packages published on NuGet under the username shanhai666 between 2023 and 2024 [Source 19]. The packages had names like MyDbRepository, Sharp7Extend, SqlUnicornCore — ostensibly legitimate database and PLC communication libraries. They had been downloaded 9,488 times in total.
What made the attack chilling was its timing. The packages were 99 percent functional code — they really did execute database queries, they really did talk to Siemens S7 PLCs. The remaining roughly twenty lines of malicious code were buried inside C# extension methods. Every .Exec() call or .BeginTran() call was designed to invoke Process.GetCurrentProcess().Kill() with a 20 percent probability after a hardcoded date (August 2027 and November 2028) [Source 20].
The most dangerous package, Sharp7Extend, used a mechanism that activated 30–90 minutes after installation to silently fail 80 percent of write operations sent to PLCs. In industrial control systems, this could mean factory lines failing quality control or safety-critical systems behaving incorrectly. The attack model blurred the line between sabotage and malfunction, making attribution nearly impossible.
January 2026 — PackageGate: Cracks in the Defenses
In January 2026, a security firm called Koi published six zero-day vulnerabilities affecting the npm, pnpm, vlt, and Bun package managers, collectively dubbed “PackageGate” [Source 21]. What the vulnerabilities had in common was that they could bypass the primary defense layers recommended after Shai-Hulud — namely --ignore-scripts and lockfile integrity.
The most worrying vulnerability concerned Git-based dependencies. A GitHub repository could carry configuration that influenced the Git operations the package manager performed during install, allowing code to execute even when lifecycle scripts were supposedly disabled. pnpm, vlt, and Bun closed their respective vulnerabilities within weeks. npm, however, closed the report as “informative,” stating that the feature worked as intended. Much of the security community found this response troubling.
March–April 2026 — Professionalization: The TeamPCP Chain and a Parallel UNC1069 Campaign
March 2026 became the month in which two organized threat actors mounted parallel attacks against the npm ecosystem. On one side, TeamPCP (also tracked as DeadCatx3, PCPcat, ShellForce, and CipherForce) ran a rapid succession of attacks — not against single packages but as a chain that propagated through one another. On the other side, North Korea-linked UNC1069 went after the most popular packages directly, including axios. No evidence of direct coordination existed between the two groups; but both exploited the same structural weaknesses (maintainer account takeover, pipeline abuse) using different techniques.
On March 19, 2026, the attacker exploited a pull_request_target misconfiguration in the GitHub Actions workflow of Trivy, Aqua Security's popular container scanner, to steal the aqua-bot Personal Access Token [Source 22]. Using that token, 76 of the 77 release tags in the trivy-action repository, and all seven tags in setup-trivy, were force-pushed to malicious commits. Malicious builds were sent through every one of Trivy's distribution channels: GHCR, ECR Public, Docker Hub, deb, and rpm.
The Trivy compromise gave the attacker credentials to reach Checkmarx KICS, LiteLLM, and other downstream tools. On March 24, two versions of LiteLLM (1.82.7 and 1.82.8) were published to PyPI with malicious code [Source 23]. LiteLLM, an AI gateway layer, was downloaded approximately 3.4 million times a day. On compromised systems, the malware harvested environment variables, SSH keys, cloud credentials, Kubernetes configurations, and Docker setups, encrypted them with AES-256 wrapped in RSA-4096, and exfiltrated them to a typosquat domain (models.litellm[.]cloud) under attacker control.
On March 31, 2026, the axios npm package — an HTTP client downloaded more than 100 million times a week and present, directly or transitively, in nearly every JavaScript project — was compromised [Source 24]. Here, a different threat actor was on stage. The lead maintainer’s npm account was taken over; versions 1.14.1 (1.x branch) and 0.30.4 (legacy 0.x) were published 39 minutes apart. The attacker used a phantom dependency, plain-crypto-js@4.2.1, which had been strategically published roughly 18 hours before the axios versions — meaning the malicious code wasn't directly in axios, but in a new dependency of axios. The postinstall hook of that phantom dependency was an obfuscated dropper GTIG named SILKBELL; it delivered the WAVESHAPER.V2 RAT, compiled separately for macOS, Windows, and Linux, then cleaned up its own traces to delay detection. Google Threat Intelligence Group attributed the attack, in a report published April 1, to UNC1069 — a North Korea-linked, financially motivated cluster active since at least 2018 [Source 36]. The attribution rested on WAVESHAPER.V2 being an evolution of the older WAVESHAPER backdoor, and on overlaps between the C2 infrastructure (sfrclak[.]com, 142.11.206.73) and AstrillVPN nodes previously associated with UNC1069. Critically, GTIG made clear that this campaign was a separate operation from TeamPCP's Trivy/LiteLLM chain; two different organized actors were mounting parallel attacks on the npm ecosystem in the same window.
Back on the TeamPCP front in April 2026, the Bitwarden CLI npm package (@bitwarden/cli@2026.4.0) was compromised by the group [Source 25]. Public repository descriptions carried the phrase "Shai-Hulud: The Third Coming." In the same period, four npm packages of SAP's Cloud Application Programming Model were also targeted (@cap-js/sqlite, @cap-js/db-service, and two others, with roughly 570,000 weekly downloads combined).
May 2026 — TanStack: Bypassing SLSA
May 11, 2026, took the blow to the npm ecosystem to another dimension. In a six-minute window between 19:20 and 19:26 UTC, 84 malicious versions of 42 packages in TanStack’s @tanstack/router family were published [Source 26]. Among the affected packages, @tanstack/react-router alone was downloaded roughly 12.7 million times per week.
What set this attack apart technically was this: the attacker did not steal npm credentials, did not break certificates, did not take over an account. Instead, they hijacked TanStack’s own legitimate release pipeline, and the packages were published using TanStack’s real OIDC identity. The result: the published packages carried valid SLSA Build Level 3 provenance attestations [Source 27]. Packages that returned “verified” when you ran npm audit signatures — and yet were malicious.
The technical anatomy chained three vulnerabilities together. First, the attacker created a fork of TanStack/router (renamed to zblgg/configuration to hide from fork-list searches). Then they opened a pull request that exploited the bundle-size.yml workflow, which used a pull_request_target trigger. That workflow checked out the fork's code using actions/checkout@v6.0.2 and ran it in the base repository's security context — meaning attacker-controlled code gained access to the base repository's GitHub Actions cache scope and GITHUB_TOKEN. The attacker poisoned the cache: when legitimate maintainers merged their PRs to main, the release workflow restored the poisoned cache and executed the attacker's binaries. Those binaries extracted the OIDC token from the runner process's memory (/proc/<pid>/mem). The OIDC token is TanStack's authority to sign attestations for npm. Using that token, the attacker ran npm publish, and packages were born that looked perfect in the sigstore chain but were malicious in content [Source 28].
The payload itself had also evolved. It installs a persistent gh-token-monitor daemon on developer machines (via macOS LaunchAgent or Linux systemd) that polls the GitHub API every 60 seconds. When the token is revoked and the daemon receives an HTTP 40X response, it runs rm -rf ~/ — a dead-man's switch. The reflex to revoke a token when an attack is detected becomes a trap that amplifies the damage to the machine.
A Glossary of New Attack Techniques
The 2025–2026 wave added several new concepts to the security community’s vocabulary. Understanding them matters not only for reading these particular attacks, but for anticipating tomorrow’s.
OIDC token hijacking is the technique of extracting short-lived credentials from a GitHub Actions runner’s process memory. A runner receives a short-lived token via OIDC in order to sign attestations to a registry like npm. That token is held in memory. If an attacker can run code on that runner (via cache poisoning or some other vector), they can read the token from the /proc filesystem.
Cache poisoning combined with the pull_request_target Pwn Request pattern exploits two distinct flaws in GitHub Actions. The pull_request_target trigger runs a PR's workflow in the base repository's security context — distinct from the normal pull_request trigger. Executing code from a fork in that context means fork-controlled code can access the base repository's secrets. The pattern was first demonstrated by security researcher Adnan Khan in 2024 against Angular, MDN, and hyperledger/besu, but years later it remained unfixed in many large projects.
Dead-man’s switch is a mechanism that harms the victim machine when an attack is detected. In the TanStack payload, the token monitor daemon dropped onto the developer machine deletes the home directory the moment it sees the GitHub token revoked. This means the conventional incident response reflex — revoke the token first, then clean up — now works against you.
Cross-ecosystem propagation is the use of a stolen token to spread across multiple package ecosystems. In April 2026, the pgserve attack (campaign name: CanisterSprawl) started in npm and jumped to Python via PyPI tokens it found along the way [Source 29]. To an attacker, a developer environment isn't a "Python developer" or an "npm developer" — it's a "credentialed developer."
SLSA provenance bypass shows exactly where the attestation infrastructure’s trust model creates fragility. SLSA Build Level 3 cryptographically proves “who built this package, on which build system, from which source commit.” But attestation does not prove that the package’s intent is correct; it only proves that it passed through the stated pipeline. If the pipeline itself is hijacked at runtime, the attestation still looks valid. The TanStack attack exploited precisely this gap.
Defense Layers
No effective defense can rest on a single solution, because the attack surface is multilayered. The following layers are complementary — none is sufficient on its own. “Defense in depth” is exactly the principle at work.
Layer 1 — Registry Level: Minimum Release Age and Cooldown
Most supply chain attacks are detected within minutes or hours of publication. Twenty minutes for TanStack, around four hours for axios, sometimes thirty minutes for Shai-Hulud. If your package manager doesn’t automatically install brand-new versions, the risk of becoming “patient zero” largely disappears.
npm 11.10.0 and later supports a min-release-age setting [Source 30]. The command is npm config set min-release-age 2d — don't install versions less than 48 hours old. On pnpm, pnpm config set minimumReleaseAge 2880 (minutes); on Bun, minimumReleaseAge = 172800 (seconds) in bunfig.toml; on Yarn, yarn config set npmMinimalAgeGate "48h". Dependabot has reportedly supported minimum package age natively since July 2025.
This isn’t sufficient on its own, but it’s a large protection layer purchased cheaply.
Layer 2 — Lockfiles and Exact Version Pinning
When you write "axios": "^1.14.0" in package.json, you've given npm the authority to fetch the latest version in the 1.x family automatically. The March 2026 axios attack spread through exactly this mechanism: everyone with ^1.14.0 automatically received the malicious 1.14.1.
A disciplined setup is this: remove the caret (^) and tilde (~) operators from package.json and write exact version numbers. Always commit package-lock.json or pnpm-lock.yaml. In CI/CD, use **npm ci** rather than npm install — this command strictly follows the lockfile and never updates it. Endor Labs has been explicit on this: committing the lockfile and using it is one of the foundational mitigators of supply chain risk [Source 31].
Layer 3 — Lifecycle Script Control
Historically, the vast majority of malicious packages used preinstall, postinstall, or prepare hooks. These hooks run automatically during package installation and execute code in the full context of the developer's machine.
pnpm v10 disables postinstall scripts by default [Source 32]. You add only trusted packages (esbuild, sharp, those needing native bindings) to the allowBuilds list. On the npm side, npm config set ignore-scripts true is more aggressive; some legitimate packages will break, so project-specific exceptions may be needed. In CI/CD pipelines, npm ci --ignore-scripts can become standard policy.
Layer 4 — SBOM and Provenance Verification
A Software Bill of Materials (SBOM) is an inventory of which packages, which versions, and which licenses your application uses. CycloneDX and SPDX are the two common formats. When a compromise is announced, teams without an SBOM spend hours — sometimes days — investigating whether they’re affected; teams with SBOM discipline run a query and get an answer in minutes.
The SLSA framework is also part of this layer. Provenance attestations prove which build system and which commit a package came from. The npm audit signatures command verifies available attestations. But as the TanStack case showed, provenance doesn't mean "this package's intent is correct" — it means "this package's pipeline is consistent." Provenance is therefore valuable as a defense layer, but not sufficient.
Layer 5 — CI/CD Hardening
CI/CD pipelines are the most critical attack surface in modern applications. There are many hardening steps, but each is applicable.
In GitHub Actions, pin action versions to commit SHAs rather than tags: uses: aquasecurity/trivy-action@a1b2c3d4.... Tags can be force-pushed; commit SHAs cannot change [Source 33]. Avoid the pull_request_target trigger where possible; if you must use it, never check out fork code with actions/checkout. Use short-lived credentials via OIDC, and minimize reliance on long-lived PATs (Personal Access Tokens). Make runners ephemeral (a new one per job) — a persistent runner is a persistent attack surface.
Build runners should have no access to production secrets. You build in the build stage; you inject secrets in the deploy stage. The separation costs nothing but dramatically limits the blast radius of chained compromises like Trivy’s.
Layer 6 — Maintainer Hygiene: Mandatory Hardware Keys
The March 2026 axios attack began with the lead maintainer’s account being hijacked. Had the account been protected by a mandatory hardware security key (FIDO2), the attack could never have started. Neither TOTP nor SMS would have helped — phones can be hijacked, TOTP secrets can be phished; but a hardware key cannot be opened without the physical device.
This is a measure on the maintainer’s side, but as a consumer you can also influence it. The question “are the owners of this package using hardware keys?” should become a fair thing to ask for important packages. On the npm side, mandatory hardware keys for owners of high-download packages is a topic of ongoing debate.
Layer 7 — Internal Registry Proxy
Rather than depending on the public registry directly, fetching packages through an internal proxy like Nexus, Artifactory, or Verdaccio offers a major defense layer at enterprise scale. The proxy keeps an allowlist of vetted known packages, caches known-good versions (so the build keeps working even if the public registry is unreachable during a new attack), inspects incoming packages with scanners, and can quickly block packages when a compromise is announced.
For organizations at the scale of a typical enterprise, this isn’t a luxury — it’s basic infrastructure. Traffic from developers directly to registry.npmjs.org has become an unacceptable risk for corporate security.
Layer 8 — Network Controls and Runtime Monitoring
If everything else fails and malicious code does run during installation, the last layer is network and runtime monitoring. Block known C2 (command and control) domains at the DNS level: filev2.getsession.org, git-tanstack.com, sfrclak.com, models.litellm.cloud, and other known IOCs. Watch for unexpected egress traffic from developer and CI environments. Runtime security tools like Falco can catch anomalous syscall patterns inside containers.
For developer machines, the practical equivalent is this: when working on a critical project, keep a separate user profile at the OS level, and where possible use ephemeral environments like Dev Containers or Nix shell. If the session running npm install has no access to your cloud credentials, personal SSH keys, or crypto wallets, even the worst case is contained.
Notes for .NET and NuGet Developers
While the JavaScript ecosystem dominates the headlines, the .NET side isn’t sitting idle. As Microsoft notes in its own .NET blog, NuGet has proactively integrated several defense mechanisms: Package ID Prefix Reservations, mandatory 2FA for publishers, and Package Source Mapping [Source 1].
Package Source Mapping lets you explicitly state which packages come from which feeds. In nuget.config, you can set up a configuration where internal packages come from corporate-feed, known third-party packages come from a specifically vetted feed, and everything else either doesn't come at all or comes through a vetted public proxy. This is a durable defense against dependency confusion attacks.
That said, the NuGet ecosystem has not yet seen a full-scale equivalent of the worm attacks the npm world has faced. The shanhai666 incident of November 2025 was a warning shot: packages that are functional and look safe, but carry delayed logic bombs inside. The February 2026 combination of NCryptYo / DOMOAuth2 / IRAOAuth2.0 / SimpleWriter was a coordinated campaign aimed at exfiltrating ASP.NET Identity data and injecting backdoors into the authorization layer [Source 34]. The goal of that campaign wasn’t to compromise the developer’s machine — it was to backdoor the application the developer produced and shipped to production. The deployed ASP.NET applications were modified to automatically grant admin rights to users authorized by the attacker’s C&C infrastructure.
Concrete recommendations for the NuGet ecosystem: Package Source Mapping must be configured. Packages from unknown publishers, especially newly published ones with low download counts, should never be added as dependencies without code review. Pay extra attention to the code of packages that make heavy use of C# extension methods — the Sharp7Extend case showed how convenient extension methods are as interception structures. Legacy CI/CD configurations that leak prod credentials to build runners need to be revisited.
A Practical Checklist for Developers
This section is a summary — a concrete, actionable list distilled from the layers above.
At the developer machine level: Enable min-release-age in your package manager. For critical projects, use Dev Containers or at minimum a separate user session. Don't carry cloud credentials in your environment during every session — inject them only when needed. Use passphrases on your SSH keys. Get a hardware security key (YubiKey) and make it mandatory for your npm, GitHub, NuGet, AWS, and GCP accounts.
At the project level: Always commit package.json, package-lock.json, or the equivalent. Remove caret/tilde operators from critical dependencies. Make npm ci or pnpm install --frozen-lockfile the standard command. Explicitly manage pnpm's allowBuilds list. Question in your README which dependencies are really necessary — unused dependencies are also attack surface.
At the CI/CD level: If you use GitHub Actions, pin every action to a commit SHA. Review your pull_request_target triggers; if needed, never check out fork code with actions/checkout. Use short-lived credentials via OIDC. Make build runners ephemeral. Cut the build stage's access to production secrets. Make --ignore-scripts standard policy in CI pipelines.
At the organizational level: Set up an internal package proxy (Nexus, Artifactory, Verdaccio, GitHub Packages, Azure Artifacts) and block developers from going directly to the public registry at the network level. Generate SBOMs and make querying them against known compromises standard procedure. Monitor maintainers of critical packages — who owns which, did anyone change their email recently, is MFA active. Prepare an incident response playbook for supply chain events. And most importantly: keep the infrastructure ready to answer “are we affected?” within five minutes when a compromise is announced.
At the moment of an incident: When a compromise is detected, the classic reflex (“revoke the token first”) is no longer always right. The TanStack attack showed that the payload may carry a dead-man’s switch, and revoking the token may trigger a disk wipe. The correct sequence: isolate the machine from the network first, then back up important data (personal files, projects) to a separate disk, then completely rebuild the machine from scratch, and only then revoke and rotate tokens. If a CI/CD pipeline was affected, every secret it had access to (cloud keys, registry tokens, deployment credentials) must be regenerated from zero.
The Threat Model Has Changed
In the 2018 event-stream incident the attacker was one person, the motivation was bitcoin theft, the impact was limited to a single application (Copay). In the 2026 TanStack incident the attacker was an organized group (TeamPCP), the motivation was multilayered (credential theft, propagation, ransom), and the impact was potentially global. Within an eight-year span, we moved from individual hobby projects to systemic attacks at the ecosystem level.
Expecting this evolution to stop isn’t realistic. The deepening dependency chains of modern applications keep expanding the attack surface. The open source economy still entrusts critical infrastructure to exhausted maintainers working for free. CI/CD pipelines are still designed under the assumption that “anything goes during build.” Hardware key requirements are still not standard for package publishers. Frameworks like SLSA are useful, but attackers have learned to hijack the pipelines they protect at runtime as well.
The good news is this: the practical measures available at the individual and team level are both concrete and relatively cheap. Committing a lockfile costs nothing. Setting min-release-age costs nothing. A hardware key costs 50 dollars. Configuring Package Source Mapping takes an afternoon. Disciplining pnpm's allowBuilds list is a one-time setup followed by low maintenance. None of these measures is sufficient alone, but together they turn the attack's economics against the attacker.
There’s bad news too: no defense layer is one hundred percent. A modern developer can’t operate under the assumption that “npm install is a safe command.” This isn’t a paranoid stance, it’s a realistic threat model. By the same token, “we’re a small team, no one targets us” isn’t a valid argument either — the Shai-Hulud worm doesn’t target anyone, it tries to jump to every developer it can reach through the dependency chain. Even if you aren’t patient zero, you can become the virus’s distribution channel.
There are things to expect in the coming period. AI-assisted malicious code generation will become commonplace (Unit 42 observed LLM signatures in its Shai-Hulud 2.0 analysis). New attack vectors will emerge for AI agents (the LiteLLM compromise was the first major incident of this kind). Alongside more traditional targets (payment systems, identity providers), LLM gateways, MCP servers, and agent orchestrators will become attack surfaces. Industrial control systems will face similar attacks at the critical infrastructure layer (the Sharp7Extend case at NuGet demonstrated this).
The bottom line: software supply chain security can no longer be the concern of security teams alone — it has to be part of every developer’s daily discipline. Pausing two minutes before installing a package, making the lockfile-commit reflex automatic, putting on a hardware key — these are no longer advanced practices, they’re basic hygiene. The threat model has changed; the response has to change too.
Sources
- Building a Safer Future — How NuGet is Tackling Software Supply Chain Threats — .NET Blog
- npm Dependencies, Supply Chain Attacks, and Bitcoin Wallets — Black Duck
- A Post-Mortem of the Malicious event-stream Backdoor — Snyk
- A Systematic Analysis of the Event-Stream Incident — es-incident.github.io
- Details About the event-stream Incident — npm Blog
- SolarWinds Hack Explained: Everything You Need to Know — TechTarget
- A Timeline of the SolarWinds Hack — Kiuwan
- The SolarWinds Hack Timeline: Who Knew What, and When? — CSO Online
- Defending Lodestar Against NPM Supply Chain Attacks — ChainSafe Blog
- XZ Utils Backdoor — Wikipedia
- The XZ Utils Backdoor (CVE-2024–3094): Everything You Need to Know — Datadog Security Labs
- The Xz-Utils Backdoor: The Supply Chain RCE That Got Caught — Invicti
- Shai-Hulud npm Supply Chain Attack — Wiz Blog
- Understanding NPM Worms and the Shai-Hulud Attack — Endor Labs
- The Shai-Hulud 2.0 npm Worm: Analysis — Datadog Security Labs
- “Shai-Hulud” Worm Compromises npm Ecosystem — Unit 42
- New Shai-Hulud Worm Spreading Through npm, GitHub — CSO Online
- Navigating the Shai-Hulud Worm 2.0 — Elastic Blog
- Hidden Logic Bombs in Malware-Laced NuGet Packages — The Hacker News
- Malicious NuGet Packages Hide Time-Delayed Sabotage Code — eSecurity Planet
- npm Supply Chain Attacks 2026: Defense Guide for SaaS Teams — Bastion
- LiteLLM and Telnyx Compromised on PyPI: Tracing the TeamPCP Supply Chain Campaign — Datadog Security Labs
- PyPI Supply Chain Attack Compromises LiteLLM — InfoQ
- Axios NPM Package Compromised — Trend Micro
- The npm Threat Landscape: Attack Surface and Mitigations — Unit 42
- Postmortem: TanStack npm Supply-Chain Compromise — TanStack Blog
- TanStack npm Packages Hit by Mini Shai-Hulud — Snyk
- Mini Shai-Hulud Strikes Again: TanStack + More npm Packages Compromised — Wiz Blog
- No Off Season: Three Supply Chain Campaigns Hit npm, PyPI, and Docker Hub in 48 Hours — GitGuardian
- Defending Against NPM Supply Chain Attacks: A Practical Guide — ArmorCode
- How to Defend Against NPM Software Supply Chain Attacks — Endor Labs
- Mitigating Supply Chain Attacks — pnpm Documentation
- 12 Best Practices to Prevent Software Supply Chain Attacks (2026) — Bastion
- Four Malicious NuGet Packages Target ASP.NET Developers — Socket
- npm Author Qix Compromised via Phishing Email in Major Supply Chain Attack — Socket
- North Korea-Nexus Threat Actor Compromises Widely Used Axios NPM Package in Supply Chain Attack — Google Cloud Blog (GTIG)
This article is based on incidents and analyses published as of May 2026. Because supply chain attacks evolve quickly, it’s worth cross-checking the current documentation of your package manager and CI/CD platform when applying specific defense configurations.
메타데이터
- post_id
- ebcf89a9f3f3
- slug
- software-supply-chain-attacks-past-present-and-what-comes-next-may-13-2026-ebcf89a9f3f3
- url
- https://ourhaventech.com/software-supply-chain-attacks-past-present-and-what-comes-next-may-13-2026-ebcf89a9f3f3
- canonical_url
- https://ourhaventech.com/software-supply-chain-attacks-past-present-and-what-comes-next-may-13-2026-ebcf89a9f3f3
- author_url
- https://medium.com/@alperkonuralp
- status
- ok
- fetched_at
- 2026-06-09 15:37:30