TL;DR: Software supply chain attacks compromise the tools and dependencies developers trust implicitly. Dependency confusion tricks package managers into pulling malicious public packages over legitimate internal ones. Typosquatting banks on a single character mistake in an install command. Compromised maintainer accounts turn trusted packages into attack vectors overnight. And build pipeline poisoning - as demonstrated by SolarWinds - signs malicious code with legitimate certificates. The defenses are layered: lockfile integrity, private registry scoping, SBOM generation, build provenance verification, and regular dependency auditing.
Supply Chain Attack Vectors: A Comparison
| Attack Vector | Mechanism | Detection Difficulty | Real-World Example |
|---|---|---|---|
| Dependency Confusion | Public package with same name as internal, higher version | Medium | Alex Birsan research (2021) - Apple, Microsoft, PayPal |
| Typosquatting | Package name one character off from popular package | Low (if detected early) | crossenv (npm), python3-dateutil (PyPI) |
| Compromised Maintainer | Hijacked account publishes malicious update | High | event-stream (npm, 2018), ua-parser-js (2021) |
| Build Pipeline Poisoning | Malicious code injected during CI/CD build process | Very High | SolarWinds Orion (2020), Codecov (2021) |
| Malicious Pull Request | Backdoor introduced via seemingly legitimate contribution | Medium | xz Utils backdoor (2024), PHP self-hosted git (2021) |
| Registry Compromise | Attack on the package registry infrastructure itself | Very High | Codecov bash uploader (2021) |
Dependency Confusion: The Most Accessible Attack
Dependency confusion exploits a design assumption in package managers: when multiple sources are configured, the manager resolves the highest version number across all sources. Organizations that use private packages - a nearly universal practice at any scale - are vulnerable if those package names do not exist on the public registry.
The attack sequence is straightforward. An attacker identifies internal package names through leaked lockfiles, error messages in public repositories, JavaScript source maps, or documentation. They register those names on the public registry (npm, PyPI, RubyGems) with a version number higher than the internal one. When a developer runs npm install or pip install, the package manager fetches the attacker's package from the public registry instead of the private one.
The malicious package typically executes code during installation - preinstall scripts in npm, setup.py in Python - exfiltrating environment variables, SSH keys, cloud credentials, and other secrets from the build environment. Because this executes during installation, not at runtime, it affects CI/CD pipelines where secrets are most concentrated.
Defending Against Dependency Confusion
The primary defense is registry scoping: configure your package manager to fetch internal packages exclusively from your private registry and never fall back to the public source. In npm, use scoped packages (@yourorg/package-name) that are tied to your organization's namespace. In Python, use the --index-url flag (not --extra-index-url) to specify a single source. Reserve your internal package names on public registries as an additional layer of defense.
Typosquatting: Banking on Human Error
Typosquatting requires no technical sophistication - just patience and a plausible package name. The attacker publishes a package with a name similar to a popular one: requets instead of requests, lodsah instead of lodash, coloures instead of colors. Developers who mistype an install command pull the malicious package instead.
The scale of the problem is significant. Package registries host millions of packages, and name reservation is trivial. Automated scanning catches some typosquatting attempts, but attackers adapt by using names that are plausible variations rather than obvious misspellings - adding hyphens, using alternative spellings, or appending common suffixes like -utils or -js.
Remediation: Use lockfiles religiously and review dependency changes in pull requests. Tools like Socket, npm audit signatures, and Phylum scan for known typosquat patterns. Pin dependencies to exact versions and use hash verification where supported.
Compromised Maintainer Accounts
The event-stream incident in 2018 demonstrated how a single compromised maintainer account can weaponize a trusted package against its entire user base. An attacker gained commit access to the popular event-stream npm package - which had millions of weekly downloads - by offering to maintain it when the original author lost interest. Over several months, the new maintainer introduced a dependency that contained encrypted malicious code targeting a specific Bitcoin wallet application.
This attack pattern is particularly insidious because it abuses the trust model of open source. Code review catches obvious backdoors, but a patient attacker who builds a contribution history, earns maintainer trust, and introduces malicious code gradually across multiple commits is extraordinarily difficult to detect. The xz Utils backdoor discovered in 2024 followed this exact pattern over a two-year period.
What organizations should do: Monitor dependency update diffs - not just version bumps but actual code changes. Use tools that flag maintainer changes, new transitive dependencies, and obfuscated code in package updates. Evaluate the health and governance of critical dependencies: single-maintainer packages with no review process are higher risk than projects with multiple maintainers and mandatory code review.
Build Pipeline Poisoning
The SolarWinds attack remains the definitive example of build pipeline compromise. Attackers gained access to the SolarWinds build system and injected malicious code into the Orion software build process. The resulting update was compiled, signed with SolarWinds' legitimate code-signing certificate, and distributed through the official update channel to approximately 18,000 organizations including multiple US government agencies.
The sophistication was in the targeting: the SUNBURST backdoor lay dormant for two weeks after installation, checked that it was not running in a sandbox or analysis environment, communicated through DNS queries that mimicked legitimate SolarWinds traffic, and selectively activated only against high-value targets. The attack went undetected for over nine months.
The Codecov incident in 2021 followed a similar pattern but targeted the CI/CD pipeline itself. Attackers modified the Codecov bash uploader script - a tool that thousands of organizations ran in their CI/CD pipelines to collect code coverage data - to exfiltrate environment variables, including secrets, tokens, and credentials from every CI/CD run that used the compromised script.
Build Provenance and SLSA
The Supply-chain Levels for Software Artifacts (SLSA, pronounced "salsa") framework addresses build pipeline integrity through increasingly rigorous requirements. At SLSA Level 1, builds produce provenance metadata describing how the artifact was built. At Level 2, provenance is generated by a hosted build service. At Level 3, the build platform is hardened against tampering. Each level makes it progressively harder for an attacker to inject malicious code without detection.
SBOM: Knowing What You Ship
A Software Bill of Materials is not a security control - it is a prerequisite for every other supply chain security control. Without an SBOM, you cannot answer the question "are we affected?" when a vulnerability is disclosed. The Log4Shell vulnerability in December 2021 demonstrated this at scale: organizations with SBOMs identified affected applications in hours; organizations without them spent weeks manually auditing codebases.
Modern SBOM formats - SPDX and CycloneDX - capture the full dependency tree including transitive dependencies, which is where most supply chain risk lives. Your application may have 20 direct dependencies but 200 transitive ones, any of which can introduce a vulnerability or be compromised. Generating SBOMs as part of the CI/CD pipeline and storing them alongside release artifacts makes vulnerability response a database query rather than a forensic investigation.
Lockfile Integrity and Package Signing
Lockfiles (package-lock.json, yarn.lock, Pipfile.lock, go.sum) pin dependencies to exact versions and integrity hashes. They are the first line of defense against supply chain manipulation - but only if they are committed to version control, reviewed in pull requests, and enforced during CI/CD builds. Running npm install without a lockfile, or ignoring lockfile changes in code review, negates their protective value.
Package signing adds cryptographic verification of package authorship. npm's provenance feature links published packages to specific source commits and build environments. Sigstore provides keyless signing for open source artifacts, creating a verifiable chain from source code to published package. These mechanisms do not prevent a compromised maintainer from signing malicious code, but they do make the supply chain auditable - you can trace exactly who published what, when, and from which build system.
For a thorough assessment of your software supply chain security posture - including dependency management practices, build pipeline hardening, SBOM maturity, and CI/CD security controls - schedule a supply chain security review with Lorikeet Security.
Secure Your Software Supply Chain
Lorikeet Security evaluates your dependency management, build pipeline security, CI/CD configuration, and supply chain controls. Our assessments identify the gaps that automated scanners miss - from registry misconfigurations to build system hardening.