npm provenance attestations get worn as camouflage in a new worm-style attack
Tomás Vega
Provenance was supposed to be the answer. Attach a cryptographic receipt to each release that says "this artefact was built by that workflow, on that commit," and downstream consumers finally have something to check besides the maintainer's word. Then somebody wore the receipt as a disguise. On August 7 The New Stack reported that security researchers this week disclosed a worm-style supply-chain attack against the npm ecosystem, in which provenance attestations were used as camouflage.
That is a short news item, and I want to be careful about what I claim on top of it. The reporting is a headline more than a full write-up; the exact package list, the researcher names, the timeline of infections and the precise abuse mechanic belong to their disclosure, not to me. What I can talk about is the shape of the trust story: what an npm attestation is supposed to prove, what "camouflage" implies about how the proofs were being read, and what a CI/CD team should do on Monday morning before the details firm up.
What we actually know today
Three lines, from The New Stack's report:
- Security researchers this week disclosed a supply-chain attack against the npm ecosystem.
- The campaign is characterised as worm-style.
- Provenance attestations were used as camouflage rather than as an obstacle.
You will notice I have not attached package counts, victim names, versions or CVE identifiers to those bullets. That is deliberate. Wait for the researchers' full write-up. Even so, the headline claim is enough to force a policy conversation.
A refresher, because "attestation" is doing a lot of work
npm provenance is a specific pipeline that binds a published package to the CI workflow that produced it. The publisher configures a trusted workflow, typically GitHub Actions with OIDC; the workflow signs a statement about the build using a short-lived identity; the signed statement lands in a public transparency log. At install time, tooling can fetch the attestation, verify the signature chain, and confirm the package was produced by that workflow on that commit.
Read that sentence again. It confirms provenance. It does not confirm intent, it does not confirm that the workflow's inputs were clean, and it does not confirm that the publisher's account was still in the right hands when the workflow ran. Provenance is an answer to "where did this come from," and if the answer is "from the workflow you configured, run by the account you own," a signature is going to say yes.
If an attacker gets to publish through your workflow (a stolen token, a compromised runner, a poisoned dependency inside the build itself, a maintainer who merged something they should not have), the attestation still checks out. The receipt is not lying. It is telling you accurately that a compromised process produced the artefact.
That is the camouflage.
What "camouflage" implies for verification policy
A checkmark on the install screen and no further review is the failure mode this attack exploits. If your enforcement rule is "must have provenance" and nothing else, you have moved the trust boundary onto a bit that flips true whenever the pipeline runs, whoever caused it to run.
Some questions to voice out loud in whatever meeting owns this:
- Whose OIDC identity is bound to the attestation, and is that identity a repository your organisation controls or a repository you happen to consume?
- Do you compare the workflow reference in the attestation against a pinned expected value, or do you accept any workflow the publisher has ever used?
- What does your policy do when a package that had provenance last week suddenly has provenance from a different workflow this week?
- Do you have a way to fail a build when a transitive dependency's attestation is structurally fine but points at an unexpected builder?
None of these are new questions. This news turns them into the ones you have to answer instead of file.
What to change in your pipelines this week
Take the caveats seriously and treat the disclosure as a nudge, not a rewrite.
- Keep verifying provenance. A signed statement about the builder is still more information than the previous status quo of "trust the tarball." Do not throw the control out because the control alone is insufficient.
- Pin, do not just prefer. If your policy accepts a package as long as some attestation exists, tighten it. Accept it only when the attestation names an approved workflow ref on an approved repository. Everything else is a warning at minimum.
- Watch the publisher-identity delta. A dependency that used to publish from workflow A and now publishes from workflow B is a signal. Log it. Alert on it if you can.
- Keep OIDC hygiene current on the workflows you own. Short-lived tokens, minimal scopes, no long-lived npm automation tokens rotting in unrelated environments. This attack targets the ecosystem; the same discipline hardens your side of the fence.
- Assume worms move. Worm-style means one compromised package writes itself into the next. Refresh your lockfile-diff review; a small unexpected transitive addition is exactly what this class of attack looks like from your seat.
Verification, expressed as a policy question rather than a shell command, might read like this (placeholders only, obviously):
# Accept the package only when its attestation names the workflow you expect.
policy:
require_provenance: true
allowed_builders:
- repository: <org>/<repo>
workflow_ref: <org>/<repo>/.github/workflows/<file>@refs/heads/<branch>
subject_digest: sha256:<digest>
on_mismatch: fail
You do not need my YAML; you need a policy your registry client or scanner can enforce, and a broken build when it does not match.
How neighbouring ecosystems sit next to this
Every major package registry is somewhere on the same slope. PyPI has trusted publishers with sigstore-backed attestations. RubyGems has a signing story most maintainers have not adopted. Container images have Cosign and SLSA-provenance workflows that face the same "signed by whom, and on whose behalf" question. None of them solve the disclosed problem, because none of them can. A signature only confirms what it was asked to confirm.
Where npm has moved fastest recently is on the identity side of that equation: mandatory 2FA on high-impact publishers, granular tokens, restrictions on bypass-2FA sessions. Attestation abuse is the next chapter of that story. This is an argument against reading attestations as a badge. It is not an argument against having them.
The verdict
Provenance is worth keeping. Provenance without a policy is worth roughly what a checkbox is worth, which is why the researchers' finding lands where it does. If your install pipeline treats the presence of an attestation as sufficient, you are the intended reader of this attack.
Read the receipt. Check who signed it. Then decide.
Source: The New Stack (thenewstack.io)