Mastra npm scope takeover: a dormant maintainer account poisons an AI agent framework
On June 17, 2026, a forgotten contributor account republished the entire @mastra npm scope — ~142 packages — with one malicious dependency that drops a crypto stealer and RAT. A stale credential, not a zero-day.
What is this?
On June 17, 2026, an attacker republished the entire @mastra npm scope — the package namespace of Mastra, a popular open-source TypeScript framework for building AI agents — and slipped a single malicious dependency into each package. The injected library, easy-day-js, is a dayjs lookalike whose install hook downloads and runs a cross-platform cryptocurrency stealer and remote access trojan (RAT). The compromise was disclosed the same day by multiple vendors, including Snyk, SafeDep, Endor Labs, and JFrog, Socket and StepSecurity (via The Hacker News).
No CVE was assigned, and the Mastra source code was never modified. This was not a code bug. The foothold was a dormant maintainer credential: the @mastra scope was published using the npm account ehindero, a real former Mastra contributor whose publish access was never revoked. npm does not expire scope permissions on inactivity, so one stale credential was enough to push to every package in the namespace. As Snyk put it, project hygiene — not a zero-day — was the root cause.
How it works
The attack hid in the dependency tree, not the source. The attacker first published a clean, fully functional easy-day-js@1.11.21 on June 16, 2026 — a byte-for-byte dayjs impersonator, down to the bundled dayjs.min.js and the package description — to serve as cover. The next day, at roughly 01:01 UTC on June 17, they published easy-day-js@1.11.22 with the malware and tagged it latest. Each poisoned @mastra release added exactly one line to its published package.json:
"easy-day-js": "^1.11.21"
The caret range is the trick: 1.11.22 satisfies ^1.11.21, so a normal npm install resolves straight to the armed version. The dependency is never imported by Mastra’s code; it exists only to pull in the trojan at install time. Between roughly 01:12 and 02:36 UTC — an automated burst of about 88 minutes — the rest of the scope was republished. Mastra’s own remediation enumerates the blast radius as 142 publishable packages across @mastra/* plus mastra, create-mastra, and mastracode; public counts ranged from 80 to 144 depending on the snapshot.
The malware runs from a postinstall hook. On install it disables TLS certificate validation (NODE_TLS_REJECT_UNAUTHORIZED='0'), downloads a second-stage payload from a raw IP over a self-signed certificate (23.254.164[.]92:8000), writes it to a temp directory, spawns it as a detached hidden background process, then deletes itself to reduce forensic traces. The second stage is an obfuscated information stealer that reads Chrome, Brave and Edge profiles for a hardcoded list of 160+ cryptocurrency wallet extensions (MetaMask, Phantom, Solflare, Coinbase Wallet, OKX, Keplr), harvests host metadata and browser history, and beacons to a separate RAT C2 (23.254.164[.]123) roughly every 10 minutes. It establishes Node-themed persistence on all three platforms: a LaunchAgent on macOS, a systemd user service on Linux, and a C:\ProgramData\NodePackages staging path on Windows.
Why it matters
Because the payload executes at install time, exposure is not limited to production. CI runners, ephemeral build agents and developer laptops are all in scope the moment they resolve a poisoned version. @mastra/core pulls roughly 4 million downloads a month and has hundreds of dependent projects, so the aggregate reach runs into the tens of millions of installs.
Mastra sits precisely where supply-chain attackers want to be: at the intersection of AI development and cloud infrastructure. As StepSecurity noted, its packages are routinely installed in environments holding some of the most sensitive credentials in modern software — and for an agent framework that means LLM provider API keys alongside cloud keys, CI secrets and SSH keys. A wallet-and-credential stealer landing in that context is a near-ideal target. Notably, Mastra generated SLSA provenance attestations on its CI publishes but did not require them, so a plain personal token could still publish without attestation — and did.
Defenses
Disable install scripts by default. Setting npm config set ignore-scripts true neutralizes postinstall droppers like this one, and you can re-enable scripts only for the few packages that genuinely need them.
Commit lockfiles and build with npm ci. A lockfile pinned to a pre-incident version means npm ci would never have resolved the armed easy-day-js@1.11.22. A loose range, a missing lockfile, or any fresh install on or after June 17 is what let the caret range re-resolve silently.
Require provenance, do not just generate it. A signature-verifying install — npm audit signatures, or a policy that rejects packages lacking attestations — would have refused every package in this wave, because the attacker dropped the provenance the legitimate CI pipeline normally produces.
Watch for phantom dependencies. A mature, widely-used package suddenly gaining a single unused dependency is the exact signal here. Treat it as a red flag in review and in automated policy.
Revoke stale maintainer access. Audit who can publish to your scopes, remove dormant accounts, and enforce 2FA and trusted-publisher flows. The entire incident turned on one credential nobody had retired.
If you resolved a poisoned version, treat the host as compromised: upgrade to a known-good release (for example @mastra/core@1.42.0 or later — do not merely pin downward, since the attacker published some versions above the legitimate latest), rotate every credential the machine could reach (cloud, CI, npm, SSH, and especially LLM API keys), move any crypto wallets to a clean device, remove the persistence artifacts, and reimage where practical.
Status
| Item | Detail |
|---|---|
| Incident | npm scope takeover of @mastra, mass republish with injected dependency |
| Date | June 17, 2026 (decoy easy-day-js@1.11.21 published June 16) |
| Malicious package | easy-day-js@1.11.22 (dropper); marker easy-day-js@1.11.21 (clean decoy) |
| Root cause | Dormant former-contributor npm account (ehindero), publish access never revoked |
| Blast radius | ~142 publishable @mastra/* packages; public counts 80–144 |
| Payload | Cross-platform crypto wallet stealer + RAT with persistence |
| CVE / CVSS | None assigned; source code unmodified, malice introduced at publish time |
| Status | Malicious versions removed; clean releases forward-rolled the same day (e.g. @mastra/core@1.42.0) |
Sources
- → https://snyk.io/blog/a-forgotten-contributor-account-compromised-the-entire-mastra-npm-package-scope/
- → https://thehackernews.com/2026/06/144-mastra-npm-packages-compromised-via.html
- → https://safedep.io/mastra-npm-scope-takeover-supply-chain-attack/
- → https://www.endorlabs.com/learn/mastra-npm-org-compromised-multiple-packages-trojanized-to-drop-a-remote-payload-via-easy-day-js