# Mastra npm compromise teardown: a phished maintainer token

> How 140+ Mastra npm packages gained an easy-day-js dependency whose install script dropped a remote-access tool, and whether Chainsaw stops it.

Source: https://chain305.com/teardowns/mastra-npm-compromise/

---

# Teardown: the Mastra npm compromise

One phished maintainer, 140+ packages, one new dependency.

What happened on 17 June 2026, how a stolen npm token got past MFA, and where Chainsaw would and would not have stopped it.

By [Muhammad Zeeshan Sultan](https://chain305.com/about/#founder), founder of Chain305 · October 2026

Questions and answers

## What happened?

On 17 June 2026 (UTC), more than 140 packages of the Mastra AI framework on npm got a new patch version with one added dependency, `easy-day-js`, whose install script downloaded and ran a second-stage payload. `@mastra/core` alone gets about 918,000 downloads a week, according to Socket, and Microsoft reports the poisoned versions were tagged `latest`.

The count and the window depend on who you read. Mastra’s incident report says a token published 116 malicious packages between 6:12 and 6:37 PM Pacific on 16 June, which is 01:12 to 01:37 UTC on 17 June. StepSecurity tracked republishes from 01:12 to 02:39 UTC, Socket counts 141 `@mastra/*` packages, and isotope¹³ notes that reported counts range from 140 to 145.

Mastra says it noticed at 8:45 PM Pacific and by 11:57 PM had unpublished 110 of the 116 packages and deprecated the other six, which npm would not let it unpublish. It then published new, safe versions of each affected package. GitHub and OSV listed `@mastra/core@1.42.1` as malware (GHSA-pp62-grrw-hvfp, MAL-2026-6011), and OSV listed `easy-day-js@1.11.22` as MAL-2026-5979 at 04:15 UTC, about three hours after it went up. On 19 June Microsoft attributed the operation with high confidence to Sapphire Sleet, a North Korean state actor focused on stealing cryptocurrency.

## How did the attacker get publish rights?

By phishing a Mastra maintainer and using a token tied to his npm account. Mastra’s report says a compromised LinkedIn account contacted him and maintainers of other prominent TypeScript packages; during a call he clicked a suspicious link, and his machine was compromised. Mastra required MFA for npm maintainers but, in its words, mistakenly allowed token bypass, so the token could publish without a second factor. Mastra removed the bypass across all its packages.

Sources disagree about the account. Mastra says the maintainer is a current, active employee. Snyk and isotope¹³ describe the account as a former contributor’s whose publish access was never revoked, and Snyk says it had been dormant since early 2025.

The publish path changed as well. Microsoft and Socket both report that earlier Mastra releases were published by the project’s GitHub Actions pipeline, while the malicious wave came from a single person’s npm account outside it.

## What changed in the packages?

One line in `package.json`. Socket found each malicious release byte-identical to the last legitimate build apart from a patch version bump and manifest normalization, plus one new dependency: `"easy-day-js": "^1.11.21"`. Microsoft found no matching change in Mastra’s GitHub repository, and Snyk notes the dependency is never imported. It is there only to be installed.

`easy-day-js` is a lookalike of the `dayjs` date library, with dayjs’s author name and links copied into its manifest. The npm registry shows its first version, a clean `1.11.21`, published at 07:05 UTC on 16 June by an account the researchers name as `sergey2016`. Version `1.11.22`, which added the install hook, followed at 01:01 UTC on 17 June, about 11 minutes before the first Mastra republish. Because of the caret range, a fresh install of any affected Mastra package resolved to `1.11.22`. When the Mastra packages started pulling it in, the `easy-day-js` name had existed for about 18 hours.

## What ran on install?

In the June 2026 Mastra npm compromise, the dropper `easy-day-js@1.11.22` ran `node setup.cjs --no-warnings` as a `postinstall` hook. The 4,572-byte `setup.cjs` is an obfuscated loader, and according to Microsoft and StepSecurity the script:

-   set `NODE_TLS_REJECT_UNAUTHORIZED=0`, turning off certificate checks for its requests;
-   wrote `.pkg_history` (the install path) and `.pkg_logs` (an encoded package-name marker) to the temp directory;
-   downloaded a second stage from `https://23.254.164[.]92:8000/update/49890878`;
-   saved it as a randomly named `.js` file, in the temp directory according to StepSecurity and the home directory according to Microsoft, and ran the file with Node.js as a detached, hidden process;
-   deleted `setup.cjs`, so the package directory no longer showed the dropper.

Microsoft and Socket analysed the second stage, a Node.js tasking client of about 41 KB which reports to `23.254.164[.]123` and runs whatever code the operator sends back. The client persists under names resembling Node tooling: a Run key value `NvmProtocal` on Windows, a LaunchAgent `com.nvm.protocal` on macOS, and a systemd user unit `nvmconf.service` on Linux. The client checks installed browsers for 166 cryptocurrency wallet extensions, reads Chrome, Edge and Brave history, and collects host details, installed applications and running processes.

The sources differ on what the client took. Mastra’s report describes a script which exfiltrated credentials. Socket says its recovered sample does not read saved passwords or cookies or copy wallet data, and StepSecurity did not observe the second stage at all because its own tooling blocked the download. Per Microsoft, on hosts where the implant reached its server, the operator delivered more tooling: a PowerShell backdoor from `teams.onweblive[.]org` beaconing to `maskasd[.]com`, a Microsoft Defender exclusion, and a Windows service named `scdev`.

## Would Chainsaw have stopped it?

Yes, on day 0, for installs that go through the Chainsaw proxy. We measured this in our re-run of 58 attacks from 2026 against production Chainsaw (v0.22.118) on 19 October 2026. No policy change is needed: both rules below are on by default.

-   **The dropper is refused on first download.** A default rule, ‘Block packages released within 1 day’, refuses packages that first appeared on npm recently. `easy-day-js` is about 18 hours old when the Mastra packages start pulling it, so the install fails before `setup.cjs` can run, with no malware feed entry needed.
-   **The malicious Mastra versions are held back.** Chainsaw holds every new version for 48 hours by default, so `npm install @mastra/core` through the proxy resolves to `1.42.0`. The known-malicious feed lists `@mastra/schema-compat@1.2.12`, `easy-day-js@1.11.22` and `@mastra/core@1.42.1` 2 to 4 hours after publish, so they stay refused once the hold ends.
-   **The age rule has a window.** It stops matching `easy-day-js` about 48 hours after the package first appeared. From then on, `easy-day-js@1.11.22` is refused by its feed listing, not its age.
-   **The install script alone is not a reliable stop.** The byte scan escalates an obfuscated loader like `setup.cjs` only above a threshold of obfuscated identifiers, and a readable loader that downloads a payload and spawns it with Node is not refused on its contents. The age rule and the hold are what stop this one.
-   **Installs that bypass the proxy get the malware.** A machine or CI runner pointed straight at registry.npmjs.org is not protected.

## What should you do?

Every install of one of the more than 140 Mastra packages republished on 17 June 2026, for example `@mastra/core@1.42.1`, also pulled in `easy-day-js@1.11.22` and ran its postinstall dropper. First find out whether `easy-day-js` was ever installed. Run `npm ls easy-day-js` and `npm ls @mastra/core mastra create-mastra`, search lockfiles and CI logs for `easy-day-js`, and look for `.pkg_history` and `.pkg_logs` in the temp directory.

If `easy-day-js` was installed:

1.  **Treat the machine or runner as compromised.** GitHub’s advisory warns that removing the package may not remove everything the dropper installed.
2.  **Rotate secrets from a different computer:** npm and GitHub tokens, cloud keys, SSH keys, CI/CD secrets and LLM API keys the host could reach.
3.  **Remove the persistence and kill the detached process.** Socket notes uninstalling the package is not enough: look for the `NvmProtocal` Run value, the `com.nvm.protocal` LaunchAgent and the `nvmconf.service` unit.
4.  **Install a clean Mastra release and regenerate the lockfile** so `easy-day-js` is gone. Snyk advises upgrading to a clean release rather than pinning down; Microsoft points to the last release before the attack, such as `@mastra/core@1.42.0`, and Socket to the last release published by GitHub Actions, after checking its provenance.
5.  **Move cryptocurrency out of browser-extension wallets** on the affected machine to a new wallet created on a clean device, as Socket and Snyk advise.
6.  **Search network logs for `23.254.164[.]92` and `23.254.164[.]123`, and block them**, along with `teams.onweblive[.]org` and `maskasd[.]com`.

For the next one:

1.  **Don’t install brand-new packages or versions straight away.** Socket and StepSecurity both list release cooldowns as a defence. `easy-day-js@1.11.22` was 11 minutes old when the first Mastra package started depending on the dropper.
2.  **Turn off install scripts by default.** Snyk suggests `npm config set ignore-scripts true`, Microsoft `--ignore-scripts`; Socket suggests allowlisting the packages that need them.
3.  **Watch for new dependencies in mature packages and for releases that skip the usual pipeline.** Snyk recommends requiring npm provenance on the packages you consume.
4.  **If you publish packages, don’t let tokens bypass MFA, and remove publish access people no longer need.** Those are the two account-level fixes Mastra and isotope¹³ describe.

## Sources

-   Mastra, [INCIDENT REPORT: 2026-06-16: Mastra hit by supply-chain attack (issue #18061)](https://github.com/mastra-ai/mastra/issues/18061), 17 June 2026.
-   Microsoft Threat Intelligence, [From package to postinstall payload: Inside the Mastra npm supply chain compromise](https://www.microsoft.com/en-us/security/blog/2026/06/17/postinstall-payload-inside-mastra-npm-supply-chain-compromise/), 17 June 2026, updated 19 June 2026.
-   GitHub Advisory Database, [GHSA-pp62-grrw-hvfp: Malware in @mastra/core](https://github.com/advisories/GHSA-pp62-grrw-hvfp).
-   OSV, [MAL-2026-5979 (easy-day-js)](https://osv.dev/vulnerability/MAL-2026-5979) and [MAL-2026-6011 (@mastra/core)](https://osv.dev/vulnerability/MAL-2026-6011).
-   npm registry, [easy-day-js publish times](https://registry.npmjs.org/easy-day-js).
-   StepSecurity, [Mastra npm packages compromised using easy-day-js](https://www.stepsecurity.io/blog/mastra-npm-packages-compromised-using-easy-day-js).
-   Socket, [Mastra npm packages compromised](https://socket.dev/blog/mastra-npm-packages-compromised), 17 June 2026.
-   Snyk, [A forgotten contributor account compromised the entire Mastra npm package scope](https://snyk.io/blog/a-forgotten-contributor-account-compromised-the-entire-mastra-npm-package-scope/).
-   isotope¹³, [Mastra npm org compromise](https://isotope13.ai/compendium/2026/mastra/).

One teardown per notable attack

## Get the next teardown by email

What happened, the install-path angle most coverage misses, and the rule that refuses it.

[Subscribe to teardowns](https://chain305.com/teardowns/) [Read what a package firewall catches →](https://chain305.com/what-is-a-package-firewall/)
