Snyk Blog In this article TL;DR How the attack worked The carrier: one line in every package.json The malware dropper: TLS off, fetch, detach, delete The payload: a multi-platform crypto stealer and RAT Impact analysis Detection: Are you exposed? Remediation Related Snyk coverage Timeline A Forgotten Contributor Account Compromised the Entire Mastra npm Package Scope Written by Liran Tal Marian Corneci June 16, 2026 0 mins read An attacker republished the entire @mastra npm scope on June 17, 2026, slipping a single malicious dependency into 142 packages, including @mastra/core , which pulls roughly 4 million downloads a month and has hundreds of dependent projects. The injected dependency, easy-day-js , is a dayjs lookalike whose install hook disables TLS verification, downloads a second-stage payload from a raw IP address, and runs a cross-platform cryptocurrency stealer in the background. This attack on an npm package was made possible due to a former contributor account whose scope access was never revoked. Action required: if you installed any @mastra package, or anything that depends on one, in a fresh or updated tree on or after June 17, 2026, treat this as a credential and wallet exposure event and read on. TL;DR Incident: npm scope takeover of @mastra , mass republish with an injected malicious dependency Malicious dependency: easy-day-js@1.11.22 (a dayjs impersonator acting as a dropper) Snyk advisory: SNYK-JS-EASYDAYJS-17353313 , Embedded Malicious Code, affects easy-day-js 1.11.21 and 1.11.22 Affected packages: essentially the entire @mastra scope, republished on June 17, 2026; Mastra's own remediation covers 142 publishable packages Notable versions: @mastra/core@1.42.1 , mastra@1.13.1 , create-mastra@1.13.1 CVE / CVSS: none assigned; this is an active supply chain incident, and the Mastra source code itself was not modified Payload: cross-platform cryptocurrency wallet stealer plus a remote access trojan with persistence Status: easy-day-js has been removed from npm, ehindero is no longer an owner of the scope, and Mastra has forward-rolled clean versions ( PR #18056 ). @mastra/core latest is back to a clean 1.42.0 . Treat any compromised version you already resolved as a host-exposure event. How the attack worked The foothold was a stale maintainer credential. The @mastra scope was published to using the npm account ehindero , a real former Mastra contributor. The npm registry's publish history records legitimate alpha releases of @mastra/core from this account in late 2024 and early 2025, after which it went dormant. Its scope access was never revoked. The account shows signs of takeover rather than insider action, including an email change away from the contributor's original address to ehindero2016@tutamail[.]com . The mechanics here are worth sitting with: npm does not expire scope publish permissions on inactivity, so one stale maintainer credential was enough to push to every package in the scope. Project hygiene, not a zero-day, is the root cause. The carrier: one line in every package.json The attacker did not touch the Mastra source code. The poison was injected into the published tarballs at publish time, and Mastra's own remediation PR confirms the repository was verified clean of easy-day-js across every package.json and lockfile ( PR #18056 ). Each malicious release on npm added exactly one line to the published package.json : "easy-day-js" : "^1.11.21" The dependency is never imported anywhere in the Mastra source. It exists purely to pull in a trojan at install time. The caret range is the trick. The attacker first published a clean easy-day-js@1.11.21 on June 16, a byte-for-byte dayjs impersonator down to the bundled dayjs.min.js and the package description. The next day, they published easy-day-js@1.11.22 with the malware and tagged it latest . Because 1.11.22 satisfies ^1.11.21 , a normal npm install resolves straight to the armed version. Then, in a burst on June 17, 2026, the attacker republished the remaining scope, each package containing the same injected dependency. Mastra's own remediation enumerates the blast radius precisely: its emergency changeset forward-rolls 142 publishable packages across the @mastra/* scope plus mastra , create-mastra , and mastracode ( PR #18056 ). Public reporting put the count anywhere from 80 to 144, depending on the snapshot, but the vendor's own figure is the one to anchor on, and the takeaway is the same: essentially, the entire scope was hit. For a handful of packages, the attacker even published versions above the legitimate latest (for example, @mastra/schema-compat@1.2.12 , @mastra/react@1.0.1 , @mastra/voice-playai@0.12.2 ), which later forced Mastra to pin explicit higher versions rather than ordinary patch bumps to supersede them ( PR #18060 ). The malware dropper: TLS off, fetch, detach, delete easy-day-js@1.11.22 ships a setup.cjs that runs as a postinstall hook. On install it: Disables TLS certificate validation by setting NODE_TLS_REJECT_UNAUTHORIZED='0' , so an HTTPS fetch succeeds against a self-signed certificate on a raw IP. Writes marker files ( ~/.pkg_history, ~/.pkg_logs ) to track installs. Downloads a second-stage payload from https://23.254.164[.]92:8000/update/49890878 (Hostwinds-hosted). Writes it to the temp directory and spawns it as a detached, hidden background process with no console output. Deletes itself to reduce forensic traces. The payload: a multi-platform crypto stealer and RAT The second stage (SHA256 221c45a790dec2a296af57969e1165a16f8f49733aeab64c0bbd768d9943badf ) is an obfuscated cryptocurrency wallet stealer , the same payload class Snyk has tracked in earlier npm compromises. It reads Chrome, Brave, and Edge profiles looking for a hardcoded list of cryptocurrency wallet browser extensions, including MetaMask, Phantom, Solflare, Coinbase Wallet, OKX, and Keplr. Alongside wallet data it collects username, hostname, OS and architecture, Node version, installed applications, browser history, and the running process list, then base64-encodes the lot into a JSON beacon. It also establishes persistence disguised as Node tooling and beacons to a separate RAT C2 ( 23.254.164[.]123/49890878 ) roughly every 10 minutes, using a self-signed wolfSSL test certificate ( CN=www.wolfssl.com , expired January 2018): macOS: LaunchAgent at ~/Library/LaunchAgents/com.nvm.protocal.plist Linux: systemd user service ~/.config/systemd/user/nvmconf.service Windows: PowerShell execution staged under C:\ProgramData\NodePackages The clean-then-armed dependency, the setup postinstall dropper, the TLS-bypass-to-raw-IP fetch, and the crypto-stealer payload closely mirror the Axios npm compromise that Snyk analyzed earlier in 2026, down to the install-time dropper that self-deletes. Microsoft Threat Intelligence attributed that earlier campaign to the actor it tracks as Sapphire Sleet (BlueNoroff). Attribution for this incident specifically is not confirmed, and we will not speculate further here; the pattern is worth noting for defenders, not asserting as fact. Impact analysis @mastra/core alone pulls about 4 million downloads a month ( npm registry ) and has hundreds of dependent projects; mastra adds roughly 1.5 million more ( npm registry ). With 142 packages republished across the scope, the aggregate monthly download volume runs into the tens of millions, so the potential blast radius is large. The practical exposure is narrower than that headline number, and it is worth being precise about it. You are at risk only if a build or developer machine resolved one of the malicious versions during the exposure window. Lockfiles are the deciding factor and the safe, reproducible pattern for dependencies in npm projects: Pinned via a committed lockfile to a pre-incident version: an npm ci would not have pulled the malicious release. You are likely fine, but verify. No lockfile, a loose range, or a fresh install / lockfile regeneration on or after June 17: the caret range would have resolved to the armed easy-day-js@1.11.22 , and the postinstall hook would have run. Because the payload executes at install time, CI runners, ephemeral build agents, and developer laptops are all in scope, not just production servers. Any of those hosts could have leaked credentials and wallets. Detection: Are you exposed? 1. Check whether easy-day-js ever entered your dependency tree. It should never legitimately appear: npm ls easy-day-js grep -r "easy-day-js" package-lock.json yarn.lock pnpm-lock.yaml 2> /dev/null 2. Audit the @mastra versions you resolved. Compromised releases were published June 17, 2026 and lack SLSA provenance. Inspect what your lockfile actually pinned: npm ls @mastra/core mastra create-mastra 3. Scan with Snyk. Snyk flags the malicious package as SNYK-JS-EASYDAYJS-17353313 (Embedded Malicious Code): snyk test snyk monitor 4. Hunt for host artifacts on any machine that ran an install during the window: #Dropper markers ls -la ~/.pkg_history ~/.pkg_logs 2> /dev/null #Persistence ls -la ~/Library/LaunchAgents/com.nvm.protocal.plist 2> /dev/null # macOS ls -la ~/.config/systemd/user/nvmconf.service 2> /dev/null # Linux dir "C:\ProgramData\NodePackages" # Windows 5. Check egress logs for connections to 23.254.164[.]92:8000 or 23.254.164[.]123 , or anything in 23.254.164.0/24 . For a hands-on walkthrough of finding and fixing a scope-wide npm compromise of this shape with Snyk, this remediation demo covers the workflow end to end: Play Video: Shai-Hulud NPM Attack: Remediation with Snyk Shai-Hulud NPM Attack: Remediation with Snyk (a hands-on remediation workflow for a mass-republish npm supply chain attack). Remediation If easy-day-js is absent and your lockfile pinned pre-incident @mastra versions: confirm with the detection steps above, keep your lockfile pinned, and move on. If you resolved a malicious version, treat any affected host as compromised. Upgrade to a clean version; do not just pin downward. Mastra responded by forward