Software Supply Chain Attacks
Real-world supply chain attack methods — dependency confusion, typosquatting, compromised maintainers, and build pipeline poisoning. How each works and how to prevent them.
What makes supply chain attacks different
A supply chain attack does not target your code. It targets the code you trust.
Every modern application pulls in hundreds of third-party dependencies. The Synopsys 2024 OSSRA report found 96% of commercial codebases contain open-source components, with an average of 500+ dependencies per application. Each of those dependencies is a potential entry point for an attacker.
What makes these attacks effective is their reach. Compromising one popular package can give an attacker access to every application that depends on it. The ua-parser-js incident in 2021 affected a single npm package, but that package had 8 million weekly downloads. The blast radius was enormous.
Traditional security focuses on vulnerabilities, bugs that can be exploited. Supply chain attacks are different because the code is intentionally malicious. There is no CVE at the time of attack. There is no patch to apply. The “fix” is to remove or replace the compromised component entirely.
Your defense strategy needs two layers: vulnerability scanning for known issues, and behavioral monitoring for unknown threats.
Dependency confusion attacks
Dependency confusion exploits how package managers resolve names when both private and public registries exist.
How it works
Most companies have internal packages hosted on a private registry (Artifactory, Nexus, GitHub Packages). These packages often have names like company-auth or internal-utils. When a developer runs npm install or pip install, the package manager may check both the private registry and the public registry (npmjs.com, PyPI).
The attack is straightforward: the attacker publishes a package on the public registry with the same name as an internal package, but with a higher version number. Many package managers default to installing the highest available version regardless of which registry it comes from. The attacker’s public package wins.
Real-world examples
Alex Birsan demonstrated this technique in 2021 against Apple, Microsoft, and PayPal, earning over $130,000 in bug bounties. He found internal package names referenced in public JavaScript files and published identically named packages to npm with pre-install scripts that phoned home. All three companies installed his packages in their internal systems.
In 2023, researchers at Orca Security found dependency confusion vulnerabilities affecting major cloud providers’ internal tooling. The pattern keeps repeating because the default behavior of most package managers still favors public registries.
Prevention
Namespace your internal packages. Use npm scopes (@company/package-name), PyPI namespaces, or NuGet prefixes so there is no collision with public names.
Reserve your internal names on public registries. Even if you never publish publicly, registering the name prevents an attacker from doing so.
Configure registry priority. Set your package manager to check the private registry first and block fallback to public registries for internal package names. Both Artifactory and Nexus support this through virtual repositories.
Use lockfiles. Lockfiles pin exact versions and registry sources, which prevents the package manager from silently switching to a different source.
Typosquatting and malicious packages
Typosquatting relies on developer mistakes during package installation. The attacker publishes a package with a name close enough to a popular package that a typo will land on it.
Attack patterns
The simplest form is character swapping: lodahs instead of lodash, reqeusts instead of requests. More sophisticated variants use hyphen confusion (python-nmap vs python_nmap), scope impersonation (@angular-devkit vs angular-devkit), or name permutations (cross-env vs crossenv).
The crossenv npm package in 2017 was one of the first widely reported cases. It mimicked the legitimate cross-env package and stole environment variables, including npm tokens, from developer machines.
PyPI has been hit repeatedly. In 2023, researchers from Phylum identified over 400 typosquatted packages on PyPI in a single campaign, all targeting data exfiltration.
Why it works
Developers install packages quickly and often. A pip install reqeusts in a terminal does not trigger any warning. The malicious package installs successfully, often including the legitimate package’s functionality so the developer never notices the difference. The malicious payload runs alongside the real code.
Detection
Traditional SCA tools check dependencies against CVE databases, so they catch typosquats only after someone reports them. By then, the damage may already be done.
Socket takes a different approach. It analyzes what packages actually do: network connections, filesystem access, environment variable reads, and obfuscated code. A legitimate cross-env package sets environment variables. A malicious crossenv exfiltrates them. Socket flags the behavioral difference regardless of whether a CVE exists.
npm and PyPI have both added automated detection, but the volume of new packages published daily (npm sees 2,000+ per day) means some malicious packages slip through.
Compromised maintainer accounts
When an attacker gains control of a legitimate maintainer’s account, they can push malicious code through the normal update channel. Users receive it as a routine version bump.
How it works
The attacker gains access to a maintainer’s npm, PyPI, or RubyGems account through credential stuffing, phishing, or social engineering. They publish a new version of the legitimate package with malicious code added. Developers who have configured automated dependency updates receive the infected version automatically.
Notable incidents
ua-parser-js (October 2021). An attacker hijacked the npm account of the ua-parser-js maintainer and published versions 0.7.29, 0.8.0, and 1.0.0 with cryptomining and credential-stealing malware. The package had 8 million weekly downloads and was a dependency of Facebook’s fbjs.
event-stream (November 2018). A new contributor offered to maintain the popular event-stream npm package after the original author stepped back. After gaining publish access, the new maintainer added a dependency (flatmap-stream) containing encrypted malicious code targeting the Copay Bitcoin wallet. The attack was specifically designed to steal cryptocurrency from a single application while hiding in a general-purpose library.
XZ Utils (March 2024). A contributor named “Jia Tan” spent two years building trust in the XZ compression project. Through patient social engineering (including sock puppet accounts that pressured the original maintainer), they eventually gained commit access and inserted a backdoor targeting the SSH authentication process on Linux. This was caught by accident when a Microsoft engineer noticed unusual latency during SSH connections.
Why this is hard to prevent
You cannot fully audit every update to every dependency. The XZ Utils attack showed that even careful open-source communities can be compromised by a determined, patient attacker. The malicious code was hidden in test files and build scripts, not in the main source.
What you can do: pin dependency versions and review changelogs before upgrading. Use lockfiles to prevent unexpected updates. Enable multi-factor authentication on your own package registry accounts. Monitor for unexpected behavioral changes in updated dependencies using tools like Socket.
Build pipeline and CI/CD poisoning
Build pipeline attacks target the systems that compile, test, and deploy your code. Instead of compromising a library, the attacker compromises the process that turns source code into a running application.
Attack vectors
Compromised CI/CD actions or plugins. GitHub Actions, GitLab CI templates, and Jenkins plugins are themselves dependencies. A compromised GitHub Action can read secrets, modify build artifacts, or inject code into your deployment. In 2022, researchers found that many popular GitHub Actions were pulling code from mutable tags that could be silently modified.
Build system infiltration. The SolarWinds attack (2020) was a build pipeline compromise. Attackers modified the Orion software build process so that compiled binaries included a backdoor. The source code itself was clean. The malicious code was injected during compilation, so it was invisible in source code review. Around 18,000 organizations installed the compromised update.
Codecov bash uploader (2021). Attackers modified Codecov’s bash uploader script hosted on their servers. CI pipelines that downloaded and executed this script during builds had their environment variables (secrets, tokens, API keys) exfiltrated. The script was not a package you install; it was a URL your CI pipeline fetched at build time.
Prevention
Pin GitHub Actions to commit SHAs, not tags. Tags are mutable. A tag like actions/checkout@v3 can be pointed to a different commit without warning. Pinning to a SHA (actions/checkout@abc123...) ensures you run the exact code you reviewed.
Audit your CI/CD secrets. Limit which jobs can access which secrets. Use short-lived credentials where possible. Do not expose production secrets to pull request builds from forks.
Verify build integrity. SLSA (Supply chain Levels for Software Artifacts) is a framework by Google for build provenance. SLSA Level 3 requires that build artifacts include a verifiable provenance statement proving which source code and build process produced them.
Do not fetch scripts from URLs at build time. If your CI/CD pipeline downloads and executes a remote script, you have no guarantee that script has not changed since you last reviewed it.
Prevention: tools and practices at each layer
Supply chain defense is not a single tool. It is a set of practices applied at different layers.
Dependency management. Use lockfiles everywhere. Pin versions. Review changelogs before upgrading. Remove unused dependencies. Every dependency adds attack surface.
Registry configuration. Scope private packages. Set registry priority rules. Use a proxy registry (Artifactory, Nexus) to cache and audit packages before they reach developers.
Behavioral analysis. Run tools like Socket that analyze what packages do, not just which CVEs they have. This catches typosquats, malicious packages, and compromised versions that traditional SCA misses.
Vulnerability scanning. Run SCA tools in your CI/CD pipeline to catch known vulnerabilities. Tools like Snyk Open Source, Mend SCA, and OWASP Dependency-Check cover this layer.
SBOM generation. Generate a Software Bill of Materials on every build so you can quickly determine exposure when the next incident drops.
Build integrity. Pin CI/CD actions to SHAs. Restrict secret access. Adopt SLSA for build provenance. Verify signatures on artifacts.
Monitoring. Subscribe to security advisories for your critical dependencies. Tools like Dependabot and Renovate automate alerting and update PRs when new vulnerabilities are disclosed.
SCA tools and their role in supply chain defense
SCA tools handle the largest category of supply chain risk, known vulnerabilities, but they cover only one part of the problem.
What SCA catches
Traditional SCA tools match your dependency list against databases of known vulnerabilities (NVD, OSV, vendor-curated databases). They tell you that [email protected] has a prototype pollution vulnerability and that upgrading to 4.17.21 fixes it. This handles the large volume of known, documented vulnerabilities in open-source software.
What SCA misses
SCA does not detect zero-day malicious packages, typosquats that have not been reported yet, or compromised versions published through hijacked accounts. These attacks have no CVE at the time of compromise.
Layered approach
Pair traditional SCA with behavioral analysis. The combination gives you:
| Layer | Tools | Catches |
|---|---|---|
| Known vulnerabilities | Snyk, Mend SCA, Grype, OWASP Dependency-Check | CVEs in direct and transitive dependencies |
| Behavioral analysis | Socket | Malicious packages, typosquats, data exfiltration |
| Reachability | Endor Labs | Filters out CVEs in code paths your app never calls |
| Dependency updates | Dependabot, Renovate | Keeps dependencies current, reduces window of exposure |
| SBOM inventory | Anchore, Syft, Trivy | Tracks what is in every build for incident response |
No single tool covers every attack vector. Your supply chain defense is only as strong as the weakest layer you have not addressed.
FAQ
This guide is part of our Software Supply Chain Security resource hub.
Frequently Asked Questions
What is a software supply chain attack?
What are examples of supply chain attacks?
How to prevent dependency confusion?
What is typosquatting in software?
Can SCA tools detect supply chain attacks?

Suphi Cankurt is an application security enthusiast based in Helsinki, Finland. He reviews and compares 129 AppSec tools across 10 categories on AppSec Santa. Learn more.
Comments
Powered by Giscus — comments are stored in GitHub Discussions.