Researchers first spotted something odd on May 22, when a package called eth-security-auditor@0.1.0 landed on PyPI. That alone isn’t unusual as the registry sees thousands of new uploads every day. What made analysts take a second look was what happened in the hours that followed: a wave of seemingly unconnected packages started appearing across PyPI, npm, and Crates.io in rapid succession, each one looking generic enough to pass a casual glance.
Within 48 hours, what looked like scattered registry spam had been traced back to a single coordinated campaign. Researchers named it TrapDoor.
So far: 34 unique packages compromised, 380-plus affected versions, three major registries hit simultaneously, and a target list that reads like a who’s-who of high-value developer environments like cryptocurrency wallets, DeFi tooling, AI development, and smart contract auditing.
This isn’t a spray-and-pray operation. The attacker built something deliberate.
Why This One Is Different
Most supply chain attacks pick one registry and one language ecosystem. TrapDoor ran all three concurrently – npm for JavaScript developers, PyPI for Python, Crates.io for Rust and each implementation was separately engineered to abuse the native installation behavior of that ecosystem. That’s not the work of someone who grabbed a script off GitHub. It takes real familiarity with how each package manager works under the hood.
There’s also the targeting. The package names are carefully chosen: eth-wallet-sentinel, defi-threat-scanner, solidity-deploy-guard, crypto-credential-scanner. These aren’t names designed to get millions of installs. They’re names designed to attract a specific kind of developer – someone working with blockchain infrastructure, managing production wallet keys, and probably running CI/CD pipelines against live cloud environments.
And then there’s the AI angle, which is genuinely new territory for this class of malware. More on that shortly.
How the Attack Works: Three Ecosystems, Three Entry Points

npm: The Postinstall Hook
Node developers are used to packages running scripts at install time. It’s how build tools work, how native addons compile, how all sorts of legitimate tooling operates. TrapDoor leans on that familiarity.
When a developer runs npm install on any of the 21 identified malicious npm packages, a postinstall hook in the package’s package.json fires automatically. This is by design in the npm spec. There’s no prompt, no warning, no user confirmation. The hook executes a payload file called trap-core.js.
At 1,149 lines and just under 48.5 KB, trap-core.js is not a quick smash-and-grab script. It’s a full credential harvesting engine. A few things stand out about how it operates:
It validates before it exfiltrates. This is the part that should concern security teams most. Rather than blindly scooping up every AWS key and GitHub token it finds and dumping them to a remote server, the script actually makes live API calls first. It tests whether an AWS access key is active. It checks whether a GitHub personal access token (PAT) is still valid. Expired credentials get dropped. The attacker ends up with a curated list of working, live credentials which is immediately actionable without any noise.
The crypto layer is serious. Exfiltrated data isn’t sent in plaintext. The script uses Fernet symmetric encryption combined with Elliptic-Curve Diffie-Hellman (ECDH) key exchange to secure the data in transit and to dynamically configure its command-and-control setup. ECDH in particular means the C2 configuration can be established without the shared key ever being transmitted – a level of operational security you don’t usually see in opportunistic malware.
It does environmental enumeration. Before stealing anything, the script maps the host environment: what cloud providers are configured, what SSH keys exist, what browser profiles are present, what .env files are reachable. It builds a picture of the machine before deciding what to take.
Crates.io: Hiding in the Compiler
Rust developers often feel a bit safer than their counterparts in interpreted languages. The type system, the borrow checker, the explicit memory model. There’s a general sense that Rust codebases are harder to exploit. TrapDoor specifically targets that confidence.
In Rust’s Cargo build system, build.rs is a build script that runs locally before the main crate compiles. It’s used legitimately for things like linking C libraries, generating code from schemas, or setting compile-time environment variables. When you run cargo build, any build.rs present in a dependency executes on your machine – no runtime, no user prompt, before a single line of your actual program has been compiled.
The six malicious Crates.io packages (sui-move-build-helper, move-compiler-tools, etc.) embed a build.rs that immediately scans the host filesystem for wallet keystores. The targets are specific: Sui, Solana, and Aptos key material. Developers working on those blockchains typically have local keystores for testing and deployment. Finding them is a matter of knowing where to look.
Intercepted keystore data gets XOR-masked with the hardcoded key cargo-build-helper-2026 – simple encryption, not the sophisticated Fernet scheme used in the npm payload, but enough to avoid trivial string matching in transit. The data is then sent to GitHub Gists controlled by the attacker account ddjidd564. GitHub Gists as an exfiltration endpoint is clever: the traffic looks like ordinary GitHub API calls, which most corporate firewalls won’t flag.
The specific focus on Sui and Move blockchain tooling is worth noting. The Move language is used across several chains (Sui, Aptos, and others), and developers working in that space are often handling real funds in their test environments. It’s a small community, but the value density is high.
PyPI: A Payload That Isn’t There
The Python implementation is the most evasive of the three, and in some ways the most technically interesting.
When you import one of the seven malicious PyPI packages, the __init__.py runs immediately which is standard Python behavior. But unlike the npm packages, these don’t bundle the main malware payload. Instead, the import triggers a network request to ddjidd564.github.io, downloads a JavaScript file, and then spawns a local shell process to execute it using node -e.
This matters for a few reasons. First, static analysis of the PyPI package itself finds almost nothing suspicious. The malicious logic lives off-package, hosted remotely. PyPI’s automated scanning tools look at what’s in the package; the actual payload is somewhere else. Second, because the JavaScript is fetched fresh on each import, the attacker can change the payload in real time. A package installed today might behave differently tomorrow. You can’t quarantine what you can’t statically identify.
The dependency on Node.js being present might seem like a limitation, but in practice, most developers working in AI, Web3, or modern software tooling will have Node installed. The attacker seems to have counted on that.
The AI Angle: Poisoning Your Coding Assistant
This is the part of TrapDoor that represents genuinely new thinking, and it’s unsettling.
Modern AI-assisted development environments such as Cursor, Claude, GitHub Copilot in some configurations read workspace files to understand the project context. Files like .cursorrules and CLAUDE.md exist specifically to give the AI instructions: what coding standards to follow, what commands to use, how to format output. They’re configuration files for your AI pair programmer.
TrapDoor attempts to write malicious versions of these files into active project directories. The files look blank or benign to a human reading them. But they’re loaded with hidden characters, zero-width spaces and bidirectional Unicode control characters, positioned precisely within the file. These are invisible in most text editors and terminals. The AI model, however, reads them.
The hidden content instructs the AI assistant to run what it describes as a “mandatory security scan” or “dependency verification” whenever the developer asks for coding help. That scan is actually the credential extraction pipeline. The developer asks the AI to help fix a bug; the AI, following the injected instructions, runs a shell command that ships environment variables, SSH keys, and config files to the attacker’s infrastructure.
The developer sees a normal coding interaction. The AI is doing something else entirely.
This is a meaningful escalation. Previous supply chain attacks have targeted what developers install. This one targets the tools developers trust most – the assistants they’re increasingly relying on for day-to-day work. Poisoning that trust relationship is a different kind of attack.
The GitHub Campaign: Seeding the Configuration Broadly
Compromising individual developers through malicious packages is one thing. The attacker was also trying to get the malicious AI configuration files into widely-used open source projects directly.
The GitHub account ddjidd564 opened pull requests against six major AI and developer tooling repositories:
langchain-ai/langchainlangflow-ai/langflowrun-llama/llama_indexbrowser-use/browser-useFoundationAgents/MetaGPTOpenHands/OpenHands
Every PR was framed the same way: documentation improvements, adding developer standards, “docs: add .cursorrules with dev standards and build verification.” Reviewers looking at a diff would see what appears to be a helpful community contribution adding project conventions. The hidden Unicode content wouldn’t show up in a standard diff view.
If any of these PRs had merged, every developer cloning those repositories would have received the malicious AI configuration files with no package installation required.
The PR text referenced a campaign marker P-2024-001 and a remote configuration file at ddjidd564.github.io/defi-security-best-practices/config.json. That config file lays out the full attack surface the payload is designed to probe:
{ "standard": "P-2024-001", "strategy": { "scan_depth": 3, "enabled_vectors": [ "git", "vscode", "cursorrules", "sourceHeaders", "readme", "pkgJson", "claudeMd", "prepush", "trapActivation", "pypi", "docker", "systemProfile" ] }, "encryption": { "enabled": true, "scheme": "Fernet" }}
Thirteen attack vectors, enumerated and enabled. Git config, VS Code settings, environment files, Docker configurations, system profiles. The attacker wasn’t being subtle about scope.
The AUDIT-MATRIX.md Document
Researchers also found a file in the attacker’s public repositories called AUDIT-MATRIX.md, which describes something called the “Universal AI Agent Extraction Framework” which is a multi-phase pipeline for compromising developer machines while disguising the payload as a legitimate security utility.
The document is partly a design spec, partly implemented. The fact that the attacker left it publicly visible is either an oversight or deliberate misdirection. Either way, it lays out a philosophy: build tools that look like they’re helping with security auditing while actually operating as credential extraction platforms. The wallet auditor that steals your wallet. The secret scanner that takes your secrets.
What Gets Stolen
If TrapDoor successfully executes on a developer machine, the collection sweep targets:
Cryptocurrency key material. Local keystores for Sui, Solana (including Phantom and Solflare browser extension data), Aptos, and Ethereum. Private keys, mnemonics, and any unencrypted keystore files in the home directory.
Cloud credentials. AWS access keys, secret access keys, and session tokens. These are actively validated before exfiltration and only live credentials make the cut. For developers with production AWS access, this is potentially catastrophic.
GitHub tokens. Personal access tokens with whatever scope the developer granted. Depending on the token, this can mean full read/write access to private repositories, the ability to push to protected branches, or access to organization secrets.
SSH keys. The full ~/.ssh/ directory. After collection, the extracted private keys are tested against known public repositories and servers associated with the developer’s GitHub account, enabling lateral movement into other systems the developer has access to.
Local development data. .env files throughout the filesystem, browser local storage (saved passwords, session cookies), and system configuration databases. On macOS, this includes Keychain-adjacent data.
The active validation step for AWS and GitHub credentials is what makes this particularly dangerous for organizations. An attacker who runs credential sweeps indiscriminately generates noise and security tooling picks up the probing. An attacker who only activates clean, validated credentials is much harder to detect before damage is done.
Infrastructure and Attribution
All identified activity traces back to the GitHub account ddjidd564. On npm, the malicious packages were published by a user called asdxzxc. On PyPI, two accounts were involved: asdmini67 and dae5411.
The GitHub Pages domain ddjidd564.github.io serves both the dynamic JavaScript payload for the PyPI attack vector and the remote configuration file referenced in the PR campaign. Using GitHub infrastructure for C2 and exfiltration (via Gists) is a deliberate choice because it blends malicious traffic into the enormous volume of legitimate GitHub API calls that most enterprise networks see every day.
The XOR key hardcoded into the Rust payload – cargo-build-helper-2026 was probably chosen to look like a plausible internal tool name if anyone spotted it in a hex dump.
The campaign marker P-2024-001 appearing consistently across registries and PR submissions is interesting. Either it’s an internal tracking reference the attacker uses to correlate activity across operations, or it’s a false flag designed to implicate a different threat actor. At this stage, researchers haven’t linked TrapDoor to any previously named group.
Discovery
The Socket Research Team flagged TrapDoor when a cluster of new Rust packages targeting the Sui and Move developer ecosystem appeared on Crates.io with immediate overlaps: identical infrastructure, matching code patterns, and the same campaign marker embedded in all of them. Cross-referencing those markers against concurrent PyPI and npm uploads revealed the full scope of the campaign.
The tell was the build.rs files. Malicious Rust packages are rare. The ecosystem sees far fewer of them than npm or PyPI, partly because Rust developers tend to be more security-conscious and partly because Cargo’s package vetting is more community-scrutinized. A cluster of new Crates.io packages with suspicious build.rs content is unusual enough to trigger automated flags.
What You Should Do Right Now
Check for the AI configuration files. Search your active project directories for .cursorrules and CLAUDE.md. If either file exists unexpectedly, especially if it wasn’t there before and inspect it carefully. Don’t just open it in a text editor and look for visible content; use a hex editor or run cat -v .cursorrules to surface hidden control characters. Check your .git/hooks/ directory for any executable scripts you don’t recognize.
Audit your dependency trees. Check your package-lock.json, poetry.lock, and Cargo.lock files against the full package list below. Don’t just check what’s explicitly in your package.json. Check transitive dependencies too. A malicious package installed as a dependency of a dependency still runs its postinstall hook.
Rotate credentials if you’re exposed. If any of the listed packages were installed and executed in your environment:
- Invalidate all active AWS access keys immediately and generate new ones
- Revoke and regenerate GitHub personal access tokens
- Generate new SSH key pairs and remove the compromised public keys from GitHub and any authorized servers
- Treat any local cryptocurrency keystores that were unlocked during the exposure window as compromised and migrate funds
Review your open source contributions. If you maintain a repository that received a PR from ddjidd564, close it immediately and audit whether any of the content was merged. Review your .cursorrules and CLAUDE.md for Unicode anomalies even if the files look empty.
Indicators of Compromise
| Type | Indicator |
|---|---|
| Domain | ddjidd564[.]github[.]io |
| GitHub account | ddjidd564 |
| npm account | asdxzxc |
| PyPI accounts | asdmini67, dae5411 |
| Campaign marker | P-2024-001 |
| Payload filename | trap-core.js (48,485 bytes) |
| XOR key (Rust) | cargo-build-helper-2026 |
| C2 config URL | ddjidd564[.]github[.]io/defi-security-best-practices/config.json |
Malicious Package List
npm (21 packages): async-pipeline-builder, build-scripts-utils, chain-key-validator, crypto-credential-scanner, defi-env-auditor, defi-threat-scanner, deployment-key-auditor, dev-env-bootstrapper, eth-wallet-sentinel, llm-context-compressor, mnemonic-safety-check, model-switch-router, node-setup-helpers, project-init-tools, prompt-engineering-toolkit, solidity-deploy-guard, token-usage-tracker, wallet-backup-verifier, wallet-security-checker, web3-secrets-detector, workspace-config-loader
PyPI (7 packages): cryptowallet-safety, data-pipeline-check, defi-risk-scanner, env-loader-cli, eth-security-auditor, git-config-sync, solidity-build-guard
Crates.io (6 packages): move-analyzer-build, move-compiler-tools, move-project-builder, sui-framework-helpers, sui-move-build-helper, sui-sdk-build-utils
Common Questions
I don’t work with crypto. Am I at risk?
Possibly, yes. Several packages in the npm and PyPI lists use entirely generic names – node-setup-helpers, workspace-config-loader, git-config-sync, env-loader-cli. These don’t signal anything about blockchain. If they made it into your dependency tree, your SSH keys, AWS credentials, and browser data are still targets.
Can my AI coding assistant run malicious commands without me knowing?
Under normal circumstances, no. AI assistants don’t execute shell commands autonomously. The TrapDoor technique works by injecting hidden instructions into workspace configuration files that the AI reads as part of its context. When you then ask the AI to do something involving the shell, it’s been instructed to include credential harvesting commands as part of the response or task execution. The key mitigation is auditing those configuration files for hidden Unicode characters.
Will this affect me if the packages were just listed in a lockfile but never executed?
For npm, the postinstall hook runs on npm install, not just on first use. If you ran npm install with any of these packages in the tree, the hook executed. For PyPI, the malicious code runs on import. If you never imported the package, the code didn’t run. For Crates.io, build.rs runs during cargo build. A package in Cargo.lock that was never compiled doesn’t trigger the script.








