Mastra Supply Chain Compromise: easy-day-js Dropper Pulls a Cross-Platform RAT Into @mastra Installs
Executive Summary
On June 17 2026, a coordinated supply chain attack pushed a malicious easy-day-js package into the dependency tree of the entire @mastra/* npm organization. Any npm install for a compromised @mastra/* package pulls [email protected], which runs a postinstall dropper, downloads a cross-platform RAT, installing persistent backdoors on macOS, Linux, and Windows.
The Mastra ecosystem has more than a million weekly npm downloads, putting a large surface of developer machines and CI runners at risk.
The Compromise
The attack played out in two stages, run from two different npm accounts.
First, on June 16, an attacker using the account [email protected] published [email protected]. It looked like a harmless typosquat of the popular dayjs library. In reality, the code was an exact copy of dayjs with only the package.json changed. For the next 18 hours the package sat in the registry looking like any other quiet utility, attracting no installs and no attention.
Then, on June 17 at 01:01 UTC, the same attacker published [email protected]. This release was not harmless. It carried a postinstall script and an obfuscated dropper called setup.cjs.
Fourteen minutes later the attack pivoted. A second npm account, this one belonging to a legitimate Mastra maintainer ([email protected]), was used to republish every current @mastra/* package with one quiet change: a new dependency on "easy-day-js": "^1.11.21". Because npm resolves the caret range to the latest matching version, every fresh install of a touched @mastra/* package now pulls the armed 1.11.22 along with it.
At the time of writing, The package is live on the npm registry, also the C2 infrastructure is also active.
Which Packages Are Affected?
The injected dependency was published to more than a dozen @mastra/* packages, covering the broader Mastra ecosystem of 140+ packages. Known compromised versions include:
- [email protected] – the armed dropper. The earlier 1.11.21 is inactive but should also be blocked.
- @mastra/[email protected]
- @mastra/[email protected]
- @mastra/[email protected]
- @mastra/[email protected]
- @mastra/[email protected]
- @mastra/[email protected]
- @mastra/[email protected]
- @mastra/[email protected]
- @mastra/[email protected]
- @mastra/[email protected]
- @mastra/[email protected], @mastra/[email protected], @mastra/[email protected], @mastra/[email protected], @mastra/[email protected]
The last clean release of each package is the patch immediately preceding the affected version. Any developer workstation or CI runner that ran a fresh install or a lockfile-free npm i of an affected package since 2026-06-17 01:15 UTC should be treated as potentially compromised.
How to Check if Your System Is Compromised
- Lockfile search:
grep -r "easy-day-js" package-lock.json yarn.lock pnpm-lock.yaml - Dropper tmpdir markers: ls -la “$TMPDIR/.pkg_history” “$TMPDIR/.pkg_logs” 2>/dev/null
- macOS persistence: ls ~/Library/NodePackages/ ~/Library/LaunchAgents/com.nvm.protocal.plist 2>/dev/null
- Linux persistence: systemctl –user status nvmconf.service 2>/dev/null
- Windows persistence: reg query HKCU\Software\Microsoft\Windows\CurrentVersion\Run /v NvmProtocal
- Network: search DNS, egress proxy, and EDR logs for connections to 23.254.164.92 or 23.254.164.123, or the spoofed beacon UA mozilla/4.0 (compatible; msie 8.0; windows nt 5.1; trident/4.0).
How Does the Attack Work?
- npm install of any compromised @mastra/* package resolves the caret range and pulls [email protected].
- npm runs the package’s postinstall script, which executes node setup.cjs –no-warnings.
- setup.cjs sets NODE_TLS_REJECT_UNAUTHORIZED=0, writes two marker files in $TMPDIR (.pkg_history, .pkg_logs), then fetches the stage-2 payload from https://23.254.164.92:8000/update/49890878 with Node’s default User-Agent.
- The response is written to a random 12-character hex .js file in $TMPDIR, then spawned as a detached child process with 23.254.164.123:443 passed as argv[2].
- setup.cjs deletes itself with fs.rmSync(__filename) for anti-forensics.
- Stage-2 is a 41 KB obfuscated cross-platform RAT. On startup it collects installed applications, running processes, browser history domains from Chrome, Brave, and Edge, and a hit-list of 166 crypto wallet browser extension IDs including MetaMask, Phantom, Coinbase Wallet, Trust Wallet, Keplr, and TronLink.
- The collected data is sent to C2 as base64-wrapped JSON over application/x-www-form-urlencoded – a deliberate choice that bypasses JSON-aware WAF.
- The implant waits for a tpcsr command before running any stage-3 payload. The operator manually reviews each victim and decides whether to proceed – victims without wallets or interesting dev tooling may never see a follow-up.
The stage-3 payload URL is decoupled from the C2 address, and a separate gfcm command lets the operator migrate the implant to a new PrimaryUrl at any time. Existing infections survive a takedown of the current C2.
Indicators of Compromise
- Stage-2 source: https://23.254.164.92:8000/update/49890878
- Beacon and exfil: https://23.254.164.123:443/49890878 (POST, base64 JSON in form-urlencoded body)
- Spoofed beacon User-Agent: mozilla/4.0 (compatible; msie 8.0; windows nt 5.1; trident/4.0)
- C2 CIDR: 23.254.164.0/24
- TLS cert issuer: Caddy Local Authority – ECC Intermediate, 12-hour validity window
- macOS persistence: ~/Library/NodePackages/protocal.cjs, ~/Library/LaunchAgents/com.nvm.protocal.plist, label com.nvm.protocal
- Linux persistence: ~/.config/systemd/nvmconf/protocal.cjs, service nvmconf.service
- Windows persistence: C:\ProgramData\NodePackages\protocal.cjs, Run key HKCU\Software\Microsoft\Windows\CurrentVersion\Run\NvmProtocal
- Config file (all platforms): config.json containing UID, PrimaryUrl, Cycle
- Tmpdir markers: .pkg_history, .pkg_logs, random 12-hex .js files
- Author fingerprint: the misspelling protocal appears across every persistence mechanism
Mitigation and Patching
- Pin every @mastra/* package to the last clean version (the patch immediately preceding the affected version above). Block easy-day-js outright in your package manager policy.
- Treat any developer workstation or CI runner that ran a fresh install of an affected @mastra/* package since 2026-06-17 01:15 UTC as potentially compromised. Rotate every credential reachable from the shell environment – the stage-3 shell runner uses /bin/zsh -s, inheriting ~/.zshrc, so AWS_ACCESS_KEY_ID, GITHUB_TOKEN, npm tokens, and similar are all in scope.
- On macOS, delete the persistence files before killing the process. Order matters:
rm -f ~/Library/NodePackages/protocal.cjs
rm -f ~/Library/LaunchAgents/com.nvm.protocal.plist
rm -f ~/Library/NodePackages/config.json
pkill -f protocal.cjs
rm -f “$TMPDIR/.pkg_history” “$TMPDIR/.pkg_logs”
- Block egress to 23.254.164.92 and 23.254.164.123 at the firewall and add the C2 IPs plus the spoofed IE8/XP User-Agent to your network detection ruleset. Multi-tenant CI environments first, isolated developer laptops after.
How Upwind Helps
Upwind actively scans for in-the-wild supply chain campaigns and continuously monitors customer runtime data. That combination is how the initial @mastra/* republish was caught within hours of the publish window, well before any public IOC list existed.
Upwind’s runtime telemetry surfaced the malware through anomalous behavior on customer right as it was executed.
Upwind also maps every instance of the affected packages across customer environments so teams can prioritize and remediate the impacted workloads.


