Safeguard
Supply Chain Attacks

A dormant contributor account just took down the entire Mastra npm scope

One forgotten npm maintainer account let an attacker republish all 142 packages in the @mastra scope in 90 minutes, hitting a package with 4 million monthly downloads.

Safeguard Research Team
Research
6 min read

Between roughly 01:12 and 02:36 UTC on June 17, 2026, an attacker republished all 142 publishable packages in the @mastra npm scope — including @mastra/core, which pulls around 4 million downloads a month, and the mastra CLI package, at roughly 1.5 million downloads a month. The entry point wasn't a leaked CI token or a compromised build pipeline. It was an npm account belonging to a former contributor, ehindero, whose access to the scope had never been revoked after their last legitimate commit sometime in late 2024 or early 2025. Snyk's security research team — Liran Tal and Marian Corneci — disclosed the full incident on June 16, 2026, tracing the attack chain from a quietly published decoy dependency called easy-day-js all the way to a Windows, macOS, and Linux persistence mechanism built to drain crypto wallets. Mastra's maintainers moved fast, shipping three emergency pull requests and restoring @mastra/core to a clean 1.42.0 release within hours. But the root cause — an org scope that was only as secure as its least-recently-audited account — is not unique to Mastra, and it's not a problem code review or CI hardening solves. This post walks through the mechanics of what happened and what it means for anyone who maintains, or simply installs from, an npm organization scope.

What actually happened to the @mastra scope?

An attacker who had gained control of the dormant ehindero npm account used its lingering publish rights to push malicious releases across the entire @mastra organization scope in a tight, 90-minute window. Snyk's timeline shows the attacker first changed the account's registered email to ehindero2016@tutamail[.]com, a change that would normally trigger scrutiny but went unnoticed because nobody was actively monitoring an account presumed inactive. From there, the attacker had standing publish access to @mastra/core, mastra, create-mastra, mastracode, and 138 other scoped packages — no additional exploit, phishing, or credential theft against a currently-active maintainer was required. This is the structural weakness Snyk's post highlights: npm scope permissions don't expire on their own, and a contributor who stops working on a project retains exactly the same publish rights they had on their last active day, indefinitely, unless someone manually removes them.

How did the malicious payload actually get delivered?

The attacker didn't inject malware directly into Mastra's source files — they used a supply-chain trick called dependency confusion through trust warm-up. On June 16, 2026, they published a clean, functioning package called easy-day-js@1.11.21 to npm. The next day, they published easy-day-js@1.11.22, tagged latest, and this version carried the actual payload. Across the compromised Mastra packages, the attacker added just one dependency entry — "easy-day-js": "^1.11.21" — to each package.json. Nothing in Mastra's codebase calls or requires that package; it has no functional role at all. Its entire purpose is to ride along in the install tree so that a routine npm install fetches it and fires its postinstall hook without anyone writing a line of code that touches it. That script disabled TLS certificate verification by setting NODE_TLS_REJECT_UNAUTHORIZED='0', then fetched a second-stage payload (SHA256 hash 221c45a7...3badf, per Snyk's advisory) from https://23.254.164[.]92:8000/update/49890878.

What did the malware do once it landed?

Once installed, the payload established persistence and began systematically targeting cryptocurrency infrastructure on the host machine. Snyk's researchers documented that it specifically searched for MetaMask, Phantom, Solflare, Coinbase Wallet, OKX, and Keplr wallet data, alongside general host, browser, and running-process reconnaissance. It phoned home to a command-and-control address at 23.254.164[.]123/49890878 roughly every ten minutes, and it installed itself for persistence differently depending on platform: a LaunchAgent on macOS, a systemd user service on Linux, and PowerShell staged out of C:\ProgramData\NodePackages on Windows. This wasn't a smash-and-grab credential grab — it was built to survive reboots and keep collecting for as long as it went unnoticed on a developer's or CI runner's machine, which is exactly the kind of behavior that makes a compromised postinstall script far more dangerous than a single leaked secret.

How did Mastra and npm respond, and how fast?

Mastra's maintainers responded within hours of the malicious publish window closing. Snyk's post credits the team with shipping three emergency pull requests — #18049, #18056, and #18060 — that forward-rolled the entire scope to clean versions rather than attempting to selectively unpublish or patch individually. @mastra/core was restored to a verified-clean 1.42.0, and easy-day-js itself was pulled from the npm registry entirely once its role in the attack chain was confirmed. Snyk assigned the finding advisory ID SNYK-JS-EASYDAYJS-17353313 so downstream scanners and SCA tools could match it against installed lockfiles. The fast forward-roll strategy is notable: rather than a slow forensic unwind of exactly which packages were touched, Mastra treated the entire scope as compromised and republished from a known-good baseline, which is generally the safer call when an attacker has held publish rights to more than 100 packages simultaneously.

Is this part of a broader pattern in npm attacks?

Snyk's researchers note that this incident echoes the structure of an earlier 2026 compromise of the Axios npm package, which Microsoft Threat Intelligence publicly attributed to Sapphire Sleet, a threat cluster also tracked as BlueNoroff and linked to North Korean state-sponsored operations with a strong financial-crime and crypto-theft motive. Attribution for the Mastra incident itself remains unconfirmed, but the tradecraft — a decoy package published a day ahead of the malicious one, a dependency injected purely for its install hook rather than its functionality, and wallet-focused data theft — lines up closely enough that Snyk flagged the resemblance explicitly rather than treating it as coincidence. The broader lesson researchers have been repeating since the 2021 dependency-confusion disclosures and the 2023-2024 wave of PyPI and npm typosquats is the same one this incident reinforces: attackers increasingly find it more efficient to compromise the publishing pipeline of a popular package than to write and distribute malware that has to be discovered independently by a victim.

What should maintainers and consumers actually do about this?

Maintainers should treat npm organization scopes as a standing access-control problem, not a one-time setup step — that means periodically auditing every account with publish rights, removing contributors who haven't been active in months, requiring hardware-key-backed two-factor authentication for publish access, and watching for account-level changes like an email swap on a rarely-used account. Consumers of any npm-scoped package can't fix someone else's stale permissions, but they can reduce blast radius: pin exact dependency versions rather than ranges, review postinstall scripts before allowing them to run in CI, and rescan installed dependency trees when a new advisory like SNYK-JS-EASYDAYJS-17353313 is published rather than assuming a clean install stays clean. This is precisely the failure mode Safeguard's Eagle malware classifier is built to catch on the technical side: Eagle scores install-script behavior and flags "package trust warm-up" — publishing one or more benign versions before a malicious release — as a distinct indicator class, which is exactly the easy-day-js 1.11.21-then-1.11.22 pattern Snyk documented. No scanner can revoke a dormant maintainer's npm credentials for you, but catching the malicious postinstall hook and the warm-up pattern before it reaches a developer's machine closes the part of this attack chain that happens after the access control failure has already occurred.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.