101% more reported CVEs per day in 2026 than last year.

Red team vs blue team

Supply chain attacks: how attackers get in, and how to stop them

Attackers rarely target your company. They target the package, the Action or the build tool that companies everywhere depend on, then try the exploit on all of them at once. They don't need your dependency list. You do.

What is a software supply chain attack?

A software supply chain attack compromises something a product is built from, such as an open source package, a CI/CD component or the build system, instead of attacking the product directly. Modern software is mostly other people's code: most of it comes from open source packages, and most of those are transitive dependencies that nobody on the team chose. Compromise one widely used component, and you reach every organization that builds on it.

That changes how attackers pick targets. They don't research one company's dependencies. They pick a package or tool with a large footprint, then exploit it everywhere and see what answers.

Types of software supply chain attacks

Exploiting a vulnerable dependency

A flaw in a popular open source package is disclosed, and attackers exploit it in every product that ships the vulnerable version, usually as a transitive dependency nobody chose directly.

Malicious package releases

An attacker takes over a maintainer account, or a worm steals publishing tokens, and releases a poisoned version of a trusted package. It runs the moment a build installs it, as with the Shai-Hulud npm worm.

Backdoored upstream projects

A contributor earns trust in an open source project over time, then slips malicious code into a release that downstream distributions and products pick up, as with the xz utils backdoor.

Typosquatting and dependency confusion

Packages with names close to popular ones catch typos. Dependency confusion goes further: a public package with the same name as a company's internal one gets installed in its place.

Compromised CI/CD components

A GitHub Action or other build tool is hijacked, and every pipeline that uses it runs the attacker's code with its secrets in reach, as with tj-actions and Codecov.

Build and artifact tampering

The build itself is altered, or the artifact is swapped between the build and deployment, so a clean source tree still produces a compromised release, as with SolarWinds.

Supply chain attack examples

SolarWinds is the best-known supply chain attack: malicious code inserted at the build and shipped to customers as a normal update. The most recent attacks go after package registries and CI pipelines instead, where one compromised package or Action reaches every build that uses it. Newest first:

npm worm · since September 2025

Shai-Hulud

A self-spreading worm that runs when an infected npm package is installed, steals npm, GitHub and cloud tokens, and publishes infected versions of the victim's other packages. Most infections ran in CI.

How to check your builds →

CVE-2025-30066 · March 2025

tj-actions/changed-files

CISA reported that every version of this popular GitHub Action was compromised for three days, with secrets exposed in workflow logs. Workflows that referenced it by tag ran the attacker's code.

CVE-2024-3094 · March 2024

xz utils backdoor

Andres Freund found a backdoor in xz versions 5.6.0 and 5.6.1 after noticing that SSH logins were using too much CPU. It had been introduced into the upstream project itself.

CVE-2021-44228 · December 2021

Log4Shell

A flaw in Apache Log4j 2 let an attacker who controlled a logged message run arbitrary code, rated CVSS 10.0. The hard part for most teams was finding which applications contained log4j-core, usually as a dependency of a dependency.

January to April 2021

Codecov Bash Uploader

Attackers altered the Bash Uploader script that teams ran in their CI pipelines, so that it sent the CI environment, including credentials, tokens and keys, to a server outside Codecov's infrastructure. It ran unnoticed from January 31 until a customer reported it on April 1.

SUNBURST · December 2020

SolarWinds Orion

Attackers had long-standing, covert access to the build process for SolarWinds Orion and inserted malicious code into Orion releases 2019.4 through 2020.2.1 HF1, which customers installed as normal updates. CISA issued an emergency directive in response.

Red team vs blue team

How supply chain attacks work, stage by stage

Each stage in the attacker's words, and the defense that answers it.

Stage 1 of 3

Recon

No need to know the target. Pick the package, and the targets pick themselves.

Red team

Bet on the dependencies everyone has

You don't need their lockfile. Popular packages sit deep in the transitive tree of almost everything, and most teams can't say which ones they ship. Public clues narrow it down: versions in JavaScript bundles and HTTP headers, public repositories and container images. And whatever their build fetches outside the lockfile, such as the binary a postinstall script downloads or the layers under their base image, their scanner never saw, so nobody is patching it.

Blue team

Know every dependency each build pulled in

CRACI sees the traffic coming into every build and records every package and file it pulls in, including the hidden dependencies that lockfile-based tools miss, at every depth of the transitive tree. Your SBOM comes from the build that shipped, so you have the list an attacker never needed, before anyone goes looking.

Build-time SBOMs →

Red team

Move the minute a new CVE drops

A new advisory tells you exactly which versions are vulnerable. Build the exploit, scan for anything that answers, and let the scan tell you who they are. You start the same day, while their team is still asking "are we affected?" in a Slack thread.

Blue team

"Are we affected?" answered from the build record

CRACI re-evaluates monitored SBOMs continuously against new vulnerability data. Build history shows which builds contained the vulnerable dependency, direct or transitive, so you know where it shipped and for how long.

Are we affected? →

Stage 2 of 3

Get in

Exploit the flaw before it's patched, or skip the flaw and ride their pipeline.

Red team

Generate the attack the day it's disclosed

AI turns an advisory and a patch diff into a working attack before their security team has triaged the ticket. Disclosure is your starting gun. Their sprint planning is next week.

Blue team

Stop shipping the vulnerable version

Policy gates can block any build that contains a specific CVE, so the vulnerable version stops shipping the moment you decide, however deep in the tree it sits.

CVE remediation →

Red team

Rewrite one tag, run in a thousand pipelines

Workflows trust tags like @v4, and tags can be moved. Compromise one popular GitHub Action and every workflow that uses it runs your code, with their secrets in reach.

Blue team

Know exactly which Action each build ran

CRACI records the GitHub Actions a workflow runs in the build's SBOM, pinned to the commit that actually ran. When an Action is compromised, you can see which builds ran the bad code instead of guessing from a tag.

CI/CD security checklist →

Stage 3 of 3

Get out

Take the secrets and stay around for more.

Red team

Phone home from their CI

A malicious package release runs its install script inside their build, where the tokens and cloud credentials live. CI runners can usually reach the whole internet, so the secrets leave for your server before anyone knows the package is bad.

Blue team

A build can only reach what it needs

A default-deny egress policy lets a build reach its package sources and publish targets, and blocks everything else. Malware sending your secrets to an attacker's host is blocked, even as patient zero of an attack nobody has seen before, and you get an alert on the policy violation.

Egress policies →

Red team

Stay on the runner for the next job

Long-lived self-hosted runners are a gift: plant something in the workspace or the tool cache and wait for the next job, and the next set of secrets, to come to you.

Blue team

One isolated virtual machine per job

Every CRACI job runs in its own isolated virtual machine, so nothing one job leaves behind is waiting for the next. There is no fleet of runners for you to patch and harden either.

Managed vs self-hosted runners →

After disclosure

The race starts when the advisory goes public

The attacker doesn't need to know you run the dependency. They try the exploit everywhere and see what answers. Your team needs to know where that dependency shipped. The difference is whether you have to go looking, and there are more races to run every year: see how many CVEs are published each day.

Red team

  1. Advisory published
  2. Exploit generated
  3. Scan for anything running a vulnerable version
  4. Inside every match, yours included

Blue team, without a build record

  1. Advisory published
  2. "Are we affected?"
  3. Grep repos, lockfiles and images
  4. Find the transitive copy nobody listed
  5. Work out which releases shipped it
  6. Patch

Blue team, with CRACI

  1. Advisory published
  2. Monitored SBOMs re-evaluated
  3. Build history shows the builds and the period
  4. Policy gate blocks new builds with the CVE

How to prevent software supply chain attacks

No single control stops every supply chain attack. Layer these, and each stage above gets harder. For the pipeline side in detail, see the CI/CD pipeline security checklist.

  1. Know what every build ships. Keep an SBOM for each build, including transitive dependencies and anything fetched outside the lockfile. A scan of the repository is not a record of the release.
  2. Watch what shipped, not just the default branch. Re-check released builds against new advisories, and keep the build history that tells you since when you were exposed.
  3. Pin dependencies and Actions. Use lockfiles, and pin GitHub Actions to a full-length commit SHA. GitHub calls that the only way to use an action as an immutable release.
  4. Stop vulnerable versions at the build. Gate builds on the vulnerabilities you have decided must not ship, so a fix cannot quietly regress.
  5. Default-deny egress in CI. Let builds reach only their package sources and publish targets, so malicious code cannot send secrets out, even in an attack nobody has seen before.
  6. Isolate jobs and limit secrets. Run each job on a fresh, isolated machine, and give each job only the tokens and permissions it needs.
  7. Verify artifacts before you deploy. Sign provenance at build time and check that what runs in production is exactly what was built.
  8. Rotate secrets after an incident. If a compromised package or Action ran in your pipeline, treat every secret it could reach as exposed. That was CISA's advice after the tj-actions compromise.

They don't need the list. You do.

Attackers watch every advisory and try the exploit on everyone the day a vulnerability is disclosed. They never needed your dependency list. You do. CRACI gives your team that list, taken from the build itself, and closes the doors attackers count on: open egress and shared runners.

Supply chain attacks: frequently asked questions

What is a software supply chain attack?

An attack on the code, tools or services a product is built from, such as an open source package, a CI/CD component or the build system, rather than on the product itself. One compromise reaches every organization that uses the affected component.

What are examples of software supply chain attacks?

The Shai-Hulud worm (since 2025) spread through infected npm packages and stole CI secrets. The tj-actions/changed-files compromise (CVE-2025-30066) hijacked a popular GitHub Action. The xz utils backdoor (CVE-2024-3094) was slipped into an upstream compression library. Log4Shell (CVE-2021-44228) exploited a flaw in a widely used Java logging library. Codecov's Bash Uploader (2021) was altered to send CI credentials to an outside server, and SolarWinds Orion (2020) shipped malicious code inserted at the build.

What is the most famous supply chain attack?

SolarWinds. In 2020, attackers with covert access to the build process for SolarWinds Orion inserted malicious code into its releases, and customers installed it as a normal update. It showed that a clean source tree is not enough: the build itself has to be trustworthy and verifiable.

Do attackers know which dependencies my company uses?

Usually not, and they don't need to. Most attacks target a package rather than a company: once an advisory is out, attackers try the exploit against anything that might run a vulnerable version and see what answers. Public clues, such as versions in JavaScript bundles or open-source repositories, help them aim. The asymmetry is that you do need the list: to know whether you are affected, you have to know what every build shipped, including what it fetched outside the lockfile.

How do you prevent software supply chain attacks?

No single control stops them all. Keep an SBOM of what every build ships and monitor it against new advisories, pin dependencies and GitHub Actions, block vulnerable versions at the build, restrict what CI jobs can connect to, isolate jobs and limit their secrets, and verify that deployed artifacts are the ones you built.

How can I protect against npm supply chain attacks?

Commit a lockfile and install from it in CI, and disable install scripts where a build does not need them (npm's --ignore-scripts). Keep a record of which package versions every build actually installed, so you can check quickly when a new wave such as Shai-Hulud is announced. Restrict what CI jobs can connect to, so a malicious install script cannot send your tokens out, and rotate any token an infected version could have reached.

What does red team vs blue team mean here?

In security exercises the red team plays the attacker and the blue team defends. This page uses the same split: each stage of a supply chain attack in the attacker's words, answered by the defense.

Does CRACI detect malicious packages?

Known ones, yes. A malicious release that has a published CVE, such as the xz backdoor, is flagged like any other vulnerability, and a policy gate can block builds that contain it. CRACI does not analyze package behavior or score reputation, so a brand-new malicious package goes unflagged until an advisory exists. That is what the egress policy is for: with default deny, the build can reach only the hosts it needs, so the package cannot send your secrets out, even in an attack nobody has seen before.