A coordinated supply-chain attack comprising 9 npm packages published by maintainer polymarketdev (GitHub actor texsellix, repo texsellix/polymarket-trading-bot) within a ~2-minute window on 2026-05-20T23:30Zā23:32Z. All packages masquerade as legitimate Polymarket CLOB trading tools while exfiltrating Ethereum private keys to a Cloudflare Worker C2 at https://polymarketbot.polymarketdev.workers.dev/v1/wallets/keys.
Kill chain:
- The postinstall hook (scripts/postinstall.mjs) probes for an interactive TTY. On non-interactive shells (CI/CD scanners), it prints "polybot installed" and exits to evade automated analysis.
- Interactive path: displays a masked readline prompt soliciting the wallet private key.
- Passive path: reads .env files in the current working directory and extracts the PRIVATE_KEY environment variable with no user interaction ā developers who keep PRIVATE_KEY in their environment lose it silently.
- Local persistence: creates ~/.polybot/ (mode 0700) containing device.json (UUID + creation timestamp) and wallets.json (Ethereum address + keccak256 fingerprint + pushedAt timestamp).
- Exfiltration: POSTs { privateKey, label } as plain JSON over HTTPS to the C2, with header x-polybot-device: <UUID> for device fingerprinting.
Distinctive fingerprint: All 9 packages ship a byte-identical dist/index.js (711 KB, SHA-256 e01b85c1437085a519217338fe4ee5ed7858c28a10f8c1477b2f1857c3386edb) ā only the name field in package.json differs across packages. The bundle wraps the real Polymarket CLOB SDK, ethers.js, Zod, pino, and WebSocket to provide working scan / quote / trade / copy commands as cover for credential theft. The banner falsely claims private keys "stay encrypted."
Targeting: polymarket-claude-code and polymarket-ai-agent are named to surface in LLM-assisted coding workflows that recommend packages without provenance evaluation.
polymarket-ai-agent is named to surface in AI agent / LLM-assisted developer workflows. Same provenance-targeting rationale as polymarket-claude-code. Payload is identical to the rest of the campaign.
{
"malicious-packages-origins": null
}