Dateline: July 16, 2026
npm’s Bad Week: AsyncAPI, Jscrambler, and a Stealer That Wants Your Claude Config
On April 29, a contributor to the AsyncAPI project filed a pull request pointing at a dangerous GitHub Actions workflow. Complete with a proof of concept. On May 17, the same person proposed a fix.
That fix was still sitting in review on July 14, when an attacker opened 37 pull requests to the same repository. Thirty six of them added a fake charity donation page. One of them stole a token that reached across the entire organization.
Five days earlier, a different attacker had already poisoned the jscrambler package with a Rust infostealer. Two separate incidents. One rough week for anyone running npm install.
What Happened?
Start with AsyncAPI, which builds tooling for event driven architectures.
The workflow used pull_request_target, which fires on every new PR and runs in the context of the base repository with full access to secrets. It then checked out the code from the pull request and ran it. That combination has a name in the security world: pwn request.
At 05:08 UTC, the attacker filed PR #2155. Inside sat a markdown file with obfuscated JavaScript hiding behind roughly 1,000 bytes of whitespace. The script swept the Actions runner for secrets and shipped them to a dead drop on rentry.co.
Automated review caught the obfuscation. The PR never merged. Didn’t matter. The workflow finished at 05:16, and the attacker walked off with a personal access token belonging to asyncapi-bot, a service account with reach across the whole organization.
By 06:58 the attacker was pushing commits straight to the next branch. By 07:10 npm had three poisoned packages. Then eleven more commits to a second repository, and two more bad versions of @asyncapi/specs. Those packages pull roughly 140,000 downloads a day.
The payload runs on import, not install, which means ignoring scripts saves nobody. It fetches an 8.25 MB encrypted bundle from IPFS, then unpacks a 92,000 line framework that persists through systemd user services and phones home over HTTP, Nostr relays, Ethereum smart contracts, and a libp2p mesh. It self identifies as M-RED-TEAM v6.4 and carries Miasma branding in its config, though Wiz declined to attribute it.
Jscrambler went differently. Someone got hold of an npm publishing credential. Jscrambler’s own advisory does not explain how.
The first bad version, 8.14.0, landed July 11 with a preinstall hook. Socket flagged it in six minutes. So the attacker adapted, pushing 8.16.0, 8.17.0, 8.18.0, and 8.20.0 over about three hours while maintainers tried to clean up.
Starting at 8.18.0, the install hook vanished and the identical dropper moved into dist/index.js and dist/bin/jscrambler.js. Same malware, now firing on import instead of install, sailing right past scanners that only read install hooks. Two of those versions even declared a dependency on themselves.
What’s the Impact?
The jscrambler payload is a Rust infostealer with an unusually current appetite. Browser wallets by extension ID. Exodus vault keys and seed phrases. AWS, Azure, and GCP metadata endpoints. Discord, Slack, and Telegram tokens. Steam sessions. KDE KWallet.
And AI tooling. Claude Desktop configs, Cursor’s mcp.json, Windsurf, Zed, VS Code, opencode. Those files hold API keys and MCP server credentials, and most people have never thought of them as secrets.
Roughly 2,400 configuration strings sat encrypted individually with ChaCha20-Poly1305. Somebody put effort in.
If a poisoned package touched your machine, the advice from researchers is blunt. Rebuild from a clean image. Rotate everything: npm tokens, source control access, cloud credentials, CI/CD secrets, SSH keys, signing keys, browser sessions.
How to Avoid This
- Audit every pull_request_target workflow today. If it checks out PR code, that is the bug.
- Stop treating dependency PRs as low priority. Fifty eight days is a long time to leave a documented hole open.
- Pin versions. Both attacks shipped through minor bumps that a loose range would have swallowed.
- Cut service account scope. One token reaching an entire GitHub org is how a bad PR becomes a bad week.
- Do not lean on ignore-scripts. Both payloads moved to import time specifically to beat that.
- Add your AI assistant configs to the secrets inventory. Attackers already did.