---
title: "Inside the Mastra npm supply chain attack"
description: "On June 17, a typosquatted npm package and stolen contributor credentials gave attackers access to 144 Mastra packages with nearly a million weekly downloads. Here's how the attack unfolded, how the malware evaded detection, and how to protect your pipeline."
canonical_url: "https://cloudsmith.com/blog/inside-the-mastra-npm-supply-chain-attack"
last_updated: "2026-06-17T10:30:39.174Z"
---
# Inside the Mastra npm supply chain attack

AI dev frameworks are becoming a key target for software supply chain attackers. The logic is rather simple: if you can compromise the framework itself, you have the ability to compromise highly sensitive infrastructure today. That includes LLM API keys, cloud provider secrets, the kind of credentials that would allow an attacker to move laterally from there.

On June 17, a sophisticated software supply chain incident, specifically targeted **Mastra**, through a simple typosquatted [**easy-day-js**](https://www.stepsecurity.io/blog/mastra-npm-packages-compromised-using-easy-day-js) package name. Mastra is a popular open-source TypeScript framework used for building AI agents and [RAG pipelines](https://www.ibm.com/think/topics/retrieval-augmented-generation).

By hijacking a former contributor’s creds, attackers were able to inject a malicious dependency across 144 packages in the Mastra ecosystem. With core components like [**`@mastra/core`**](https://www.npmjs.com/package/@mastra/core) pulling nearly a million weekly downloads, the blast radius of an attack like this is massive. In this blog we’ll look at how the attack unfolded, how the malware evades detection, and how developers can secure their environment today.

## How the attack unfolded

The attackers executed a multi-stage campaign that relied on a blend of account takeover, social engineering (via package mirroring), and a dynamic second-stage runtime payload designed to bypass traditional static analysis.

The groundwork was laid a day prior to the primary breach. An npm user named `sergey2016` published version `1.11.21` of a package called `easy-day-js`. At this point, the package appeared entirely benign, indicating it was a fully functional clone of the highly popular [**`dayjs`**](https://www.npmjs.com/package/dayjs) date library.

By copying the original library’s version numbering, MIT license, and author metadata ([**`iamkun`**](https://www.npmjs.com/~iamkun?page=1)), the attackers ensured that any casual visual or automated sanity check of the package structure would look clean - one of the many ways the attacker is evading detection.

In the next stage, the threat actor updated the `easy-day-js` package to version `1.11.22`. Again, this version looked identical to its predecessor but introduced a relatively small, obfuscated file named `setup.cjs`, along with an execution trigger in the `package.json`. Following a wave of community concern, `npm` recently announced it would [**disable postinstall scripts by default**](https://opensourcemalware.com/blog/npm-v12-security-theatre) in its next major version. This is why.

```json
{
  "_key": "922ea43c7c58",
  "_type": "code",
  "code": "\"scripts\": {\n  \"postinstall\": \"node setup.cjs --no-warnings\"\n}",
  "filename": null,
  "language": "javascript",
  "markDefs": null
}
```

The `--no-warnings` flag was explicitly used to suppress the Node.js runtime environment warnings, which ensured devs remained unaware during the installation.

A few minutes later, the attackers struck the **Mastra** ecosystem. They hijacked the `npm` account belonging to `ehindero`, a legitimate former Mastra contributor whose organisational scope access had never been revoked. From there, they used an automated script that rapidly populated the `@mastra/*` org and mass-published updates to **144 packages** in just over an hour. Each package was updated to include the malicious dependency:

```json
{
  "_key": "a6154d1e4142",
  "_type": "code",
  "code": "\"dependencies\": {\n  \"easy-day-js\": \"^1.11.21\"\n}",
  "filename": null,
  "language": "javascript",
  "markDefs": null
}
```

Because of the way that `npm` resolves semantic versioning (`^`), any fresh install or build runner pulling the clean pinned version `1.11.21` was automatically forced to resolve and download the malicious `1.11.22` patch. From an execution perspective, when a dev or automated CI/CD pipeline runs `npm install`, the `postinstall` hook fires immediately, which causes the `setup.cjs` script to initiate a highly-evasive first-stage dropper into the environment.

## How the malware evades detection

The underlying mechanics of the first-stage execution reveal a strong emphasis on evasion and anti-forensics. It has four clear evasion tactics:

1. **TLS cert bypassing**: The `NODE_TLS_REJECT_UNAUTHORIZED = '0'` allows the script to safely reach out to an attacker’s C2 infrastructure even if the interception tools or self-signed proxies attempt to inspect or block the traffic.
2. **Process detachment**: By leveraging the `detached: true` and `.unref()`, the second-stage payload is then able to spin out into its own OS process. When the core `npm install` routine finishes or is terminated, the malware continues running silently in the background.
3. **Self-deletion**: Finally, the script finishes by calling `fs.rmSync(__filename)`. By removing the `setup.cjs` immediately after execution, the installer leaves behind a clean directory tree, baffling standard post-incident file scanners.
4. **Missing attestations**: Mastra utilises npm's trusted publisher flow inside their CI pipeline, generating robust Sigstore-backed SLSA provenance attestations for authentic releases. However, while Mastra generated provenance, their `npm` org policy **_did not enforce it_**.

The tragedy of this fourth evasion tactic is that it was entirely preventable. Because a strict verification policy wasn't required on the registry side, `npm` willingly accepted the attacker’s mass updates pushed directly from a stolen PAT, even though they dropped the cryptographic provenance signature. Any client configuring a strict signature-verifying installation policy would have immediately blocked this entire campaign.

## How developers can secure their environments today

By using open infrastructure tooling like `osv-scanner`, organisations can detect the malicious `easy-day-js` package as well as the various malicious packages published to the compromised Mastra org on June 17.



- `easy-day-js` ([**MAL-2026-5979**](https://github.com/ossf/malicious-packages/blob/6cd7ce45f8d8acf40e00150580af7443c2351d65/osv/malicious/npm/easy-day-js/MAL-2026-5979.json#L12))
- `@mastra/agent-browser` ([**MAL-2026-5996**](https://github.com/ossf/malicious-packages/blob/6cd7ce45f8d8acf40e00150580af7443c2351d65/osv/malicious/npm/%40mastra/agent-browser/MAL-2026-5996.json#L15))



However, security shouldn’t just be reactive. Developers can’t just wait for security advisories. While `npm` has stepped in to pull any compromised versions from the registry, if you had run an install during the exposure window, before these advisories were published, you should treat the environment as compromised.

Securing your software supply chain requires a proactive architecture. If you're managing external dependencies using Cloudsmith, here’s how you could mitigate attacks like `easy-day-js`:

1. **Enforce upstream cooldown policies**: You’ll be hearing this from us a lot, but cooldown policies really are one of the most effective solutions to this recent wave of open-source supply chain attacks. Malicious packages are often caught and reported within hours of publication. By establishing an upstream proxy with a cooldown window (let’s say, holding newly-published packages for _<u>one or two days</u>_ before they become eligible for download), you create a natural buffer that keeps automated pipeline scripts from pulling zero-day dependencies.
2. **Lock down your semantic versioning**: As highlighted earlier, you should never rely purely on range-based specifiers (either `^` or `~`) for high-value upstream dependencies. Where possible, ensure a strict `package-lock.json` or a `yarn.lock` is enforced across all local and CI/CD builds. This guarantees that your builds anchor exclusively to known, cryptographically hashed versions.
