Back

Software Supply Chain Failures - Overview

What Are Software Supply Chain Failures?

Software Supply Chain Failures occur when an attacker compromises any of the people, code, tools, or infrastructure that a piece of software depends on before it reaches production—so that malicious or vulnerable code is delivered through channels the victim already trusts. The application team may write flawless code and still ship a backdoor, because the compromise lives in a dependency, a build server, a signing key, a container base image, or a script loaded from a third-party CDN.

This is the defining shift of the 2025 edition. The 2021 Top 10 addressed one slice of the problem under A06:2021 – Vulnerable and Outdated Components, which focused on running dependencies with known vulnerabilities. The 2025 category subsumes and greatly expands that scope: it is no longer only "are your libraries patched?" but "can you trust every link in the chain that produced and delivered your software?"

The Software Supply Chain

SOURCE  -->  DEPENDENCIES  -->  BUILD  -->  PACKAGE  -->  DISTRIBUTE  -->  DEPLOY  -->  RUN
  |             |               |            |             |               |          |
 SCM         registries       CI/CD       artifact       registry       runtime    browser /
 commits     (npm, PyPI,      runners,    signing        / CDN /         hosts /    third-party
 & PRs       Maven, etc.)    build steps  & provenance   mirrors         clusters   scripts

A trust failure at ANY node ships attacker-controlled code to everyone downstream.

Concretely, a modern application is assembled far more than it is written. A typical service pulls in hundreds to thousands of packages once transitive (nested) dependencies are resolved, builds them on shared automation, packages them into container images layered on other people's base images, and—on the web tier—loads analytics, tag managers, and payment widgets directly from third-party domains at runtime. Each of those is a trust relationship an attacker can target.

The Failure Classes

Why Does This Matter?

Supply chain compromise is uniquely valuable to attackers because it is a force multiplier: one successful intrusion at an upstream provider is inherited automatically by everyone who trusts that provider. It also bypasses most traditional defenses—the malicious code arrives signed, from an expected source, through the normal update mechanism, and is often installed by automation with elevated privileges.

Business Impact

Technical Impact

Technical Context

Where Trust Can Break in the Chain

StageWhat you trustHow it failsAttacker payoff
Source (SCM)Commits and pull requestsStolen developer creds, malicious PR, tampered branchCode enters "legitimately"
DependenciesPublic registriesTyposquat, dependency confusion, hijacked packageMalicious code auto-installed
Build (CI/CD)Runners and build stepsPoisoned runner, leaked secrets, malicious stepInject after review, before signing
Package / signSigning keys, provenanceStolen key, no provenance, unsigned artifactMalicious artifact looks authentic
DistributeRegistries, CDNs, mirrorsRegistry takeover, CDN/script compromiseSwap or skim at delivery
Container baseBase imagesPoisoned or outdated base layerEvery child image inherits it
Runtime (web)Third-party scriptsMagecart-style injectionLive data theft from users

Why Transitive Dependencies Amplify the Risk

Your direct dependencies are only the top of an iceberg. Each one pulls in its own dependencies, which pull in theirs, often several levels deep. You may vet the ten packages you chose and still install a thousand you never evaluated.

your-app
└── trusted-framework        (you reviewed this)
    └── helper-lib            (you did not)
        └── tiny-utility      (nobody reviewed this)
            └── COMPROMISED    <-- one hijacked leaf reaches your production

A compromise at a deep, obscure, widely-reused leaf package can therefore affect an enormous number of applications that have no idea they depend on it. This is exactly why an inventory (SBOM) matters: you cannot defend, or even assess, what you do not know you are shipping.

Dependency Confusion, Concretely

Many organizations use internal package names (for example @acme/auth-client or acme-internal-utils) that exist only in a private registry. If the build tool is configured to consult the public registry as well, an attacker can publish a package with the same name and a higher version number to the public registry. Default "highest version wins" resolution then pulls the attacker's public package into internal builds—no typo or human error required.

Real-World Impact

The incidents below are referenced as illustrative classes of failure. Specific figures vary by source and are deliberately omitted; the durable lesson is the mechanism, not a precise statistic.

Class 1: Build-System Compromise (SolarWinds-style)

Mechanism: Attackers gained access to a vendor's build pipeline and inserted malicious code into the software during the build, so the tampered update was compiled, signed with the vendor's legitimate certificate, and distributed through the normal update channel. Customers who installed a properly signed update from a trusted vendor received a backdoor.

Lesson: Code review and code signing are insufficient on their own if the build environment itself is untrusted. This is the canonical argument for build integrity, provenance (SLSA), and hardened, ephemeral runners.

Class 2: Compromised CI Uploader / Leaked Secrets (Codecov-style)

Mechanism: A widely-used CI helper script was modified so that, when it ran inside customers' pipelines, it exfiltrated environment variables—which routinely contain cloud keys, registry tokens, and other secrets—to an attacker-controlled endpoint.

Lesson: Anything executed in CI can read your pipeline secrets. Least-privilege, short-lived credentials and verifying the integrity of third-party CI tooling are essential.

Class 3: Maintainer Account Hijack (ua-parser-js / coa-style)

Mechanism: An attacker took over a legitimate maintainer's registry account (through credential theft or phishing) and published new, malicious versions of very popular packages. Auto-updating consumers pulled malware that stole credentials and installed miners.

Lesson: Popularity is not safety. Pin versions, require publisher 2FA, and do not blindly auto-update to the newest release.

Class 4: Malicious Insider / Protestware (event-stream-style)

Mechanism: A widely-depended-upon package was handed off to a new "maintainer" who added a malicious transitive dependency targeting a specific downstream application. The payload was obfuscated and narrowly targeted, so it evaded casual inspection.

Lesson: Maintainer turnover and social-engineering of trust are real attack vectors. Review dependency changes, not just initial selection.

Class 5: Long-Game Backdoor via Social Engineering (xz-utils-style)

Mechanism: An attacker spent a long period building trust as a helpful contributor to a low-profile but critical open-source project, eventually gaining maintainer rights and introducing a carefully hidden backdoor into release artifacts (not obvious in the source repository).

Lesson: Trust in open source is a process, not a one-time check. Reproducible builds and scrutiny of release artifacts (not just source) are defenses against build-time-only payloads.

Class 6: Web-Skimming via Third-Party Scripts (Magecart-style)

Mechanism: Attackers compromised a third-party script (analytics, chat, or a shared library on a CDN) that many e-commerce sites loaded directly into their checkout pages. The injected code silently copied payment-card fields as customers typed them and sent the data to an attacker's server.

Lesson: Any script you load from another origin runs with full access to your page. Subresource Integrity (SRI), a strict Content-Security-Policy, and minimizing third-party scripts are the front-line defenses.

Prevalence and Statistics

Supply chain attacks have moved from rare, headline events to a routine, industrialized category. Automated campaigns publish malicious packages to public registries continuously, and dependency-confusion and typosquatting are now standard techniques in commodity tooling.

Rather than cite precise counts (which differ widely by source and year), the defensible picture is:

Note: treat any single percentage or breach count as illustrative. The durable takeaway is that third-party and build-time code dominate your risk, and that trust in the chain must be verified, not assumed.

Common Misunderstandings

Myth 1: "We passed code review, so our software is safe."

Reality: Review covers the source you can see. Build-system compromise, hijacked dependencies, and malicious release artifacts inject code after review or outside the repository entirely.

Myth 2: "The package is popular and has millions of downloads, so it's trustworthy."

Reality: Popularity makes a package a better target. Several high-impact incidents hijacked packages precisely because they were widely used and auto-updated.

Myth 3: "A signature means the artifact is safe."

Reality: A signature proves who signed it, not that the signer's build was clean. If the signing key or build system is compromised, malware is signed too. You need provenance (what was built, from what source, by which pipeline), not just a signature.

Myth 4: "Pinning versions is enough."

Reality: Pinning defeats surprise auto-updates, but a pinned version can still be a hijacked release, and a mutable tag (like latest) or an unpinned CI action can still change under you. Pin to immutable identifiers (hashes/digests) and verify them.

Myth 5: "This is just the old 'outdated components' problem renamed."

Reality: Outdated components (A06:2021) are one subset. The 2025 category adds malicious/hostile packages, build and CI/CD compromise, provenance, container base images, and runtime third-party scripts.

Myth 6: "Third-party scripts on our website are the vendor's responsibility."

Reality: A script you embed runs in your users' browsers with access to your page. If the vendor is compromised, your customers' data is stolen from your site. SRI and CSP put that risk back under your control.

Relationship to A06:2021 – Vulnerable and Outdated Components

A06:2021 asked one question: are you running components with known vulnerabilities and keeping them patched? That question remains valid and is fully contained within the 2025 category. What changed is the threat model: attackers no longer wait for you to run an old, vulnerable version—they actively poison the supply itself.

AspectA06:2021 (Vulnerable & Outdated Components)A03:2025 (Software Supply Chain Failures)
Core questionIs my dependency patched?Can I trust the whole chain that produced and delivered my software?
ThreatPassive: known CVE in an old versionActive: malicious packages, hijacks, build/CI compromise
ScopeRunning dependenciesSource, dependencies, build, signing, distribution, base images, runtime scripts
Key defensePatch cadence, SCASCA + SBOM + provenance/signing + hardened CI/CD + registry controls + SRI

Key Takeaways

  1. Most of your code is someone else's. Your risk lives largely in dependencies, build tooling, and third-party scripts—not just your source.
  2. Trust must be verified, not assumed. Signatures prove identity; provenance proves origin and build integrity. Prefer both.
  3. The build system is production. A compromised CI/CD pipeline injects code after review and signs it as authentic—harden it accordingly.
  4. Know what you ship. An SBOM turns "we think we're not affected" into a searchable, defensible answer during the next incident.
  5. Pin to immutable identifiers. Hashes and digests, private-registry precedence, and scoped names defeat confusion, typosquatting, and silent mutation.
  6. The browser tier counts. SRI and CSP contain the runtime third-party-script risk that traditional dependency scanning never sees.

How to Identify if You're Exposed

Ask these questions about your software and its pipeline:

Several "no" or "not sure" answers indicate meaningful supply chain exposure today.

Next Steps