Skip to content

Software Supply Chain Attacks: How They Work and How Teams Defend

What is a supply chain attack? How software supply chain attacks work, from SolarWinds and 3CX to Shai-Hulud and Axios, and the npm and PyPI defenses that hold.

Yubico YubiKey 5C NFC hardware security key with a USB-C connector and gold touch sensor on a white background
YubiKey 5C NFC · Credit: Yubico

A software supply chain attack is a cyberattack that compromises the code, build systems or publishing accounts a team already trusts, so that malicious code reaches victims inside a normal dependency, update or release. Nobody on the receiving end has to click a phishing link; a routine npm install or pip install does the work. Supply chain attacks also reach hardware and vendor update channels, but package registries such as npm and PyPI sit at the center of the software risk: GitHub traced the Shai-Hulud worm to compromised maintainer accounts. The defenses that hold up split cleanly between the people who publish packages and the people who install them.

What Is a Supply Chain Attack?

A supply chain attack is a cyberattack that reaches its targets through a supplier they already trust instead of attacking them directly. MITRE ATT&CK defines supply chain compromise as manipulating products or product delivery mechanisms before a final consumer receives them. The product can be a software dependency, an application update or a piece of hardware.

MITRE splits the technique into three types, and a software supply chain attack can fall under either of the first two:

  • Software dependencies and development tools (T1195.001). Malicious code added to open-source packages such as pip and npm packages, lookalike names chosen through typosquatting, abandoned packages re-registered by attackers, and CI/CD components such as GitHub Actions.
  • Software supply chain (T1195.002). Tampering with an application before delivery, by changing its source code, hijacking its update or distribution mechanism, or swapping a compiled release for a modified one.
  • Hardware supply chain (T1195.003). Modified hardware or firmware in servers, workstations, network gear or peripherals, which MITRE says can plant a backdoor that is difficult to detect.

The difference from a direct attack is the delivery route. MITRE notes that attackers looking to run code have often focused on malicious additions to legitimate software in distribution or update channels, and that they may push a tainted release to a broad set of users while following up only on chosen victims. The victim installs the attack as part of normal work, which is why a supply chain compromise can stay hidden behind a trusted name.

How a Software Supply Chain Attack Works

A software supply chain attack targets the path code travels before it runs, rather than the running system. MITRE ATT&CK files the technique as Compromise Software Dependencies and Development Tools (T1195.001): adversaries manipulate dependencies and development tools before they reach the final consumer. The OWASP Software Supply Chain Security Cheat Sheet sorts the threats by the part of the chain they hit:

  • Source code threats. Malicious or vulnerable code slipped into a repository, version control exploits, or builds from an unauthorized branch.
  • Build environment threats. Changing the artifact without touching the source, for example by poisoning a build cache or hijacking a privileged build account.
  • Dependency threats. Pulling in a compromised or vulnerable direct or transitive dependency, which OWASP calls the most common case.
  • Deployment and runtime threats. A compromised CI/CD account, a misconfiguration, or a compromised binary shipped to production.

OWASP also names dependency confusion, stolen code signing certificates and CI/CD exploits as specific threats, and it warns that a compromised supplier can pass the damage to many customers downstream. That fan-out is what separates a supply chain compromise from an ordinary breach. The attacker breaks in once and lets the victims' own update habits do the distribution.

Landmark Supply Chain Attacks: SolarWinds and 3CX

Two older supply chain attacks still define how security teams talk about a software supply chain attack, because both went through a vendor's build system rather than a public registry. MITRE ATT&CK documents each as a campaign:

AttackActive (per MITRE)Way inReach
SolarWinds Compromise (C0024)First seen August 2019, discovered mid-December 2020APT29 injected malicious code into the SolarWinds Orion build process, shipped through a normal software updateThe US government assessed about 18,000 affected Orion customers, with a much smaller number hit by follow-on activity
3CX Supply Chain Attack (C0057)November 2022 to March 2023A 3CX employee ran a trojanized, end-of-life copy of Trading Technologies' X_Trader; the attackers then compromised the Windows and macOS build environments for the 3CX desktop app3CX serves more than 600,000 customers and 12 million users; only a subset of systems were affected

MITRE calls 3CX the first publicly reported case of one supply chain compromise triggering another. The US and UK governments attributed the SolarWinds operation to Russia's Foreign Intelligence Service (SVR) in April 2021, according to the MITRE campaign entry. Both fit what OWASP calls a build environment threat: the source looked clean, and the shipped artifact did not.

Recent npm and PyPI Incidents

The recent software supply chain attack record on npm and PyPI repeats one loop: steal a credential, publish a poisoned release, harvest more credentials. Each row below links to the official report.

IncidentWhereWay inWhat the official report says
Shai-Hulud worm, September 2025npmCompromised maintainer accounts, malicious post-install scriptsCISA says it targeted GitHub tokens and cloud API keys, then republished itself as the victim, compromising over 500 packages
Token theft via GitHub Actions, September 2025PyPIInjected workflow code that sent stored PyPI tokens to outside serversPyPI says no packages were published by the attackers; it invalidated the affected tokens
LiteLLM and telnyx, March 2026PyPIAn API token exposed through an exploited Trivy dependencyPyPI counts 119k downloads of the bad litellm releases and 2 h 32 min from upload to quarantine; LiteLLM's own security update dates its bad releases to March 24, 2026, and telnyx's notice dates its to March 27
Axios, March 31, 2026npmTwo Axios releases that pulled in a malicious dependencyCISA says the payload included a remote access trojan
Nx Console, May 2026VS Code extensionA poisoned extension update on a GitHub employee's deviceCISA says internal GitHub repositories were exfiltrated; CVE-2026-48027 is in the KEV catalog

Two details recur. Code that runs at install time, through npm post-install scripts or Python packages that execute on install, turns a download into a compromise. Stolen tokens then fuel the next round: PyPI describes malware that lifts API tokens from developer machines and uses them to compromise further packages, a cycle that keeps going for as long as it keeps working. GitHub says Shai-Hulud combined self-replication with theft of many kinds of secrets, not only npm tokens.

Why Public Registries Make Easy Targets

A software supply chain attack through a public registry pays off because of scale and habit. The numbers PyPI publishes about itself show both:

  • Volume. PyPI's review of its 2025 operations counts more than 130,000 new projects and more than 3.9 million new files, and its LiteLLM report puts new projects at roughly 700 to 800 a day. PyPI itself calls that a scaling challenge.
  • Unpinned installs. PyPI estimates that 40 to 50% of LiteLLM installs fetched the newest version on every run, and the bad litellm releases were downloaded more than 119k times during the attack window.
  • Long-lived tokens. PyPI warns that a stored API token stays useful to an attacker long after it leaks, even if nobody notices the theft.
  • Lookalike names. PyPI added automatic flagging of likely typosquats at project creation, and OWASP lists dependency confusion, where a public package borrows the name of a private one, among the core threats.

None of this makes npm or PyPI unsafe by design. PyPI says it processed more than 2,000 malware reports over the year and handled 66% of them within four hours and 92% within a day. The exposure that remains sits between a malicious upload and its removal, and that gap is when an unpinned build can pull it.

Publisher Defenses: Trusted Publishing, Provenance and 2FA

On the publishing side, the strongest answer to a software supply chain attack is to stop keeping long-lived tokens in CI at all. Trusted publishing replaces a stored API token with short-lived OpenID Connect (OIDC) credentials issued to one specific workflow. GitHub credits PyPI with pioneering the approach and lists RubyGems, crates.io, npm and NuGet among the registries that followed. npm's trusted publishing documentation supports GitHub Actions, GitLab CI/CD and CircleCI on cloud-hosted runners and requires npm CLI 11.5.1 or later with Node.js 22.14.0 or higher.

npm two-factor setup shows Security key selected, a defense against a software supply chain attack
Two-factor authentication setup · Credit: npm

Adoption is real on the Python side. PyPI reports more than 50,000 projects using trusted publishing, which accounted for more than 20% of file uploads over the past year, and 17% of uploads carried an attestation. PyPI also says more than 52% of active users have non-phishable 2FA enabled.

After Shai-Hulud, GitHub said npm publishing would narrow to three paths: local publishing with required 2FA, granular tokens with a seven-day lifetime, and trusted publishing. It also said it would deprecate classic tokens and move users from TOTP codes to FIDO-based 2FA. The token part has largely shipped, though the cap on granular tokens landed at 90 days rather than seven. GitHub's changelog of November 5, 2025 announced that new npm classic tokens can no longer be created and that granular tokens with write permissions are capped at a 90-day maximum lifetime. Its December 9, 2025 changelog says GitHub has permanently revoked all existing npm classic tokens, and that npm login now issues a two-hour session token, with 2FA enforced for publishing during those sessions. That is the same direction CISA pushes when it tells organizations to mandate phishing-resistant MFA on developer accounts, and the FIDO2 and WebAuthn comparison sets out how the security keys behind phishing-resistant MFA differ.

Provenance closes the loop for the people installing a package. According to the npm provenance documentation, a provenance statement links a package to its source repository and build instructions, is signed through Sigstore and is logged in a public transparency ledger. The same page is explicit about the limit: npm provenance does not guarantee that a package has no malicious code. PyPI's digital attestations play the same role, and PyPI says they let users spot a release that did not come through the usual workflow.

ControlnpmPyPI
Tokenless CI publishingTrusted publishing from GitHub Actions, GitLab CI/CD, CircleCITrusted Publishers from GitHub, GitLab, Google Cloud Build, ActiveState
Build attestationsProvenance via Sigstore, checked with npm audit signaturesDigital attestations from Trusted Publishing providers
Account protectionClassic tokens revoked; two-hour login sessions with 2FA for publishing; write tokens capped at 90 days2FA required to publish; email check added for TOTP logins
Malware responseRemoval of compromised packages; uploads carrying Shai-Hulud indicators blockedReport-as-malware button, quarantine, trusted reporters who can trigger it

Consumer Defenses: Lockfiles, Cooldowns and Script Controls

Teams that install packages can blunt a software supply chain attack without waiting for a registry to act. The controls below come from the CISA alerts and PyPI's incident guidance, roughly in the order a team can adopt them:

  1. Lock every dependency. OWASP recommends pinning to versions already verified as legitimate, using a lockfile such as package-lock.json. For Python, PyPI says a secure lockfile must carry package hashes, names uv lock, pip-compile with its generate-hashes option and Pipenv as tools that produce one, and notes that pip freeze does not.
  2. Add a dependency cooldown. CISA's Axios alert recommends min-release-age=7 in .npmrc so npm installs only packages published at least seven days earlier. Its Nx Console alert sets a floor of three hours. PyPI shows the same dependency cooldown for Python through uv's exclude-newer setting, with three days as its example.
  3. Stop install scripts by default. The Axios alert also recommends ignore-scripts=true in .npmrc, which keeps a post-install script from running during an install.
  4. Verify what arrives. The npm provenance documentation describes npm audit signatures, which checks registry signatures and provenance attestations for the packages in a project.
  5. Rotate secrets after any hit. CISA lists VCS tokens, CI/CD secrets, cloud keys, npm tokens and SSH keys as credentials to revoke on affected systems, plus every secret injected into a compromised ephemeral CI run.
GitHub audit log shows Dependabot alert events, a software supply chain attack defense, created and resolved
Dependabot alerts in the audit log · Credit: GitHub

A dependency cooldown has a cost. PyPI points out that it also delays urgent security fixes, so it pairs the idea with vulnerability scanning and notes that Dependabot and Renovate bypass cooldowns for security updates by default. Set the window per project and write down how to override it for an emergency patch. Fast patching is the other half of the job, covered in how businesses prevent zero-day attacks.

Hardening the CI/CD Pipeline

The CI/CD pipeline holds exactly the secrets a software supply chain attack goes after, so it needs its own controls:

  • Pin third-party actions to a full-length commit SHA. GitHub's secure use reference calls pinning to a full-length commit SHA the only way to use an action as an immutable release and offers repository and organization policies that require it. PyPI gives the same advice, favoring commit SHAs over Git tags because tags are writable.
  • Treat pull_request_target with suspicion. GitHub warns that this trigger and workflow_run, combined with a checkout of an untrusted pull request, expose the repository. PyPI recommends avoiding it in release workflows altogether.
  • Pass untrusted inputs through environment variables. PyPI recommends this to stop template injection through attacker-controlled values such as pull request titles or branch names.
  • Require a human before release. PyPI's Trusted Publishers for GitHub can require a GitHub Environment, so a maintainer approves each publish.
  • Watch the bots. After the Megalodon campaign, which injected malicious GitHub Actions workflows to harvest secrets, CISA advised auditing workflow files and contributor activity, especially commits from automated accounts.
PyPI Trusted Publisher page shows a GitHub workflow as publisher, a guard against a software supply chain attack
Trusted Publisher management · Credit: PyPI

How much of this a platform enforces for you varies, and the CI/CD pipeline comparison of GitHub Actions, GitLab CI and Jenkins sets out the platform differences. Images built by the same CI/CD pipeline need matching care once they leave it, which is where Docker and Kubernetes hardening takes over.

Where SSDF and SBOMs Fit

Frameworks do not stop a software supply chain attack on their own, but they give producers, buyers and auditors a shared vocabulary. NIST published the initial public draft of SP 800-218 Rev. 1, the Secure Software Development Framework (SSDF) Version 1.2, on December 17, 2025, describing it as a core set of high-level secure development practices that slot into any development life cycle. CISA's 2025 Minimum Elements for a Software Bill of Materials draft adds component hash, license, tool name and generation context to the fields a software bill of materials (SBOM) should carry.

An SBOM answers the first question every incident above raised: are we running the affected version? It does nothing to stop the malicious release from being published. Each control covers a different part of the chain:

ControlWhat it blocksWhat it leaves open
Lockfile with hashesSilent upgrades to a new malicious releaseA bad version already recorded in the lock
Dependency cooldownInstalls in the first hours or days after publicationMalware that stays undetected past the window
Trusted publishingReuse of stolen long-lived tokensA compromised workflow or repository; PyPI notes short-lived tokens can still be exfiltrated
Provenance and attestationsReleases built outside the expected pipelineMalicious code committed to the real source
SBOMNot knowing whether you are affectedThe compromise itself

The cheapest two rows are the place to start. PyPI measured the LiteLLM exposure window at two hours and 32 minutes from upload to quarantine. A build that installs only what its lockfile recorded, or only releases older than its cooldown, does not pick up a release that is newer than both.

Frequently Asked Questions

What is a supply chain attack in cybersecurity?

It is an attack that reaches its targets through a supplier they trust, such as a software dependency, an update channel or a hardware vendor, instead of hitting them directly. MITRE ATT&CK defines supply chain compromise as manipulating products or their delivery mechanisms before a final consumer receives them. A software supply chain attack does this through code, build systems or publishing accounts, so the malicious code arrives inside a normal install or update.

What are examples of software supply chain attacks?

The SolarWinds Compromise, discovered in mid-December 2020, and the 3CX Supply Chain Attack, active from November 2022 to March 2023, both went through a vendor's build environment, according to MITRE. Recent registry cases include the Shai-Hulud worm on npm, which CISA says compromised over 500 packages, the poisoned LiteLLM releases on PyPI, and two Axios releases on npm that CISA says pulled in a malicious dependency carrying a remote access trojan.

Does npm audit protect against supply chain attacks?

Only partly, because a vulnerability audit flags dependencies with published advisories, which a freshly poisoned release may not have yet. In the LiteLLM case, PyPI measured two hours and 32 minutes from upload to quarantine, the period the bad releases were live. Pair audits with a lockfile, a dependency cooldown and npm audit signatures, which checks registry signatures and provenance attestations.

Is npm provenance proof that a package is safe?

No, provenance proves where and how a package was built, not that its code is benign. The npm documentation says established provenance does not guarantee a package has no malicious code. It gives developers a verifiable link to the source and build instructions so they can decide whether to trust it. PyPI says its attestations let users spot a release that was not published through the usual workflow.

How long should a dependency cooldown be?

Pick the longest window your update policy can live with: a longer cooldown gives reporters and registries more time to pull a malicious release, at the cost of slower updates. CISA's Axios alert recommends seven days for npm, and its Nx Console alert says to wait at least three hours before pulling a new package. PyPI uses three days as its example. Whatever the window, keep a documented override so security patches are not held back.

What should a team do first when a dependency it uses is reported compromised?

Find out whether the bad version is installed anywhere, then rotate every secret it could have touched. CISA's guidance after the Shai-Hulud worm starts with checking lockfiles, including nested dependencies, and searching artifact caches. It then calls for pinning to known safe releases, rotating developer credentials, and watching outbound traffic for connections to the attacker's infrastructure.

Share this guide

Daniel Brandt

Daniel Brandt covers threats, malware, and vulnerability disclosure for techshooked, from active exploit campaigns to the patch cycles that follow. His standard is operational: name the affected versions, separate a proof of concept from in-the-wild exploitation, and tell readers which fix to apply first.