We Renamed Our Detector After The Larval Form. Sandtrouts Are Easier To Catch Than Worms.
- Patrick Duggan
- 7 minutes ago
- 5 min read
The npm supply-chain worm that hit the TanStack, Nx Console, and @antv ecosystems across May 2026 is publicly named Mini-Shai-Hulud, after the giant sandworms of Frank Herbert's Dune. The naming travels because the campaign behaves like a worm — burrows into a maintainer's GitHub Actions pipeline, harvests the credentials necessary to publish, and then breaches the surface in a mass-publish event that consumes everything in its blast radius. Eighty-four malicious package artifacts in six minutes for TanStack. Three hundred and twenty-three malicious package versions in twenty-two minutes for @antv. The bloom is the visible part. The bloom is what hits the news cycle.
The bloom is also where the defender has lost.
By the time a Mini-Shai-Hulud wave is publicly named, the malicious packages have already entered the dependency graphs of every consumer who auto-updates. Public reporting catches up after the npm registry has propagated the bad versions, after the credential stealers have harvested CI environments, after the worm has self-published into every namespace the original victim could write to. The detector that fires during the bloom is operationally too late.
In Frank Herbert's Dune biology, the giant sandworm has a larval form: the sandtrout. Sandtrout are small, transparent-bodied creatures that live in shallow water, encapsulate moisture to protect the dry-environment-adapted adult worm from contact with water, and represent the earliest, most catchable stage of the lifecycle. The mature Shai-Hulud is enormous, fast, and overwhelmingly dangerous to anyone standing on the open sand. The sandtrout is small enough to fit in a Fremen child's hand and slow enough to be picked up before it matures.
The defender lesson, articulated in Patrick Duggan's frame this morning: if your detector is named after the mature form, you are catching it too late. Name it after the larval form and you are catching it on schedule.
What we renamed
DugganUSA's PreCog precursor aggregator runs eleven signals against the IOC corpus on an hourly cadence. One of those signals, deployed on May 24, 2026, was originally named CI/CD Compromise Indicators. Its detection logic queries the trailing-twenty-four-hour window of indicator records for tradecraft markers consistent with GitHub Actions workflow poisoning: forged-bot author email TLDs (@noreply.dev, @automated.dev), workflow-directory path references (.github/workflows/), and the identity-string set used by the TeamPCP / UNC6780 cluster (ci-bot, build-bot, pipeline-bot).
On May 27, 2026 at 07:05 UTC, the signal escalated from 0.4 to 0.85 — from "one indicator observed" to "five or more indicators in the trailing day." A T1 alert fired to the operator inbox. The escalation was caused by IOC pipeline absorption of the publicly-named Mini-Shai-Hulud @antv-wave indicators, hours before the campaign hit broad coverage. The signal, in other words, caught the campaign during the larval phase of its public disclosure — after the mass-publish event but before the doctrine had named the wave.
That is sandtrout detection. The signal is now formally renamed: Sandtrout Detector — Pre-Bloom CI/CD Compromise. The registry key remains cicd_compromise_indicators for historical correlation; the display name and description are the operational handle defenders see.
Why the naming travels
Defenders remember mnemonics that map onto the lifecycle they are trying to interrupt. "CI/CD Compromise Indicators" is a category name; it describes what the detector watches without committing to where in the timeline the detection lands. "Sandtrout Detector — Pre-Bloom CI/CD Compromise" commits to the lifecycle position. The defender reading the alert subject line knows immediately: this is the larval-phase signal, fire before the mature worm publishes. The action triggered by the alert — patch the maintainer's repository, rotate the credentials in the workflow secrets, deny-list the forged-bot identities — is the response that prevents the mature-phase bloom. The mnemonic carries the response timing inside the name.
This is a small move. It is also the kind of small move that compounds. Two weeks from now, when the next TeamPCP-class campaign generates a fresh CI/CD-tradecraft fingerprint and the signal elevates, the operator who receives the alert at 03:05 UTC will not need to remember what "CI/CD Compromise Indicators" was watching. The operator will receive an email titled "Sandtrout Detector — Pre-Bloom CI/CD Compromise ELEVATED" and immediately know that something is in the credential-encapsulation phase, that the campaign has not yet bloomed into mass-publish, and that the window for intervention is measured in hours, not days.
The lifecycle taxonomy as a defender primitive
We extend the lore by naming the three observable stages of the supply-chain worm lifecycle:
Sandtrout phase. Single maintainer credential theft, encapsulation of write-access tokens, build-pipeline tampering. Detection markers: forged-bot identities in commit logs, workflow-directory modifications, Trycloudflare-tunneled callbacks, blockchain-canister staging. Time window before bloom: hours to days. Our PreCog Sandtrout Detector watches this phase.
Pre-spice mass phase. Sigstore-signed malicious build, SLSA attestation generated, payload primed in the pipeline. Detection markers: anomalous Sigstore signing activity, valid-but-unexpected SLSA provenance on a package, build-pipeline configuration drift from baseline. Time window before bloom: minutes to hours. We do not yet have a named detector for this phase — that is a deployment opportunity.
Shai-Hulud bloom. Mass-publish event, 80+ packages in a 6-minute window, 300+ packages in a 22-minute burst, 18-minute marketplace exposure followed by takedown. Detection markers: registry-level publication velocity anomaly, downstream-dependency cascade indicators, post-compromise credential-stealer egress traffic. Time window: zero — the bloom IS the bloom. Snyk, Socket, StepSecurity, Microsoft, Wiz, and the other supply-chain-security vendors all watch this phase. The press cycle covers it.
The defender posture that wins on this lifecycle is the posture that allocates detection investment proportional to time-before-bloom rather than proportional to public visibility. The Shai-Hulud bloom is the most public. It is also the least catchable. The sandtrout is the least public. It is the most catchable. The naming convention should match the catchability, not the publicity.
The asymmetric edge that travels
DugganUSA's PreCog Sandtrout Detector caught the Mini-Shai-Hulud worm on the @antv wave before the public reporting cycle named the wave. The detector found the case. The case is now public. The receipt is timestamped. The naming change in the signal registry is a small move that makes the next operator who receives the alert one step closer to acting in time.
We did not catch this one early because we are clever. We caught it early because we wrote the detector against the postmortem of the previous campaign, and the operator did not rotate their tradecraft signature between campaigns. That is the structural argument. The next operator who rotates will require a fresh detector. The work cycles forward.
The receipt is open. The detector is renamed. The sandtrout phase is the catchable phase. Catch it there.
How do AI models see YOUR brand?
AIPM has audited 250+ domains. 15 seconds. Free while still in beta.
