Open Source ·

AntV ecosystem npm packages hit by TeamPCP

On 2026-05-19, TeamPCP took the shared atool npm account and published 639 malicious versions across 323 packages — most of the @antv ecosystem and a long tail of standalone neighbors. The bun-based dropper harvested CI/CD secrets and self-propagated via npm.

Part of Shai-Hulud hits npm and PyPI campaign

Hundreds of npm packages from Alibaba's @antv data-visualization stack, plus a long tail of widely used JavaScript utilities that happened to share the same maintainer account, were hijacked over a 90-minute stretch on the morning of May 19, 2026, and republished as a self-spreading credential stealer.

The packages were all owned by an npm account called atool, the shared publishing handle behind the @antv namespace, several smaller scopes, and a grab-bag of standalone libraries including echarts-for-react, timeago.js, and size-sensor. Researchers at Socket, who first reported the activity, said the attacker pushed 639 malicious versions across 323 packages in two automated waves between 01:39 and 02:56 UTC; npm's own publication records still account for 566 of those versions across 283 packages, in two bursts at 01:56 and 02:05. SafeDep and StepSecurity confirmed roughly the same scope. Wiz, which named the attacker TeamPCP, said the broader "Mini Shai-Hulud" wave that day reached 1,055 versions across 502 packages spanning npm, PyPI, and Composer, most of it driven by this single compromised account.

According to Socket, the attacker used two delivery paths. Most packages had their package.json rewritten with a preinstall or postinstall of bun run index.js, with the script dropped at the package root. A second set instead pointed at a poisoned commit in the antvis/G2 GitHub repository through optionalDependencies, where a prepare hook ran the same code. The payload was a half-megabyte, heavily obfuscated Bun script that walked the disk for credentials covering every major cloud provider, Kubernetes, HashiCorp Vault, SSH, and database connection files, then read /proc/*/mem on GitHub Actions runners to pull masked CI/CD secrets out of the Runner.Worker process in plaintext. It behaved like a worm: given any usable npm token, it would validate the credential, enumerate every package the account could publish, fetch each package's latest tarball, inject the same dropper, and republish. Exfiltration ran to t.m-kosche.com over HTTPS disguised as OpenTelemetry trace traffic, with bodies wrapped in AES-256-GCM and RSA-OAEP, falling back to GitHub itself when that channel failed and committing harvested data to public repositories on stolen developer accounts. Socket counted between 2,200 and 2,500 such repositories by the end of the day. On infected hosts the payload also rewrote editor and CI configuration files and, on macOS, registered a LaunchAgent for a backdoor named kitty.

Socket said it flagged most malicious versions within six to twelve minutes of publish, with a median of 6.7 minutes, and npm reclassified them as known malware. Wiz attributed the operation to TeamPCP at moderate confidence based on shared infrastructure, the firedalazer dead-drop tag, payload kinship with other campaigns, and reuse of the kitty backdoor and Dune-themed repositories elsewhere in the same wave. The same backdoor surfaced a few hours later in the Nx Console VS Code extension compromise (see [[nx-console]]), and Wiz said credentials stolen in the @antv wave were later used to publish a malicious Microsoft Python SDK to PyPI (see [[durabletask-pypi]]). The cross-ecosystem aggregate lives on [[shai-hulud-here-we-go-again]]; this record holds the @antv-account evidence.

Notes

  • Compromised maintainer was the shared npm account atool per Socket. Wiz tracked the same account's GitHub credentials being reused to enter the microsoft/durabletask-python repository later the same day.
  • The per-package version lists here were derived from npm's own publication times rather than from a published table. Publication stamps for the affected scopes fall into two tight bursts, 283 releases at 01:56 UTC and 283 more at 02:05 to 02:06 UTC, one per package in each. Those 566 versions across 283 packages are recorded as affected, against Socket's count of 639 across 323. The shortfall is packages whose npm records are gone entirely, leaving no publication time to read. Spot checks against StepSecurity's published examples agree exactly.
  • Three releases on the same day fall outside the bursts, at 01:44, 01:47, and 01:49 UTC, and are still served by npm. Their archives were downloaded and contain none of the campaign's files and no reference to its collection host, so they are recorded as clean pre-attack baselines rather than affected versions. A window drawn from the 01:39 start time some reports give would have swept them in.
  • Socket's count of 639 weaponized versions across 323 unique packages is the most inclusive published number. Lower counts elsewhere (SafeDep 637/314, StepSecurity 500+, Wiz 400+ @antv) reflect earlier or scope-limited tallies. The atool account maintained 547 packages total. The broader same-day Mini Shai-Hulud total per Socket was 1,055 versions across 502 unique packages spanning npm, PyPI, and Composer.
  • Publishing windows reported differ slightly: SafeDep places the two automated waves at 01:39 to 02:06 UTC; Socket places overall publish activity at 01:56 to 02:56 UTC. Both agree on the May 19 date and the two-wave structure.
  • Compromised maintainer was the shared atool npm account, email i@hust.cc, associated with @antv, @lint-md, @openclaw-cn, @starmind scopes plus a long tail of standalone JavaScript and tooling packages.
  • SafeDep notes the payload is identical to the Mini Shai-Hulud toolkit used in the earlier SAP compromise the same week.
  • Wiz also reported same-day compromises of the GitHub Actions actions-cool/issues-helper and actions-cool/maintain-one-comment using shared infrastructure, plus the nrwl.angular-console VS Code extension v18.95.0 (tracked separately as nx-console).

Appendix · Affected releases

@antv/a8 npm
0.1.1 no sample yet
0.2.1 no sample yet
0.3.5 no sample yet
0.4.5 no sample yet
0.2.26 no sample yet
0.3.26 no sample yet
2.3.9 no sample yet
2.4.9 no sample yet
0.4.5 no sample yet
0.5.5 no sample yet
@antv/ava npm
3.5.1 no sample yet
3.6.1 no sample yet
3.4.2 no sample yet
3.5.2 no sample yet
0.1.9 no sample yet
0.2.9 no sample yet
1.2.2 no sample yet
1.3.2 no sample yet
1.2.6 no sample yet
1.3.6 no sample yet
0.1.4 no sample yet
0.2.4 no sample yet
0.2.3 no sample yet
0.3.3 no sample yet
@antv/ckb npm
2.1.4 no sample yet
2.2.4 no sample yet
0.3.3 no sample yet
0.4.3 no sample yet
2.1.6 no sample yet
2.2.6 no sample yet
2.2.11 no sample yet
2.3.11 no sample yet
0.5.7 no sample yet
0.6.7 no sample yet
1.1.0 no sample yet
1.2.0 no sample yet
1.1.3 no sample yet
1.2.3 no sample yet
1.1.1 no sample yet
1.2.1 no sample yet
0.12.8 no sample yet
0.13.8 no sample yet
2.1.4 no sample yet
2.2.4 no sample yet
0.1.4 no sample yet
0.2.4 no sample yet
0.3.1 no sample yet
0.4.1 no sample yet
1.1.10 no sample yet
1.2.10 no sample yet
2.1.4 no sample yet
2.2.4 no sample yet
0.9.4 no sample yet
0.10.4 no sample yet
1.2.5 no sample yet
1.3.5 no sample yet
1.2.7 no sample yet
1.3.7 no sample yet
1.2.7 no sample yet
1.3.7 no sample yet
1.2.4 no sample yet
1.3.4 no sample yet
0.2.3 no sample yet
0.3.3 no sample yet
1.1.2 no sample yet
1.2.2 no sample yet
0.1.0 no sample yet
0.2.0 no sample yet
1.11.0 no sample yet
1.12.0 no sample yet
1.11.0 no sample yet
1.12.0 no sample yet
1.11.0 no sample yet
1.12.0 no sample yet
1.11.0 no sample yet
1.12.0 no sample yet
1.1.9 no sample yet
1.2.9 no sample yet
1.11.0 no sample yet
1.12.0 no sample yet
1.11.0 no sample yet
1.12.0 no sample yet
@antv/f2 npm
5.15.0 no sample yet
5.16.0 no sample yet
5.8.0 no sample yet
5.9.0 no sample yet
1.1.5 no sample yet
1.2.5 no sample yet
0.1.1 no sample yet
0.2.1 no sample yet
0.1.16 no sample yet
0.2.16 no sample yet
4.1.52 no sample yet
4.2.52 no sample yet
5.15.0 no sample yet
5.16.0 no sample yet
4.1.42 no sample yet
4.2.42 no sample yet
4.1.33 no sample yet
4.2.33 no sample yet
5.15.0 no sample yet
5.16.0 no sample yet
4.1.51 no sample yet
4.2.51 no sample yet
@antv/f6 npm
0.1.19 no sample yet
0.2.19 no sample yet
0.1.7 no sample yet
0.2.7 no sample yet
0.1.2 no sample yet
0.2.2 no sample yet
0.1.1 no sample yet
0.2.1 no sample yet
0.1.2 no sample yet
0.2.2 no sample yet
1.1.6 no sample yet
1.2.6 no sample yet
1.1.3 no sample yet
1.2.3 no sample yet
0.1.7 no sample yet
0.2.7 no sample yet
@antv/g npm
6.4.1 no sample yet
6.5.1 no sample yet
0.6.16 no sample yet
0.7.16 no sample yet
2.1.45 no sample yet
2.2.45 no sample yet
2.3.0 no sample yet
2.4.0 no sample yet
1.2.1 no sample yet
1.3.1 no sample yet
1.1.11 no sample yet
1.2.11 no sample yet
2.1.42 no sample yet
2.2.42 no sample yet
1.1.38 no sample yet
1.2.38 no sample yet
1.1.38 no sample yet
1.2.38 no sample yet
1.7.13 no sample yet
1.8.13 no sample yet
2.1.42 no sample yet
2.2.42 no sample yet
3.1.42 no sample yet
3.2.42 no sample yet
1.1.42 no sample yet
1.2.42 no sample yet
1.8.49 no sample yet
1.9.49 no sample yet
2.8.0 no sample yet
2.9.0 no sample yet
1.2.1 no sample yet
1.3.1 no sample yet
3.2.0 no sample yet
3.3.0 no sample yet
1.2.5 no sample yet
1.3.5 no sample yet
1.2.1 no sample yet
1.3.1 no sample yet
1.1.42 no sample yet
1.2.42 no sample yet
1.2.1 no sample yet
1.3.1 no sample yet
1.2.1 no sample yet
1.3.1 no sample yet
2.1.42 no sample yet
2.2.42 no sample yet
1.1.0 no sample yet
1.2.0 no sample yet
2.2.1 no sample yet
2.3.1 no sample yet
1.5.1 no sample yet
1.6.1 no sample yet
1.3.0 no sample yet
1.4.0 no sample yet
2.2.1 no sample yet
2.3.1 no sample yet
2.2.26 no sample yet
2.3.26 no sample yet
2.4.1 no sample yet
2.5.1 no sample yet
2.6.1 no sample yet
2.7.1 no sample yet
2.4.1 no sample yet
2.5.1 no sample yet
2.2.1 no sample yet
2.3.1 no sample yet
2.2.1 no sample yet
2.3.1 no sample yet
2.7.1 no sample yet
2.8.1 no sample yet
2.2.31 no sample yet
2.3.31 no sample yet
2.2.1 no sample yet
2.3.1 no sample yet
2.2.1 no sample yet
2.3.1 no sample yet
1.10.20 no sample yet
1.11.20 no sample yet
2.4.1 no sample yet
2.5.1 no sample yet
2.4.1 no sample yet
2.5.1 no sample yet
2.2.1 no sample yet
2.3.1 no sample yet
1.1.42 no sample yet
1.2.42 no sample yet
2.2.1 no sample yet
2.3.1 no sample yet
2.2.1 no sample yet
2.3.1 no sample yet
2.2.1 no sample yet
2.3.1 no sample yet
2.1.46 no sample yet
2.2.46 no sample yet
2.5.1 no sample yet
2.6.1 no sample yet
1.10.17 no sample yet
1.11.17 no sample yet
1.1.26 no sample yet
1.2.26 no sample yet
1.10.17 no sample yet
1.11.17 no sample yet
2.4.1 no sample yet
2.5.1 no sample yet
2.2.1 no sample yet
2.3.1 no sample yet
2.2.1 no sample yet
2.3.1 no sample yet
2.1.0 no sample yet
2.2.0 no sample yet
2.2.1 no sample yet
2.3.1 no sample yet
2.2.32 no sample yet
2.3.32 no sample yet
2.2.1 no sample yet
2.3.1 no sample yet
2.2.1 no sample yet
2.3.1 no sample yet
0.1.1 no sample yet
0.2.1 no sample yet
2.2.1 no sample yet
2.3.1 no sample yet
0.8.2 no sample yet
0.9.2 no sample yet
0.8.2 no sample yet
0.9.2 no sample yet
0.8.2 no sample yet
0.9.2 no sample yet
0.6.1 no sample yet
0.7.1 no sample yet
0.6.1 no sample yet
0.7.1 no sample yet
@antv/g2 npm
5.5.8 no sample yet
5.6.8 no sample yet
0.1.2 no sample yet
0.2.2 no sample yet
0.3.0 no sample yet
0.4.0 no sample yet
0.3.0 no sample yet
0.4.0 no sample yet
0.3.2 no sample yet
0.4.2 no sample yet
2.2.1 no sample yet
2.3.1 no sample yet
0.3.0 no sample yet
0.4.0 no sample yet
2.5.35 no sample yet
2.6.35 no sample yet
1.3.2 no sample yet
1.4.2 no sample yet
@antv/g6 npm
5.2.1 no sample yet
5.3.1 no sample yet
0.1.1 no sample yet
0.2.1 no sample yet
0.1.4 no sample yet
0.2.4 no sample yet
0.9.24 no sample yet
0.10.24 no sample yet
1.3.0 no sample yet
1.4.0 no sample yet
0.9.25 no sample yet
0.10.25 no sample yet
0.2.23 no sample yet
0.3.23 no sample yet
0.3.7 no sample yet
0.4.7 no sample yet
0.2.2 no sample yet
0.3.2 no sample yet
0.9.25 no sample yet
0.10.25 no sample yet
0.9.25 no sample yet
0.10.25 no sample yet
0.1.4 no sample yet
0.2.4 no sample yet
1.1.9 no sample yet
1.2.9 no sample yet
1.5.8 no sample yet
1.6.8 no sample yet
0.2.1 no sample yet
0.3.1 no sample yet
0.1.1 no sample yet
0.2.1 no sample yet
0.2.0 no sample yet
0.3.0 no sample yet
1.1.8 no sample yet
1.2.8 no sample yet
2.6.22 no sample yet
2.7.22 no sample yet
2.4.19 no sample yet
2.5.19 no sample yet
2.5.40 no sample yet
2.6.40 no sample yet
1.3.15 no sample yet
1.4.15 no sample yet
2.2.15 no sample yet
2.3.15 no sample yet
1.2.15 no sample yet
1.3.15 no sample yet
1.2.15 no sample yet
1.3.15 no sample yet
2.2.15 no sample yet
2.3.15 no sample yet
2.3.21 no sample yet
2.4.21 no sample yet
2.2.15 no sample yet
2.3.15 no sample yet
0.3.15 no sample yet
0.4.15 no sample yet
0.2.30 no sample yet
0.3.30 no sample yet
1.3.11 no sample yet
1.4.11 no sample yet
1.4.16 no sample yet
1.5.16 no sample yet
1.1.5 no sample yet
1.2.5 no sample yet
1.1.1 no sample yet
1.2.1 no sample yet
3.1.0 no sample yet
3.2.0 no sample yet
1.3.10 no sample yet
1.4.10 no sample yet
0.7.11 no sample yet
0.8.11 no sample yet
0.2.0 no sample yet
0.3.0 no sample yet
2.8.1 no sample yet
2.9.1 no sample yet
1.1.0 no sample yet
1.2.0 no sample yet
0.4.7 no sample yet
0.5.7 no sample yet
3.1.5 no sample yet
3.2.5 no sample yet
2.5.1 no sample yet
2.6.1 no sample yet
1.1.5 no sample yet
1.2.5 no sample yet
1.1.0 no sample yet
1.2.0 no sample yet
2.1.4 no sample yet
2.2.4 no sample yet
0.8.1 no sample yet
0.9.1 no sample yet
0.3.19 no sample yet
0.4.19 no sample yet
0.2.5 no sample yet
0.3.5 no sample yet
0.1.0 no sample yet
0.2.0 no sample yet
1.2.4 no sample yet
1.3.4 no sample yet
@antv/l7 npm
2.26.10 no sample yet
2.27.10 no sample yet
2.26.10 no sample yet
2.27.10 no sample yet
0.18.1 no sample yet
0.19.1 no sample yet
2.26.10 no sample yet
2.27.10 no sample yet
2.4.12 no sample yet
2.5.12 no sample yet
3.2.5 no sample yet
3.3.5 no sample yet
1.2.13 no sample yet
1.3.13 no sample yet
1.1.0 no sample yet
1.2.0 no sample yet
2.26.10 no sample yet
2.27.10 no sample yet
1.1.2 no sample yet
1.2.2 no sample yet
2.26.10 no sample yet
2.27.10 no sample yet
0.6.0 no sample yet
0.7.0 no sample yet
2.26.10 no sample yet
2.27.10 no sample yet
2.21.8 no sample yet
2.22.8 no sample yet
1.1.0 no sample yet
1.2.0 no sample yet
2.5.3 no sample yet
2.6.3 no sample yet
2.26.10 no sample yet
2.27.10 no sample yet
2.26.10 no sample yet
2.27.10 no sample yet
2.26.10 no sample yet
2.27.10 no sample yet
2.26.10 no sample yet
2.27.10 no sample yet
2.26.10 no sample yet
2.27.10 no sample yet
0.6.11 no sample yet
0.7.11 no sample yet
0.1.11 no sample yet
0.2.11 no sample yet
1.6.1 no sample yet
1.7.1 no sample yet
1.2.7 no sample yet
1.3.7 no sample yet
1.5.2 no sample yet
1.6.2 no sample yet
0.5.7 no sample yet
0.6.7 no sample yet
1.10.1 no sample yet
1.11.1 no sample yet
1.4.7 no sample yet
1.5.7 no sample yet
1.7.1 no sample yet
1.8.1 no sample yet
1.9.2 no sample yet
1.10.2 no sample yet
0.2.4 no sample yet
0.3.4 no sample yet
1.6.1 no sample yet
1.7.1 no sample yet
2.2.1 no sample yet
2.3.1 no sample yet
3.1.4 no sample yet
3.2.4 no sample yet
0.2.8 no sample yet
0.3.8 no sample yet
0.10.10 no sample yet
0.11.10 no sample yet
2.2.7 no sample yet
2.3.7 no sample yet
0.2.1 no sample yet
0.3.1 no sample yet
0.3.20 no sample yet
0.4.20 no sample yet
0.4.7 no sample yet
0.5.7 no sample yet
0.4.16 no sample yet
0.5.16 no sample yet
3.1.1 no sample yet
3.2.1 no sample yet
2.2.1 no sample yet
2.3.1 no sample yet
@antv/s2 npm
2.8.1 no sample yet
2.9.1 no sample yet
2.4.1 no sample yet
2.5.1 no sample yet
2.2.2 no sample yet
2.3.2 no sample yet
0.2.1 no sample yet
0.3.1 no sample yet
2.3.0 no sample yet
2.4.0 no sample yet
@antv/sam npm
0.3.0 no sample yet
0.4.0 no sample yet
0.6.2 no sample yet
0.7.2 no sample yet
1.1.4 no sample yet
1.2.4 no sample yet
0.3.1 no sample yet
0.4.1 no sample yet
0.1.2 no sample yet
0.2.2 no sample yet
@antv/t8 npm
0.4.0 no sample yet
0.5.0 no sample yet
2.1.0 no sample yet
2.2.0 no sample yet
2.1.0 no sample yet
2.2.0 no sample yet
1.1.6 no sample yet
1.2.6 no sample yet
1.1.1 no sample yet
1.2.1 no sample yet
3.4.11 no sample yet
3.5.11 no sample yet
1.1.11 no sample yet
1.2.11 no sample yet
0.2.1 no sample yet
0.3.1 no sample yet
1.1.0 no sample yet
1.2.0 no sample yet
0.4.4 no sample yet
0.5.4 no sample yet
2.2.1 no sample yet
2.3.1 no sample yet
@antv/x6 npm
3.2.7 no sample yet
3.3.7 no sample yet
3.1.1 no sample yet
3.2.1 no sample yet
2.1.17 no sample yet
2.2.17 no sample yet
0.11.7 no sample yet
0.12.7 no sample yet
2.1.5 no sample yet
2.2.5 no sample yet
2.2.1 no sample yet
2.3.1 no sample yet
2.2.6 no sample yet
2.3.6 no sample yet
2.3.4 no sample yet
2.4.4 no sample yet
2.3.3 no sample yet
2.4.3 no sample yet
2.1.7 no sample yet
2.2.7 no sample yet
2.1.10 no sample yet
2.2.10 no sample yet
2.3.2 no sample yet
2.4.2 no sample yet
2.2.7 no sample yet
2.3.7 no sample yet
2.2.5 no sample yet
2.3.5 no sample yet
2.2.8 no sample yet
2.3.8 no sample yet
0.2.26 no sample yet
0.3.26 no sample yet
2.1.9 no sample yet
2.2.9 no sample yet
3.1.1 no sample yet
3.2.1 no sample yet
1.5.2 no sample yet
1.6.2 no sample yet
3.1.2 no sample yet
3.2.2 no sample yet
1.1.0 no sample yet
1.2.0 no sample yet
2.2.13 no sample yet
2.3.13 no sample yet
1.1.0 no sample yet
1.2.0 no sample yet
2.1.0 no sample yet
2.2.0 no sample yet
2.1.0 no sample yet
2.2.0 no sample yet
0.1.14 no sample yet
0.2.14 no sample yet
2.1.4 no sample yet
2.2.4 no sample yet
3.1.7 no sample yet
3.2.7 no sample yet
2.6.3 no sample yet
2.7.3 no sample yet
1.1.11 no sample yet
1.2.11 no sample yet
1.1.4 no sample yet
1.2.4 no sample yet
4.1.2 no sample yet
4.2.2 no sample yet

Indicators

  • fileindex.js
  • commandbun run index.js
  • file~/.local/share/kitty/cat.py
  • file~/Library/LaunchAgents/com.user.kitty-monitor.plist
  • file~/.config/systemd/user/kitty-monitor.service
  • file.claude/settings.json
  • file.claude/setup.mjs
  • file.vscode/tasks.json
  • file.vscode/setup.mjs
  • file.github/workflows/codeql.yml
  • domaint.m-kosche.com
  • domainm-kosche.com
  • ipv4185.95.159.32
  • urlhttps://t.m-kosche.com:443/api/public/otel/v1/traces
  • tagfiredalazer
  • tagniagA oG eW ereH :duluH-iahS
  • file_sha256cat.py: fb5c97557230a27460fdab01fafcfabeaa49590bafd5b6ef30501aa9e0a51142
  • file_sha1cat.py: 783b4019fc5b942a29846132d28441c8fc31bed8
  • file_md5cat.py: b06b126b9e26af03a7ef2f8b8e90d446
  • accountatool (npm)

References

  1. Mini Shai-Hulud: TeamPCP Hits @antv Supply Chain - Wizwiz.io
  2. Shai-Hulud Here We Go Again - Mass npm Supply Chain Attack Hits the AntV Ecosystem - StepSecuritystepsecurity.io
  3. @antv Packages Compromised - Socketsocket.dev

Source record: oss/attacks/antv-npm/meta.yaml