The Incident
On May 22, 2026 at 20:20:18 UTC, Socket observed the first artifact of what is now tracked as the TrapDoor campaign: the PyPI package [email protected]. Over the following days TrapDoor expanded to 34 malicious packages across npm (21), PyPI (7), and Crates.io (6), totaling 384 artifact versions. The packages impersonate development utilities aimed at crypto, DeFi, Solana, Sui, Aptos, and AI developer audiences. Each ecosystem ships an ecosystem-native execution path: postinstall hooks in npm, import-time execution in Python, and build.rs in Rust. The Rust variant searches for Sui and Aptos wallet keystores, encrypts what it finds with the XOR key cargo-build-helper-2026, and exfiltrates to attacker-controlled GitHub Gists.
The novel stage is not the install-time payload. The shared npm payload trap-core.js writes two files into the project tree — .cursorrules and CLAUDE.md — that look blank or benign to a human reviewer. The instructions inside are encoded as runs of zero-width Unicode characters (U+200B, U+200C, U+200D, U+FEFF). When the developer next opens the repository in Cursor or Claude Code, the assistant reads those files as project context, decodes the Unicode stream, and executes what it interprets as a mandatory “security scan” workflow — walking ~/.ssh, ~/.aws, browser profiles, environment variables, and crypto wallet keystores, then exfiltrating the results. The same attacker (ddjidd564 on GitHub) has been opening pull requests against browser-use, langchain, langflow, llama_index, MetaGPT, and OpenHands to seed the same configuration files upstream; GitHub flagged at least one for containing hidden bidirectional Unicode.
MITRE ATT&CK coverage: T1195.002 (Compromise Software Supply Chain), T1027 (Obfuscated Files or Information), T1552.001 (Credentials in Files), T1552.004 (Private Keys), T1567 (Exfiltration Over Web Service).
The Authority Path That Failed
The identity that carried execution authority at the moment of failure was the AI coding assistant — Cursor or Claude Code — running inside the developer’s local shell with the developer’s filesystem and token scope. Its held scope was broad by design: read project files, propose and execute shell commands, traverse ~/.ssh, ~/.aws, ~/.config, browser stores, and crypto keystores. That is what the operator granted the assistant for ordinary “help me build this” use. Its exercised scope at the moment of failure was a credential-harvest workflow that swept the filesystem outside the project tree, encrypted the results, and posted them to GitHub Gists. The operator never approved that workflow.
The trust anchor that failed first was the implicit treatment of .cursorrules and CLAUDE.md as authoritative project context. The assistant pulls those files from whatever the project tree contains — a freshly installed npm dependency, a cloned repo with an unreviewed PR — without provenance checks, without a signed approval gate, and without Unicode normalization that would surface zero-width payloads. The postinstall hook is the delivery vector; the agent’s failure is to elevate file-tree contents to instruction context. Phoenix Security’s April 2026 disclosure of three CWE-78 OS command-injection flaws in Claude Code CLI (CVE-2026-35020, CVE-2026-35021, CVE-2026-35022) is the amplifier: post-injection, the agent’s already-broad shell access reaches reliable code execution sinks.
SecurityV0 Perspective
This is a scope_drift finding. The agent held the authority to read sensitive paths and run shell commands; it exercised that authority against a workflow its operator never approved. The steganographic delivery — instructions invisible to the developer reviewing the diff — is the mechanism, not the root cause. The root cause is that AI coding assistants treat any .cursorrules or CLAUDE.md in the project tree as policy, with no provenance check and no separation between files the operator wrote and files a dependency dropped.
The evidence pack SecurityV0 would produce maps every AI-assistant policy file (.cursorrules, CLAUDE.md, AGENTS.md, MCP configs) in the developer’s checkout, hashes each against an expected baseline, and runs a Unicode-normalization pass that surfaces zero-width and bidirectional sequences. Alongside that, a scope manifest enumerates which assistant identity holds which filesystem and token capabilities, and an enforcement gate requires explicit operator approval before the assistant runs any workflow whose targets fall outside the working tree. Pre-exfiltration, the pack answers: did any agent session run a credential sweep, and which policy file authorized it? Post-exfiltration, the same pack answers: what was that file’s provenance, when did it land in the tree, and which non-human identities were enumerated before the call to GitHub Gists?
What To Do
- Normalize Unicode in agent policy files before treating them as instructions. Any tool that parses
.cursorrules,CLAUDE.md,AGENTS.md, or MCP configuration should strip or surfaceU+200B,U+200C,U+200D,U+FEFF, and bidirectional controls. Until vendors ship that, gate it yourself with a pre-commit hook and a CI step that fails when those code points appear in agent config paths. - Treat AI-assistant config files as code, not data. Put
.cursorrules,CLAUDE.md,.claude/,.cursor/, and MCP config under CODEOWNERS review, block first-time contributors from modifying them, and alert whennpm install,pip install, orcargo buildwrites or changes any of them. - Constrain agent scope to the working tree by default. Configure Cursor and Claude Code so filesystem access outside the project directory —
~/.ssh,~/.aws,~/.config, browser stores, wallet keystores — requires explicit per-session operator approval. Do not let a project-local rules file silently extend the agent’s reach into the home directory. - Audit fresh checkouts before opening an AI editor. Run a static check for project-context files dropped by dependencies before launching Cursor or Claude Code on a fresh clone or after
npm install/pip install/cargo build. Files such as.cursorrulesorCLAUDE.mdshould never appear as a side effect of a package install. - Rotate every credential that touched a Cursor or Claude Code session this week. If a TrapDoor package appeared in any dependency tree installed since May 22, 2026, treat SSH keys, AWS/GCP/Azure tokens, GitHub PATs, browser-stored credentials, and crypto wallet keystores as compromised. Revoke, rotate, and re-issue from a clean machine.
Sources
- Socket — TrapDoor Crypto Stealer Supply Chain Attack Hits 34 Packages
- Phoenix Security — TrapDoor Supply Chain Campaign: AI Assistant Poisoning
- The Hacker News — TrapDoor Supply Chain Attack Spreads Credential-Stealing Malware
- Socradar — TrapDoor: Malicious npm, PyPI, Crates.io Packages Target Developer Secrets & AI Tooling
- Cyberpress — Supply Chain Attack Compromises 34 Packages
- Cybersecurity News — Hackers Compromised 34 Packages in npm, PyPI, and Crates
- Technadu — TrapDoor Supply Chain Attack Targets npm, PyPI, and Crates.io
- NVD — CVE-2026-35021
- NVD — CVE-2026-35022
- Phoenix Security — Three CVEs in Claude Code CLI (CVE-2026-35020/35021/35022)
- MITRE ATT&CK: T1195.002, T1027, T1552/001, T1552/004, T1567