Why a valid signature is no longer enough in 2026 — an honest note after Mini Shai-Hulud

On the evening of 11 May 2026, just before 22:00 German time, the first publication from the StepSecurity researchers about the Mini Shai-Hulud wave hit my feeds. 42 @tanstack/* packages, 84 malicious versions, plus Mistral AI, UiPath, OpenSearch, Guardrails — over 170 packages in total, more than 500 million cumulative downloads. I wrote up the technical finding with a client lens on moselwal.de. Here I want to put down briefly the one thing that has occupied me most about the whole incident — and why it matters more than the hundredth list of affected versions.
A delivery that was genuine in every verifiable way
The compromised npm packages carry a valid SLSA Build Level 3 provenance. That means: the Sigstore signature is genuine, the OIDC identity is the right one, the build pipeline spec it was signed against is the official one. Anyone who built a cosign verification into their install stage — which many of us did over the past year and a half precisely to catch supply chain incidents — would have waved the compromised versions through as legitimate. The verification is not broken. It does what it is specified to do. It checks the shell, not the content.
I find that an honestly produced structural finding, and I find it considerably more uncomfortable than any classic token-theft story. In the predecessor incidents — Bitwarden CLI in April, Aqua Trivy in March, the original Shai-Hulud worm in summer 2025 — the model was “attacker gets credentials, publishes under a foreign identity, provenance is missing or forged”. The answer was always: “have the provenance checked”. This time the provenance is not the missing or forged piece, but the correctly generated one. The worm hijacked the build pipeline itself, mid-workflow, with the legitimate maintainer’s OIDC token — and Sigstore signed correctly under that identity because from the platform’s point of view everything was in order.
Read soberly, this means: “have the provenance checked” is no longer a complete answer in 2026.
What this means for my own practice
In the last 18 hours I flipped the switch that has been sitting in a drawer for some months in the pipelines I actively operate — at Moselwal, at OnlyOle, in the client projects. It comes down to three disciplines, and I write them down here because I will explain them in a client architecture meeting tomorrow morning anyway, and writing them down myself helps me state them cleanly.
First: signature and manifest are checked separately. Cosign verification stays at the entry gate, because it is structurally sound and in the normal case does exactly what it should. Right after it comes a manifest diff stage, which compares every newly resolved package version against the immediately preceding one — not the tarball as a whole, but structured fields of the package: scripts.postinstall, scripts.preinstall, bin definitions, the file list, newly added top-level dependencies. A version bump may have legitimate changes in these fields; an unexpected extension of the install hooks is a hard signal. The stage is a few dozen lines of bash and jq, runs in under 200 ms per package, and produces build stops rather than silent warnings.
Second: install hooks run in a hardened subprocess whose network egress is monitored.npm install no longer runs in the same shell as the actual build, but in an --ignore-scripts preamble followed by an isolated hook runner that executes the install hooks one package at a time with Falco detection in the observation field. Any install hook that opens an outbound connection to a non-allowlisted IP fails the build. In the first 24 hours of live operation, this caught two legitimate npm telemetry pings as false positives, which I have now explicitly allowlisted, and zero malicious activity. But when the next worm comes, it catches that one regardless of the provenance question.
Third: pull_request_target is now only allowed for steps that explicitly do not execute code from the PR. Label handling, comment triggers, status API updates — fine. actions/checkout@v4 with ref: pull_request.head.sha plus npm install in the same job — no longer. The operational consequence is that we have rethought certain preview build pipelines: the preview build now runs via a downstream workflow_run trigger with an approval gate. That is less convenient than before, and that is exactly the point — the inconvenience is the price the security of this class demands.
Why this stays with me
I believe that in two years’ time 11 May 2026 will be the date one names in hindsight as a turning point — not because Mini Shai-Hulud was the largest incident, but because it was the first in which the structural assumption “validly signed means content-trustworthy” was publicly and documentedly broken. Anyone who in 2026 continues to live in the architecture where Sigstore validation is the only entry control is no longer living in advance of the next wave. They are living in an architecture that has its break already behind it.
This is not a call to panic. It is a call to install the second stage. Provenance validation remains correct. It is just no longer enough on its own.
An honest note, because I believe we will read many such notes in the months ahead. Whoever installs this now will catch the next wave of this class. Whoever waits for the next patch is waiting for the wrong tool.
More on the specific vulnerability, the affected packages, and the operational immediate measures for clients: CVE-2026-45321 and Mini Shai-Hulud on moselwal.de.