One lock is not a security program
No single control is a security program. Locking the front door is important. It also does not help if you left a window open.
I sit on the SLSA steering committee, which is why I keep getting asked why SLSA didn’t stop the last attack. The answer is that it was never going to, and the people who write these specifications (me included) have done a poor job of transparently saying that.
Sometimes the question is instead "why didn't trusted publishing help." Sometimes it is a scanner, an SBOM, a policy tool, or an attestation someone had in place. The specifics change; the shape of the question does not. Something was supposed to prevent this. It did not. Why?
A few people turn that into "SLSA is useless" and post it. Most people do not post anything. They are just confused. You keep hearing that SLSA, trusted publishing, in-toto, the OpenSSF Baseline, or your scanner of choice is "the answer", then you read an incident writeup where one of those was sitting right there when the compromise happened anyway, and you cannot square it.
That confusion is fair, and I think a lot of it is on the community that builds these specifications. Myself included. We have done a decent job of explaining what each control claims. We have done much less of a job explaining what each control does not claim, and even less of a job explaining what happens when you deploy one in isolation. This post is my attempt at fixing some of my share.
Here is the frame the whole series is going to lean on. No single control is a security program. Locking the front door is important. It also does not help if you left a window open. Every specification, every tool, every attestation, every scan is one lock on one door. Doors matter. But attackers do not pick the strongest door; they pick the easiest way in, and the way in is almost always the one someone did not know to lock.
None of the recent supply chain attacks are evidence that SLSA failed. In every one of them, the project had a lock on the front door and a window open two rooms over, and once you see that, the incident writeups stop reading like paradoxes and start reading like floor plans.
This post is the entry point for a series aimed at three audiences: producers, distributors, and consumers of software. The point of the series is to take you, or your team, from either no security program at all or a security program built out of unrelated tools that nobody has connected together, toward an SDLC security program where the controls compose. If you have been on the receiving end of "why didn't SLSA help" or asking it yourself, read this first. The audience-specific pieces behind it assume you leave here knowing what each specification is actually for and, at least as importantly, what it is not.
What SLSA build provenance actually claims
SLSA build provenance is a signed statement, produced by the build service, that says: this artifact was produced by this build service, from this source, at this commit, at this time, with these inputs, in this workflow, running in this configuration. That is the whole claim. At Build Level 3 the builder is hardened enough that a build-side attacker cannot lie about any of it.
Read that claim carefully. Every noun in it is about the build. None of them says anything about whether the source deserved to be built in the first place.
If the source is truthful, the artifact is truthful. If the source is malicious, the artifact is faithfully malicious.
What this does NOT prevent: compromise of the source repository, a malicious commit landing before the build starts, or compromise of the maintainer account that triggers the build. Any of those, and the resulting provenance is signed, verifiable, and completely wrong about the trustworthiness of the code it truthfully attests to.
What trusted publishing actually claims
Trusted publishing binds the act of publishing to a specific workflow in a specific repository at a specific point in its history. It replaces long-lived registry tokens with short-lived OIDC identities, which means there is no npm or PyPI credential sitting in a repo secret for someone to phish. When it works, the only thing that can publish your package is a workflow you approved, running in the repository you approved.
That is real and worth having. It closes the token-theft class of attack cleanly, which is why the ecosystem has been pushing it aggressively over the last two years.
What this does NOT prevent: the source repository being compromised in the first place. If a bad commit lands in the source and the trusted-publishing workflow runs on that source, the trusted-publishing binding will produce a valid attestation for malicious code. It checks that the workflow was authorized to publish, which is a different question from whether it should have run at all.
Why one control isn't a security program
Both of the sections above describe individual locks. What neither of them explains is how a compromise travels once it is inside, and that is the part the current wave of incidents keeps demonstrating.
The chain looks like this. Source produces build. Build produces artifact. Artifact is published. Publish reaches the consumer. The arrow points in one direction, and this matters more than most people give it credit for.
If you compromise the source, you compromise the build (it reads compromised source), which compromises the artifact (build produced it from bad source), which compromises the publish (the published artifact is compromised), which compromises the consumer (they pulled a compromised artifact). Attestations along the way describe real events truthfully, and by describing real events truthfully they attest to a compromised source having produced a compromised artifact. They are faithfully wrong.
If you compromise the build instead, everything downstream of the build is compromised. The source is unaffected upstream. The artifact and everything after it are working from bad inputs.
If you compromise the publish, the artifact-to-consumer link is compromised. Upstream is unaffected.
If you compromise the consumer, it is local to that consumer. Other consumers are unaffected.
The direction of the arrow is why "SLSA didn't help" keeps happening. Attackers know the arrow points downstream. If your build system is hardened and your source is not, the rational move is to skip the build entirely: attack the source, walk the compromise downstream, and let your hardened build system faithfully produce and sign the malicious artifact for you. You did the signing infrastructure work; the attacker gets the benefit.
That is what happened in the 2026 incidents. SLSA build provenance was there. It did what it does. What it does is not the door that got left open.
The mental models the industry has been using to describe this for a long time apply cleanly:
- Defense in depth: no single control is the program. Every layer that carries a control raises the cost of getting through. Locks on the door, alarms on the window, motion sensors in the hallway; each one buys something, none of them is the whole.
- Swiss cheese: every control has gaps. The point of layering is to arrange the gaps so they do not line up. Incidents happen when the gaps line up across layers. A compromised source that passes review with only two colluding maintainers, and reaches a build system that assumes a reviewed commit is safe, and produces provenance that describes what happened rather than what should have happened, is the alignment of three gaps.
- Weakest link: attackers pick the weakest lock, not the strongest. If your build is at Level 3 and your source has no signed commits and no protected branches, then investing in Level 4 does not make you safer. Reducing your investment in build controls is not the answer either. Bringing up the weak layer is.
- Chain of custody: because compromise propagates downstream, upstream controls buy more than downstream controls for the same effort. Source-side hygiene closes doors before the attacker has picked the first one. Build-side and publish-side controls still matter; they are just not a substitute.
So the specific answer to "why didn't SLSA help in the recent attacks" is that SLSA answers one question about one link in the chain, and the rest of the chain is your problem. Every control in every layered system works this way, and physical security has been designed around that for decades.
There is a velocity problem layered on top of all of this, and it is the part that makes the old advice insufficient even when people follow it. Development is moving faster than it ever has: more code, more repos, more pipelines, more dependencies, much of it generated or assembled faster than anyone reviews it. Attacks are automating at the same pace. So the house metaphor needs an update.
You no longer have a handful of doors and windows to check. You have dozens or hundreds, and if your practices have not kept up with your footprint, an awful lot of them are standing open right now. That changes what a useful preventive control looks like. A control that takes a quarter and a working group to roll out loses to an attack that takes minutes. The controls that actually get adopted at this velocity are the ones that are dead simple to turn on, and the ones worth recommending are the ones that stay on without someone tending them.
The rest of this post walks through the specific controls that were, or would have been, other locks in the same house, and where the recent incidents show us the windows were open.
Build integrity vs source integrity
Zooming in on one specific gap alignment, because it is the one the 2026 events keep hitting. The chain has more than two links, but the split between the build side and the source side is where most of the current confusion lives.
Build controls answer: was this artifact produced by the pipeline we said it was, from the code we said we were building?
Source controls answer: was that code itself what we think it was?
| Category | Answers | Controls in this category | What breaks it |
|---|---|---|---|
| Build integrity | Was this artifact really produced from that source by that builder? | SLSA build track, trusted publishing, reproducible builds, artifact signing | Post-build tampering, build-side compromise, mirror substitution |
| Source integrity | Was the source itself what we think it was, produced by the people we think produced it? | Signed commits, allowlisted maintainer identities, protected branches with review, hardware-token 2FA, SLSA source track | Maintainer takeover, social engineering, orphan-commit bypass, insider action |
Both categories are necessary. Historically the industry has invested overwhelmingly in build controls, because build compromise was the visible failure mode for a long time. SolarWinds is the archetype: the attacker got into the build system and injected code that the source repository never knew about.
What has changed in the last two years is that attackers have gone upstream. They are patient enough now that compromising a maintainer, or waiting for one to leave and inheriting their access, is a better return on effort than compromising a hardened build system. The build system is still there and still hard. The attacker just stopped attacking it.
The current attack pattern — social engineer a maintainer or steal their session, land malicious code through a legitimate account, let the pipeline do the rest — runs the build side truthfully and lies through the source side. That is why build-side controls come back unblemished after these incidents. They ran, they passed, and the check they passed was never the one that would have caught this.
If you only invest in one of the two categories, you are looking at half the picture and paying full price for it.
Where the recent attacks actually happened
I want to walk through the three 2026 events specifically, because press coverage smears them together as "another SLSA failure" and they are actually distinct. If you take one thing from this section, take the asymmetry: two of them are source-side compromises, one of them is a publish-side compromise, and all three produced valid downstream attestations.
AsyncAPI (July 14, 2026). Attacker gained push access to the project's next branch across four core repos. The project's real GitHub Actions release workflow ran, requested an OIDC token, and published to npm. Every malicious package carried valid npm provenance. The provenance was correct. It said: this was built by this workflow in this repo at this commit. All of those statements were true. The commit itself was the compromise.
What would have raised the cost is what you would expect: signed commits from an allowlisted set of maintainer identities, tight branch protection on release-adjacent branches, and required review even for maintainer pushes. None of that is exotic. It just was not fully in place on the release path.
Red Hat @redhat-cloud-services (June 1, 2026).
Compromised employee GitHub account pushed orphan commits that bypassed branch review, triggered Actions to mint OIDC tokens, and shipped Trojanized packages under at least 32 packages in the @redhat-cloud-services scope.
Provenance was valid SLSA.
Same shape as AsyncAPI at the mechanism level: build side truthful, source side compromised, downstream sees a clean chain.
The specific enabling gap was the orphan-commit path, which let commits reach the release path without going through review. That is a source-side gap that build provenance is definitionally blind to.
TeamPCP LiteLLM PyPI (March 23, 2026). Slightly different shape: this one hit publishing infrastructure rather than source. Attacker used PyPI publishing tokens to push v1.82.7 and v1.82.8. Trusted publishing would have replaced the tokens with an OIDC workflow binding, and there is a version of this argument where "if trusted publishing had been in place they'd have been fine." That version is wrong. If the binding had been in place and used, the same workflow that published legitimate versions would have published these. The compromise vector was upstream of the publish step. Trusted publishing closes credential theft. It does not close pipeline ownership.
Note the asymmetry across the three: source, source, publish infrastructure. All three ended the same way downstream, with a valid attestation attached to a package that should not have been published. Any single one of these is a case study. All three in six months is a pattern.
This is not new; it just keeps happening
The reason to lead with 2026 is that it is fresh, not that it is unprecedented.
xz-utils, 2024. The most instructive version of this same story. "Jia Tan" spent roughly two years working themselves into maintainership on xz. They were productive, helpful, technically competent. Their commits were reviewed. Their PRs merged. When they had commit rights, they hid the backdoor payload in the release tarball's build-time autotools plumbing — not in the git tree that everyone was reviewing, but in the generated files that ship in the release. The tarball built and shipped to distros; the git repo looked clean the whole time. It took luck (Andres Freund's benchmark caught a slow SSH handshake) to surface it before it landed in stable Debian.
If SLSA build provenance had been present on those tarballs at Level 3, the provenance would have been signed and verifiable, and would have said: this tarball was produced by this builder from this source. Which would have been true. And useless, because the "source" was the maintainer's local checkout that contained plumbing that never survived a code review. Same shape as the 2026 events, roughly two years earlier, with a much longer setup time.
Older cases in the same family: event-stream, 2018, where a maintainer socially engineered into a package handoff shipped a malicious dependency to Copay wallet users through the npm registry; Codecov, 2021, where the trusted uploader script hosted at codecov.io/bash was modified in place and exfiltrated CI secrets from thousands of projects for two months before anyone noticed. The specifics differ and the pattern doesn’t: attacker moves upstream of the visible integrity check, downstream sees no red flags, artifacts and pipelines behave exactly as designed.
If you are counting, that is roughly one high-profile source-side or distributor-side compromise every year to eighteen months for the last decade, and the cadence is going up. The "SLSA doesn't help" reaction is understandable after any one of these. This is the same argument each time, though, and it has been for a decade. At some point the interesting question stops being about the lock and starts being about the window.
What actually would have helped
So if build controls do not catch source compromise, what does?
Nothing on this list will surprise you. It is a small set of source-side controls most projects already know they should have, applied consistently and hardened enough that one compromised account cannot wave them through.
Hardware-token 2FA on every maintainer account. Not SMS. Not TOTP with phishing-friendly recovery. Hardware. This closes the low-effort account-takeover class, which is how the compromised employee account in the Red Hat incident happened. It is not a cure. A determined social-engineering attack (see xz) does not care about your hardware token. But it takes bulk phishing off the board, which is the entry vector for most of these.
What this does NOT prevent: patient social engineering that gets an attacker legitimately promoted to maintainer, or targeted device compromise of an already-authenticated maintainer.
Signed commits from an allowlisted set of identities. Every commit that lands on a release branch is signed by an identity that is on your allowlist. Sigstore-based gitsign, organization-managed keys, whatever fits. This makes "pushed by an account no longer on the team" and "pushed by an identity we never approved" catchable, because you have decided what an approved commit looks like.
What this does NOT prevent: the maintainer whose identity is on the allowlist being the attacker (see xz), or the attacker having compromised the maintainer's signing key.
Protected branches with required review, no bypass paths. Release branches accept nothing that has not been reviewed by an identity other than the author. No orphan-commit paths. No admin override without an audit trail. The Red Hat incident specifically exploited a bypass path that let orphan commits skip review. If that path had not existed, the compromised account would have needed to also compromise a reviewer.
What this does NOT prevent: two colluding attackers, an attacker who has compromised both the author and the reviewer, or a rubber-stamp review culture.
Unusual-workflow-shape alerting. A release workflow that has run the same way for two years and one day runs from a slightly different job configuration or a different pinned action version is worth alerting on. Not glamorous. Would have caught pieces of AsyncAPI, where the attacker's push subtly changed the workflow's behavior.
What this does NOT prevent: an attacker who is patient enough to make the change look ordinary, or who lets normal drift over months provide cover.
SLSA source track. SLSA has a source track precisely because the community understood the build track was insufficient on its own. Source track adds attestations about how the source got to its current state — what branches were merged, what review happened, which identities acted. It is younger than the build track and less commonly implemented, and this is the moment for producers to start. Source track being present makes downstream verification of the source-side story possible in the same mechanical way build provenance made the build-side story verifiable.
What this does NOT prevent: what any attestation cannot prevent, which is the underlying event. Source track raises the cost of hiding a compromise; it does not stop the compromise itself.
Identity revocation velocity. When an employee leaves, when a maintainer is offboarded, when a session is suspected of being hijacked, how fast does the identity actually lose access to the release path? If the answer involves a quarterly access review and a spreadsheet, the answer is "not fast enough."
Be honest about what speed buys you here, though, because this control has gotten harder, not easier. Attackers automate now, and increasingly they automate with the same AI tooling that is accelerating everyone else. In recent incidents, a compromised workflow harvested credentials and those credentials were used for further compromise within seconds to minutes. The Shai-Hulud npm worm in late 2025 is the extreme case: stolen tokens were used to trojan and publish more packages with no human in the loop at all. No revocation process with a person in it wins that race. Revocation still matters, because it bounds how long an attacker keeps access they should not have, and in the slower 2026 account-compromise incidents it would have shortened the window. What it no longer does is arrive before the damage. So the weight shifts to prevention (short-lived credentials, so there is nothing durable worth stealing) and detection (knowing what was taken and what it touched, so you can scope the impact instead of guessing at it).
What this does NOT prevent: the attacker who acts inside the revocation window, which for automated attacks is now essentially every attacker, or an attacker with legitimate access.
OpenSSF Baseline as the frame. If you want a menu of these controls in one place, OpenSSF Baseline is where the industry consensus lives now. It is the reference frame the audience tracks in this series use. Baseline is not a control on its own; adopting the controls it names is what does the work.
What this does NOT prevent: Baseline is a menu, not a mechanism. It does not close any specific attack surface on its own. Reading it does not deploy any of it.
Where SLSA and trusted publishing still matter
Because the honest version of "these controls did not prevent the recent attacks" has to include the fact that they are still the right controls, just not for the attack that happened.
Build track still matters for post-build tampering. If your artifact ships from a hardened builder and carries verifiable provenance, then intermediate hops — artifact mirrors, distribution CDNs, package caches — cannot silently substitute a different artifact and have it pass verification. That is not what happened in the 2026 events. It is what happened in SolarWinds, and it will happen again the moment build-side attention slips.
Trusted publishing still matters for token theft. A whole class of "attacker got a long-lived npm publish token and pushed" attacks disappears when there is no long-lived token to steal. Removing a class of attack is worth doing even when it does not close the class of attack that just made the news.
Reproducible builds matter for verifying, at distribution time, that the artifact you got matches what the source you can read would produce. That check would have caught xz, because the malicious payload was in the tarball and not in the git tree. Reproducible builds catches that specific gap — artifact drift from source — which is a real gap that has appeared repeatedly in incidents.
Every one of these is a piece of the picture. What has gone wrong in the current discourse is treating any one of them as the whole picture. When AsyncAPI happened, "SLSA didn't help" was true about the build track and silent about the source track, which is the piece that would have. Two tracks with two different jobs, graded as if they were one thing.
The track list is also not done growing. There is active work on a SLSA dependency track, aimed at the consumption side of the chain. The idea is attestations about how a dependency entered your environment in the first place: where it was pulled from, what screening it passed on the way in, and whether anyone verified its upstream provenance before the package landed in your build. Today that step is close to invisible. Someone ran an install command at some point, the package became load-bearing, and if you have ever tried to reconstruct after an incident why a package is in your tree at all, you know how little record exists. That is the gap this track is pointed at. It is still in draft, and in keeping with everything above, when it lands it will answer one more question about one more link, not all of them. Worth watching anyway: it is the first track to treat "how did this get here" with the same rigor build provenance brought to "how was this built."
The series map
The point of this series is to take you from either no supply chain security program, or a program that is a pile of unrelated tools nobody has connected together, toward an SDLC security program where the controls compose. That is a longer journey than any one post, so the series splits by audience and by depth.
Producers (people writing and shipping software for downstream consumption): what to adopt, in what order, and against which threats. If your project ships a package or binary that other people install, you're here.
Distributors (registries, mirrors, distros, repackagers): the obligations unique to the middle layer, and the blast-radius argument for taking them seriously. This audience is written for the least in the current supply chain security literature, and its compromises fan out the widest.
Consumers (people pulling in third-party code): what SCA and scanning catch, what they miss, and which controls you can adopt without waiting for any producer to change anything. If you're a security team responsible for what enters your enterprise dependency graph, you're here.
One more thing about these three roles before you pick a track: they do not carry the burden equally, and most guidance is written as if whoever is reading it has the budget to act on it.
Consumers are usually the ones running a business on the open source they pull in. They are getting something for free, with everything "free" actually means: no contract, no support commitment, no legal remedy when it breaks or turns out to be compromised. That is the deal, and the alternatives all exist — buy commercial software, pay for enterprise support, fork the project and staff it — and how rarely anyone picks them tells you how good the deal is. But it also means a consumer's leverage over what they consume is close to zero, which is why the consumer track focuses on controls you can adopt without asking anyone upstream to change anything.
Distributors have real control on paper. They own the distribution points, and they could decide who publishes and what gets through. In practice both fairness and cost push the other way: inspecting everything that flows through a public registry is expensive, and gatekeeping who gets to publish sits badly with the open publishing model that made these ecosystems work in the first place. So most registries let people publish what they want, and are only now starting to look harder at the most popular packages, where the blast radius justifies the cost.
Producers carry the biggest burden with the smallest priority attached to it. Some open source is effectively subsidized by multibillion or multitrillion dollar companies; the Linux kernel does fine. A lot of it is not, and a lot of the transitive dependencies major projects sit on are not. xz is the canonical example: a compression library maintained by roughly one overloaded volunteer that turned out to sit underneath sshd on major distros. And even developers at large companies are usually told to ship features, not security. I have heard this directly from multiple projects: they care about security, they are just not paid to care about security. Some of those same organizations, which shall remain nameless, will publicly espouse the virtues of supply chain security and want the whole ecosystem to adopt the latest tools and practices, while declining to fund that work in the projects they depend on or even the ones they run. If the producer track reads like it is asking a lot from the people with the least resources, that is because it is, and it is written knowing that.
Producers are also consumers. That overlap is handled at the series level, not with a fourth track: the producer and consumer intros cross-link at the exact points where the two roles apply to the same organization, and neither piece asks you to read the same content twice.
Follow-ons will be control guides that go deep on one control at a time (framed by which layer it addresses and which layers it doesn't), and attack post-mortems that walk through specific incidents in the same "which controls helped, which would not have, which do not exist yet" format used here.
If you came for the SLSA correction and want to leave, the short version is: use it, know what layer it addresses, and put controls on the other layers too. If you came for the "so what do I actually do," pick the audience track that matches your role and start there.