Safeguard
AI Security

The Nx Attack Turned AI Coding Agents Into the Malware

In August 2025, attackers hijacked Nx's npm publish token and used Claude Code, Gemini CLI, and Amazon Q as the exfiltration engine — leaking 2,349 secrets.

Safeguard Research Team
Research
6 min read

On August 26, 2025, at roughly 22:32 UTC, a compromised npm publish token let attackers push eight malicious releases of nx and several @nx/* packages — devkit, enterprise-cloud, eslint, js, key, node, workspace — plus Nx Powerpack. The packages stayed live for somewhere between four and five hours before Nx pulled them, according to Nx's own postmortem published at nx.dev/blog/s1ngularity-postmortem. That window was enough: a postinstall script scanned each infected machine for locally installed AI coding CLIs — Claude Code, Gemini CLI, and Amazon Q — and launched them with permission-bypass flags (--dangerously-skip-permissions, --yolo, --trust-all-tools) alongside a prompt instructing the agent to recursively enumerate cryptocurrency wallets, SSH keys, .env files, and credential stores. The harvested data was written to /tmp/inventory.txt, then pushed to public GitHub repositories named s1ngularity-repository-<N>. Nx reported 2,349 distinct secrets leaked, dominated by GitHub OAuth tokens and personal access tokens, alongside npm, cloud, and AI-provider API keys. The incident, corroborated by Snyk, Endor Labs, Socket, Semgrep, Orca, and The Hacker News, is one of the first documented cases where malware didn't ship its own stealer — it coerced a legitimate, already-trusted AI agent into doing the reconnaissance and exfiltration for it.

How did attackers get a valid npm publish token for a project as widely used as Nx?

The entry point wasn't a stolen credential in the traditional sense — it was a GitHub Actions workflow Nx had added on August 21, 2025, just five days before the attack, to automate parts of its release process. According to Nx's postmortem, the workflow was injectable via a crafted pull request title, a known class of GitHub Actions vulnerability where untrusted input (PR titles, branch names, issue bodies) gets interpolated directly into a shell step instead of being passed as a sanitized environment variable. An attacker who can control that string can smuggle arbitrary commands into the workflow's execution context. Because the workflow ran with access to Nx's npm publishing credentials, a single injected command was enough to exfiltrate the token and publish the eight malicious package versions directly to the registry — no need to compromise a maintainer's laptop or guess a password. GitHub Actions injection via untrusted trigger data has been a recurring root cause across supply chain incidents for several years; Nx's case is notable mainly for what happened downstream of the token theft, not the theft itself.

What made this attack different from a typical malicious-package postinstall script?

Most npm postinstall malware ships everything it needs: a bundled stealer binary, a hardcoded exfiltration endpoint, obfuscated JavaScript that reads ~/.aws/credentials or ~/.ssh/id_rsa directly. The Nx payload did something structurally different — it checked whether the host already had Claude Code, Gemini CLI, or Amazon Q installed, and if so, invoked them as subprocesses with flags that suppress the human-in-the-loop confirmation these tools normally require before taking file-system or shell actions. The prompt handed to the agent was a plain-language instruction to search for wallets, keys, and credentials, which is exactly the kind of task these agents are designed to perform well when a developer asks in good faith. The malware didn't need to write its own file-enumeration logic or understand every possible credential file format across a heterogeneous developer machine — it delegated that work to a general-purpose reasoning tool that was already sitting there, already trusted, and already capable.

Why does bypassing an AI agent's permission prompts matter so much here?

Claude Code, Gemini CLI, and Amazon Q all ship default confirmation gates before executing file reads outside a project directory, running shell commands, or performing bulk operations — specifically because a coding agent with broad file-system access is a powerful primitive that shouldn't act unsupervised on sensitive paths. Flags like --dangerously-skip-permissions, --yolo, and --trust-all-tools exist for legitimate automation use cases: CI pipelines, sandboxed containers, and scripted batch jobs where a human isn't available to click "approve." The Nx attack shows what happens when that same flag is invoked by malicious code on a developer's own workstation rather than in an isolated CI runner. The agent had no way to distinguish "a trusted automation pipeline is asking me to scan for credentials" from "a malicious postinstall script is asking me to scan for credentials" — the flag strips the one control (human confirmation) that would have caught the mismatch. This is a defense-in-depth failure, not a bug in any single agent: the flags did exactly what they're documented to do.

What does this reveal about trusting the install step in modern JavaScript projects?

npm's postinstall (and preinstall) lifecycle hooks execute arbitrary code the moment a package is fetched, before a developer ever opens the source or runs the application — a design decision that predates today's supply chain threat landscape by well over a decade. Socket and Semgrep's independent writeups on the Nx incident both emphasized that the attack required zero interaction beyond npm install completing normally on a machine that happened to have an AI CLI present; there was no separate "run the app" step where a user might notice anomalous behavior. The npm ecosystem has hosted repeated waves of similar postinstall-triggered attacks for years — this is the pattern the event-stream compromise established in 2018 and that typosquat campaigns have repeated regularly since — but Nx demonstrates that the payload delivered through that same fifteen-year-old mechanism has grown considerably more capable, simply because the tools already present on developer machines have grown more capable.

How should teams defend against this class of attack going forward?

The most durable fix is treating install time as an enforcement point, not just a fetch step — evaluating a package's registry metadata, publish history, and archive contents before it ever reaches a developer's disk, rather than trusting the registry implicitly. Safeguard's Package Firewall does this as an install-time proxy in front of npm and pip: because it sits on the fetch path, it sees every transitive dependency pull, not just top-level installs, and its behavioral analyzer inspects package contents statically — without executing anything — to surface indicators like unusual postinstall hooks before install completes. Safeguard's malware classification model, Eagle, scores install-script behavior, egress patterns, and credential-harvesting indicators specifically, which maps closely onto the postinstall-plus-exfiltration shape of the Nx attack, though no static or behavioral scanner today specifically models "spawns a locally installed AI CLI with permission-bypass flags" as its own signal — that's a newer sub-pattern the industry is still building detections for. Organizationally, the more immediate control is policy: never run AI coding agents with permission-bypass flags outside a sandboxed, non-production environment, and treat any CI workflow that interpolates untrusted PR or issue text into a shell step as an immediate audit priority.

Never miss an update

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