Skip to content

Mastra npm scope hijacked: 142 packages backdoored via easy-day-js

Microsoft documents the @mastra npm takeover: 142 packages republished in 88 minutes on June 17 with the easy-day-js typosquat, dropping a cross-platform Node.js infostealer.

Published 4 min read

Microsoft Threat Intelligence published a full writeup on June 17, 2026 of a scope-wide takeover of the @mastra npm organisation, the publisher of the Mastra TypeScript AI agent framework. Between 01:12 and 02:39 UTC on June 17, an attacker republished 142 packages under the @mastra and mastra scopes, each with a single injected dependency: easy-day-js, a typosquat of the dayjs library (57M weekly downloads). The malicious version of easy-day-js shipped a postinstall hook that fetched a cross-platform Node.js info-stealer from 23.254.164.92. Combined weekly downloads across the affected scope are above 1.1 million, with @mastra/core alone at ~918K/week.

What's affected

  • All @mastra/* packages and mastra published after 2026-06-17 01:20 UTC until the maintainer revoked the compromised token. Microsoft confirms the breakpoint at mastra@1.13.1; earlier versions (mastra <= 1.13.0, @mastra/core <= 1.42.0) are unaffected.
  • easy-day-js@1.11.22 is the weaponised release. 1.11.21, published 17 hours earlier as bait to seed trust, contains no malicious code.
  • Because compromised @mastra packages declared easy-day-js: "^1.11.21", npm's semver resolution automatically pulled 1.11.22 for anyone who ran npm install between the publish window and remediation.

The Hacker News' coverage confirms the package count and identifies the compromised maintainer as ehindero — a stale contributor account whose @mastra scope publish rights were never revoked after the contributor left the project.

Exploitation status

Confirmed in the wild on June 17. Any workstation, CI runner, build container, or autobuilder that ran npm install against a @mastra/* package — directly or transitively — between 01:20 UTC June 17 and the maintainer's revoke must be treated as potentially compromised. There is no exploitation window before the publish; the malicious code only runs via the postinstall lifecycle hook of easy-day-js@1.11.22.

Microsoft Defender XDR detections shipped under the names Trojan:JS/NpmStealz.Z!MTB, Trojan:JS/NpmStealz.ZA!MTB, Trojan:JS/NpmSteal.DB!MTB, and Trojan:PowerShell/PsExec.DE!MTB.

Indicators of compromise

Reproduced verbatim from Microsoft's writeup:

# Network IOCs
23.254.164.92                                 # primary C2
23.254.164.123                                # secondary C2
https://23.254.164.92:8000/update/49890878    # second-stage payload URL

# SHA-256 file hashes
B122A9873BEDF145AE2A7FD024B5F309007DBB025149F4DC4AC3F7E4F32A36A4  setup.cjs (dropper)
AE70DD4F6BC0D1C8C2848E4E6B51934626C4818DCB5AF99D080DDBD7DC337185  easy-day-js-1.11.22.tgz
4A8860240E4231C3A74C81949BE655A28E096A7D72F38FBE84E5B37636B98417  easy-day-js-1.11.21.tgz (bait)
B73DE25C053D3225A077738A1FCBD9CA6966D7B3CD6F5494A30F0AA0EAE55C7E  mastra-1.13.1.tgz
221c45a790dec2a296af57969e1165a16f8f49733aeab64c0bbd768d9943badf  protocol.cjs

# Host-side markers (Stage 0)
$TMPDIR/.pkg_history                          # install-path marker
$TMPDIR/.pkg_logs                             # XOR-0x80 encoded "easy-day-js"
<home>/<random_hex>.js                        # second-stage payload on disk

# Persistence locations (Stage 1)
HKCU\Software\Microsoft\Windows\CurrentVersion\Run    # Windows
~/Library/NodePackages/                                # macOS LaunchAgent
~/.config/systemd/nvmconf/                             # Linux systemd user unit

Microsoft also publishes a Defender Advanced Hunting query:

DeviceProcessEvents
| where FileName in ("node", "node.exe")
| where ProcessCommandLine has "setup.cjs" or ProcessCommandLine has "easy-day-js"

Action checklist

  1. Grep your lockfiles for easy-day-js now. git grep -n easy-day-js -- 'package-lock.json' 'pnpm-lock.yaml' 'yarn.lock' 'bun.lockb' on every repo. Any hit on 1.11.22 is presumptive compromise of every developer and CI runner that resolved that lock.
  2. Pin @mastra/* and mastra below the compromise. Last known-good is mastra@1.13.0 and @mastra/core@1.42.0. Lock to those until the maintainer publishes a clean tag and rotates publish tokens.
  3. Re-run installs with --ignore-scripts until you've confirmed clean transitive trees. Microsoft's full kill-chain depends on the postinstall hook of easy-day-js; disabling lifecycle scripts neutralises Stage 0 even if the malicious tarball is in cache.
  4. Hunt the IOCs. Block 23.254.164.92 and 23.254.164.123 at the egress. Sweep $TMPDIR/.pkg_history, $TMPDIR/.pkg_logs, the three persistence locations above, and the five file hashes across your fleet. The Defender Advanced Hunting query covers the process-event side.
  5. Rotate every credential the affected hosts could reach. Stage 1 enumerates browser profiles, cryptocurrency wallets (166 extension fingerprints, per Microsoft), and exfiltrates anything reachable in ~. Treat npm tokens, GitHub PATs, cloud keys, LLM API keys, CI secrets, SSH keys, and database credentials as burnt on any host that ran the dropper.
  6. Move wallets off compromised devices entirely. The implant targets MetaMask, Phantom, Coinbase Wallet, and 163 other wallet extensions specifically. Generate new wallets on clean hardware; do not unlock the old ones on the same host.

Context

This is now the fourth npm-scope-takeover incident this quarter that this site has covered, sitting in a clear sequence with the Laravel-Lang credential-stealer push, the nx-console / GitHub Actions wave that CISA picked up on May 28, and the Red Hat RHSB-2026-006 npm "miasma" advisory. The common pattern is the same: an old maintainer credential — never expired by npm — used to mass-republish under a scope whose downstream consumers trust the namespace, not the individual publisher. Microsoft makes the point explicitly in its writeup: npm does not expire scope publish permissions on inactivity, so a single forgotten contributor is enough to break an entire ecosystem.

The Mastra incident also lands in the same week as Anthropic's claude-code-action repo-takeover chain, making it the second public agent-tooling supply-chain story in seven days. AI framework registries inherit the same trust failure modes as the general-purpose npm scopes — they just bring a richer payload target (LLM keys, wallet seeds, model weights, training data) for the implant to walk away with.

What other outlets missed

Most secondary coverage repeats Microsoft's headline package count without surfacing the 17-hour bait window: easy-day-js@1.11.21 was published clean at 07:05 UTC on June 16, almost a day before the mass republish. A defender pinning easy-day-js to =1.11.21 on June 16 with intent-to-block would have shipped the bait into their lockfile, and ^1.11.21 would have silently upgraded them into the trojan the next morning — the resolution rule is the vulnerability, not the version pin. Treat any pin against a brand-new typosquatted package as a tripwire, not as containment.

Related stories