← all case studies Case study · npm · worm

What Mini Shai-Hulud
taught our firewall.

One stolen npm token poisoned 323 packages across the AntV namespace in 27 minutes, with a credential harvester wired to run before any user script. No CVE existed. Here is the timeline, when CyberXYZ blocked it (after Endor Labs' public disclosure, not before) and what we changed.

Live attack · case study

The Mini Shai-Hulud worm,
and where the firewall stops it.

Between 01:39 and 02:06 UTC on May 19, 2026, a single stolen npm publish token pushed malicious versions of dozens of packages across the AntV namespace and several widely used test libraries. Each one ran a credential harvester before any user script. No CVE existed. Here is the timeline, and where CyberXYZ blocks it. CyberXYZ did not catch this wave early: our npm publish stream was 42 million messages behind and first saw jest-canvas-mock@2.5.3 about 36 hours after it was published. We blocked it from Endor Labs' disclosure: the packages reached our block list 5 h 51 min after Endor Labs published.

323packages poisoned
639malicious versions
27 minpublish window
6credential stores targeted
  1. 01:39 UTC

    A stolen publish token goes live

    A single compromised npm publish token starts shipping. The first trigger package, jest-canvas-mock@2.5.3, looks ordinary, but it carries an optionalDependencies entry pointing at a raw GitHub commit hash.

  2. 01:39 UTC · what the commit-level signal looks for

    A phantom commit drops the payload

    The referenced commit (github:antvis/G2#1916faa…) exists on no branch. npm resolves it, downloads it, and runs its prepare script on install. A dependency that resolves to a commit on no branch is the pattern CyberXYZ's commit-level signal looks for.

  3. 01:44 UTC

    A second trigger lands

    size-sensor@1.0.4 ships with the same phantom-commit technique. Two unrelated, widely used packages now both carry the dropper.

  4. 01:56 UTC · what the script scan looks for

    The namespace is flooded

    A burst of 14 packages publishes at once, including @antv/g6, @antv/scale, timeago.js and echarts-for-react. Each embeds a roughly 500 KB obfuscated index.js wired to "preinstall":"bun run index.js", so it runs before any user script can inspect it.

  5. on execution (had it run)

    What it would have stolen

    The payload enumerates the environment, hits the AWS metadata endpoint at 169.254.169.254, and harvests GitHub, AWS, GCP, Kubernetes, Vault and npm credentials, then exfiltrates them to t.m-kosche.com disguised as OpenTelemetry traces on port 443.

  6. the novel part

    Sigstore provenance forgery

    On a CI runner the payload mints a fresh GitHub Actions OIDC token and signs through public Sigstore, producing a package that appears to carry a valid provenance badge with no genuine link to the project. A signature alone is no longer proof.

  7. 02:22 UTC

    The first public disclosure lands

    Endor Labs publishes the initial write-up; Socket Threat Research later counts 639 malicious versions across 323 packages in this wave alone.

  8. 08:57 UTC · after the disclosure

    BLOCK, at install time

    The named packages were added to CyberXYZ's block list at 08:13 UTC from Endor Labs' disclosure, 5 h 51 min after it was published, and the first real block of jest-canvas-mock@2.5.3 came at 08:57 UTC. From then on, installing a listed version through the proxy returns 403, CI gates fail and the editor flags it.

  9. afterwards

    What we changed

    We backfilled 28 named packages into the malicious-package corpus, added six indicators (the exfil domain, the spoofed author marker, two phantom commit SHAs and the payload hash), moved 2,233 npm packages with over a million monthly downloads onto 15-minute polling, and restored the npm publish stream, which had fallen 42 million messages behind. The technical write-up has the detail.

Blocked at install

What the proxy returned
for the trigger package.

This is the real record from CyberXYZ's install log: one internal test install, blocked at 08:57 UTC on May 19, after Endor Labs' disclosure. The full IOC table (package/version pairs, C2 domains, commit SHAs) is in the technical write-up.

app.cyberxyz.io/proxy/findings
Search package, IP, OS…All typesAll risk levels live
May 19, 08:57 UTCnpmjest-canvas-mock@2.5.3BLOCKEDdev laptop DEV macOSinternalCRITICAL

fig. 01 · proxy findings · the real block, an internal test install, 7 h 18 min after the trigger package was published

app.cyberxyz.io/notifications
illustrationnot a recorded notification

Blocked install: jest-canvas-mock@2.5.3 on gha/runner · GitHub Actions

0/10
RISK SCORE critical · verdict block
SIGNALS
BLAST RADIUS0 packages · 0 malicious versions
jest-canvas-mock@2.5.3size-sensor@1.0.4@antv/* · 40 packages
STATEMENTEcosystem npm · decision block (confidence 1.0) · stolen publish token · no safe version, rotate credentials
SIGNALS · 4 described
01Script & Tarball ScantriggeredCRITICAL

A ~500 KB obfuscated index.js is wired to a preinstall hook (bun run index.js) so it executes before any user script.

02Commit-Level AnalysistriggeredCRITICAL

optionalDependencies resolves to a raw GitHub commit that exists on no branch and only delivers the payload via the prepare hook.

03Credential & Exfil BehaviortriggeredCRITICAL

Reads the AWS metadata endpoint 169.254.169.254 and harvests GitHub, AWS, GCP, Vault and npm secrets, exfiltrating to t.m-kosche.com.

04Live Threat IntelmatchedCRITICAL

Matches the Mini Shai-Hulud campaign: 639 malicious versions across 323 packages in this wave.

PACKAGE CONTEXT
published May 19, 01:39 UTC · trigger package · phantom-commit dropper · preinstall: bun run index.js · exfil to t.m-kosche.com
PACKAGE jest-canvas-mockVERSION 2.5.3ECOSYSTEM npmDECISION BLOCK

fig. 02 · illustration · how the signals described above present the trigger package. They did not fire on May 19: the real block came from a known-malicious-version match added from Endor Labs' disclosure. The score is illustrative

Sources: CyberXYZ threat intelligence, with Endor Labs and Socket Threat Research disclosures (May 19, 2026). Full technical write-up on the CyberXYZ blog.

// book a demo

Watch it block a real attack. Then run it on your own installs.

Book 15 minutes. We run real packages through CyberXYZ while you watch, including axios 1.14.1, a hijacked release that dropped remote-control malware in March 2026, and show you exactly what your team would see. Then we connect one laptop or one pipeline for a 30-day proof of value.

What happens next

  1. 01A 15-minute callReal packages, real verdicts, and your questions.
  2. 02Connect one laptop or one pipelineOne setup command, or one line in CI. Under an hour.
  3. 03A 30-day proof of value on your own installsEvery signal, no card.

Not ready for a call?

Check any package, free, and see the verdict we would give it.

npm

Try faker@6.6.6ua-parser-js@0.7.29express@4.21.2

Thanks! We'll be in touch.

Check your inbox. We'll reach out within 24 hours.

Where should we send the invite?

  • 15 minutes
  • Video call
  • Times in your time zone

We reply within 24 hours to set a time.

We only use these details to arrange the call. Privacy policy