Supply Chain Security
- title
- Supply Chain Security
- type
- concept
- summary
- Protecting code-to-artifact chain: CI/CD, dependencies, registries, releases, defense patterns
- tags
- security, ci-cd, dependencies, software-engineering
- sources
- open-source-security-astral, long-lived-keys, marius-bitwarden-not-recommended, tanstack-npm-supply-chain-postmortem, fsnotify-maintainer-dispute
- created
- 2026-04-09
- updated
- 2026-05-12
Protecting the chain from source code to deployed artifact. Every link β CI/CD pipelines, dependency managers, package registries, build caches, release processes β is an attack surface. Compromising any one link can inject malicious code into the final product without touching the source repository.
Attack surfaces
CI/CD pipelines. GitHub Actions, GitLab CI, and similar systems execute code with access to secrets and publishing credentials. Dangerous trigger types β see the pwn-request-pattern β expose privileged contexts to external code. Mutable action tags let attackers silently replace action code. Build caches can be poisoned to inject payloads into future builds (github-actions-cache-poisoning). Once code is running on a CI runner, OIDC tokens minted in-process can be extracted from memory and used to publish directly (ci-runner-token-extraction).
Dependencies. A compromised upstream package poisons everyone who depends on it. The window right after a new release is especially dangerous β the Astral post describes dependency cooldowns as a mitigation: delay updating to avoid catching a temporarily compromised version.
Package registries. Long-lived API tokens for PyPI, NPM, crates.io are a common takeover vector. Account compromise or token theft lets attackers publish malicious versions under a trusted package name.
Release artifacts. Tags can be force-pushed, releases modified after publication, binary downloads served from mutable URLs. The Trivy supply chain attack used tag force-pushing to replace a legitimate release.
Defense patterns
Eliminate credentials where possible. Trusted Publishing (OIDC-based identity federation) lets CI publish to registries without stored tokens. The registry trusts the CI provider's identity assertion instead. This is one instance of the broader ephemeral-credentials pattern β see long-lived-keys for the case that registry tokens are exactly the kind of credential you should never have in the first place.
Pin everything. Actions pinned to commit SHAs, dependency versions locked, download URLs mapped to cryptographic hashes. Mutability is the enemy β anywhere a pointer can be silently redirected, an attacker can substitute malicious content.
Minimal permissions. Start with zero permissions, grant only what each job needs. Isolate secrets into deployment environments rather than making them available repo-wide.
Attestation and verification. Sigstore creates cryptographic links between artifacts and their producing workflows. Users can verify that what they downloaded was actually built by the expected CI pipeline.
Immutable releases. Once published, artifacts and tags can't be modified. This blocks the "replace the release after the fact" attack pattern.
Multi-person approval. Release processes require sign-off from more than one person, mitigating single-account compromise.
Dependency cooldowns. Deliberately delay dependency updates after new releases. Most supply chain poisoning through dependencies is discovered quickly β waiting a few days filters out the worst.
Social relationships. Know your upstream maintainers. Contribute security improvements to their pipelines. Participate in ecosystem security teams. Supply chain security is partly a coordination problem.
Tools
- zizmor β static analysis for GitHub Actions workflows, catches unpinned actions and impostor commits
- pinact β automated action pinning to commit SHAs
- Sigstore β keyless signing and verification for artifacts
- Trusted Publishing β OIDC-based credential-free publishing (PyPI, crates.io, NPM)
- Dependabot / Renovate β automated dependency updates with cooldown support
Maintainer-trust attacks
Not every supply-chain risk is a credential or pipeline compromise. The hardest class to defend against is maintainer-trust capture β a contributor accumulating legitimate access over time and then misusing it, as in xz-utils. Its sibling failure mode, maintainer-governance-ambiguity, is what makes even legitimate maintainer transitions look like attacks now, and forces downstream users into expensive verification cycles when projects don't make access changes auditable. Related: unmaintained-scanner-pressure is the forcing function that pressures stable projects into the very kind of "new maintainer steps in" event that, post-xz, reads as an attack from outside.
Notable incidents
-
2026-05 fsnotify β maintainer dispute mistaken for takeover. A 321k-dependent Go library; access removals between arp242 and mattn read from outside as a possible supply-chain incident. No code compromise. Worked example of maintainer-governance-ambiguity and post-xz outside-observer cost. See fsnotify-maintainer-dispute.
-
2026-05-11 TanStack β
@tanstack/*npm scope. 84 malicious versions across 42 packages published in a 6-minute window via a three-link CI chain: apull_request_targetworkflow that built fork code (pwn-request-pattern), Actions cache poisoning across the forkβbaseβproduction trust boundary (github-actions-cache-poisoning), and OIDC token extraction from runner memory (ci-runner-token-extraction). No npm tokens were stolen; the legitimatePublish Packagesstep never ran. External detection within ~20 minutes via Socket.dev and an open issue. See tanstack-npm-supply-chain-postmortem for the chain and the lessons specific to each defense. -
2026 Shai-Hulud / Checkmarx β Bitwarden CLI. Bitwarden's
@bitwarden/cli2026.4.0 was published to npm with a maliciousbw1.jspayload via a compromised GitHub Action in their CI/CD pipeline. The payload pulled the Bun runtime, decrypted the Shai-Hulud worm, and harvested GitHub/npm tokens, SSH keys, shell history, AWS/GCP/Azure credentials, GitHub Actions secrets, and MCP configs β exfiltrated by auto-creating a public repo on each victim's own GitHub account. Live for ~19 hours; 334 developers affected. Two compounding factors: a security-critical CLI distributed through npm rather than as a single static binary, and a CI/CD pipeline that didn't catch the injected file before publish. See marius-bitwarden-not-recommended for the broader Bitwarden context.
See also
- open-source-security-astral β Astral's detailed implementation of these patterns
- long-lived-keys β Ludwig's argument that the registry-token problem generalizes to all long-lived keys
- ephemeral-credentials β the underlying pattern Trusted Publishing instantiates
- hazmat β runtime containment for AI coding agents (a different layer of the trust problem)
- living-off-the-land β runtime analogue: attackers using legitimate pre-installed binaries instead of dropping malware
- gtfobins β canonical Unix catalog of LotL-abusable binaries, both red-team reference and sysadmin checklist
- dockerscan β a concrete scanner covering several of these surfaces (CIS benchmark, supply-chain, secrets, CVE, runtime) for Docker images
- appsec.guide β Fuzzing Chapter (Trail of Bits Testing Handbook)
- CI Runner Token Extraction
- Coverage-Guided Fuzzing
- Differential Fuzzing
- fsnotify Maintainer Dispute and Supply-Chain Concerns
- GitHub Actions Cache Poisoning
- gosentry β Trail of Bits' Go Fuzzing Fork
- Grammar-Based Fuzzing
- Maintainer Governance Ambiguity
- I Do Not Recommend Bitwarden
- Patch β Port (the New Unit of OSS Contribution)
- Pwn Request Pattern
- Structure-Aware Fuzzing
- TanStack npm Supply Chain Compromise β Postmortem
- Unmaintained-Scanner Pressure
- CrabTrap
- dockerscan
- manylinux
- Agent readiness
- Agentic Coding is Burning Me Out
- Anubis WASM vendor binary: reproducible builds are surprisingly hard
- Bitwarden
- CI Runner Token Extraction
- Credential Compartmentalization
- Default version bound constraints
- Dependency Vendoring
- don't sign in with google (the smart ape, 2026)
- Ephemeral Credentials
- fsnotify Maintainer Dispute and Supply-Chain Concerns
- fsnotify
- GitHub Actions Cache Poisoning
- gosentry β Trail of Bits' Go Fuzzing Fork
- GTFOBins
- Living Off The Land
- You Don't Want Long-Lived Keys
- Maintainer Governance Ambiguity
- I Do Not Recommend Bitwarden
- Matryoshka Isolation (Containers Inside VMs)
- Your Container Is Not a Sandbox β MicroVM Isolation in 2026
- OAuth token theft (multilogin + consent phishing)
- Obsidian: The Future of Plugins
- Open Source Security at Astral
- The pandemic of incomplete OpenSSL error handling
- PHK's last Bikeshed: the end of FOSS as we know it
- Patch β Port (the New Unit of OSS Contribution)
- Pwn Request Pattern
- Redis and the Cost of Ambition
- Reproducible Builds
- Reuse Less Software
- rust-vmm
- Sandboxing AI Agents
- Socket Blog
- The specification.website Checklist
- specification.website
- TanStack npm Supply Chain Compromise β Postmortem
- TanStack
- Unmaintained-Scanner Pressure
- xz-utils Incident
- ENOSUCHBLOG (blog.yossarian.net)