genai
SECURITY LAB
IncidentsSupply chain

s1ngularity: A Poisoned PR Title Stole Nx's npm Token, Then AI CLIs Hunted Secrets

Critical severityReal-world incidentAugust 2025LLM04: Supply ChainLLM03: Excessive AgencyLLM02: Sensitive Information Disclosure
Status: GHSA-cxm3-wv7p-598c (no CVE listed); npm removed the nx versions about four hours after the first publish; Nx moved to npm Trusted Publishing and gated every external contributor run
Sources checked October 2026
On this page

One unescaped pull request title gave an attacker Nx's npm token, and the malware it shipped asked developers' own AI assistants to find their secrets.

WhenToken stolen 24 August 2025; malicious releases 26 August, live about four hours
TargetNx build system and plugins on npm (~6M weekly installs)
AttackerUnattributed
TechniqueGitHub Actions script injection via a PR title, then a postinstall infostealer that drove AI CLIs
AdvisoryGHSA-cxm3-wv7p-598c (no CVE listed)
ResultWiz: 1,000+ valid GitHub tokens leaked; 5,500+ private repos made public in a second wave
Attack flow
  1. 1An attacker opens a pull request whose title carries shell commands
  2. 2Nx's title-check workflow runs them with write access, and the publish job's npm token is stolen
  3. 3Malicious Nx versions drive local AI CLIs to find secrets and post them to public GitHub repos

What happened

On 26 August 2025 an attacker published malicious versions of Nx, a JavaScript build system with about six million weekly npm installs, and of several Nx plugin packages. The first bad release went up at 22:32 UTC. npm removed the affected nx versions at 02:44 UTC the next day, so they were live for roughly four hours. Users reported it in a GitHub issue about two hours in.

Installing an affected version on Linux or macOS ran a postinstall script that gathered credentials and uploaded them, encoded, to a new public repository in the victim's own GitHub account. The Nx Console extension for VS Code installed the latest nx to check versions, so opening the editor during the window could set it off. Wiz counted more than 1,000 valid GitHub tokens, dozens of valid cloud and npm credentials and about 20,000 other files exposed this way. In a second wave on 28 and 29 August, stolen GitHub tokens were used to make more than 5,500 private repositories public.

How the attack worked

The way in was a GitHub Actions workflow that validated pull request titles. It ran on the pull_request_target trigger, which executes with the base repository's permissions and secrets, and it echoed the title into a shell step without escaping it, so the title ran as part of the command. The repository also kept GitHub's older read/write default for workflow tokens. Nx reverted it on 22 August after a public post flagged the flaw, but the trigger runs the copy on a pull request's base branch, and older branches still had it.

On 24 August the attacker used that access to push a branch carrying a modified CI script, start the publish workflow against it through the API (the workflow accepted manual dispatch), and delete branches and workflow runs to hide it. When the publish job ran the altered script, it sent out the npm publishing token, which the attacker used two days later.

The payload makes this an AI security incident. Besides sweeping for wallet files, SSH keys, .env files, npm credentials and the GitHub CLI token, it looked for locally installed AI coding CLIs (Claude Code, Gemini CLI and Amazon Q) and launched each one with its permission prompts turned off, asking it to list the paths of sensitive files. Wiz reports that this AI-driven step worked in hundreds of cases and that provider guardrails sometimes stopped it. The script also added a shutdown command to the user's shell startup files.

The victim's own assistant did the searchingPart of the reconnaissance ran through a coding agent the developer had installed, with its confirmations switched off.

Root cause

Contributor-controlled text was spliced into a shell command instead of being passed as data. The workflow that handled it had write access and a path to the release job's secrets. Reverting it on the default branch left it live on older ones. And a long-lived npm token could publish from anywhere, so stealing it once was enough. On victims' machines, AI CLIs that can run tools without asking handed the malware a ready-made search tool.

What a test would have caught

A workflow linter that flags PR titles, branch names or issue bodies used directly inside run steps, run on every branch, would have caught the title check and the copies the revert left behind. Mapping what a pull request build can reach would have shown the route to the publish job. On developer machines, an alert when a package install launches an AI CLI in a no-confirmation mode would catch the payload's most unusual step.

How to prevent it

  • Treat PR metadata as data. Pass titles and branch names into steps as quoted environment variables, never interpolated into the script.
  • Keep untrusted events away from secrets. Avoid pull_request_target for jobs that touch contributor input, and make workflow tokens read-only by default.
  • Retire long-lived publish tokens. Nx moved to npm Trusted Publishing over OIDC, added manual two-factor approval to releases and now requires approval for every external contributor's pipeline run.
  • Verify provenance on install and purge known-bad versions from caches and internal registries.
  • Do not leave AI CLIs able to act unattended on machines that hold credentials. If an affected version ran, rotate GitHub, npm and cloud credentials and check shell startup files.

Feel it yourselfThe replay lab splices a pull request title into a CI shell step that holds a deployment token, the entry point that cost Nx its npm token.

FAQ

What was the s1ngularity attack on Nx?

A supply chain attack in August 2025. An attacker stole Nx's npm publishing token and released malicious versions of the nx build tool and several plugins. For about four hours, installing them on Linux or macOS ran a script that collected credentials and published them to a public GitHub repository in the victim's own account. Wiz counted more than 1,000 valid GitHub tokens leaked, and a second wave made more than 5,500 private repositories public.

How did a pull request title lead to a stolen npm token?

Nx had a workflow that checked PR titles. It ran on pull_request_target, with the base repository's permissions, and echoed the title into a shell step unescaped, so the title ran as commands with a read/write repository token. Nx had reverted the workflow on its default branch, but older branches still carried it. The attacker used that to push a branch with a modified CI script, trigger the publish workflow against it and send out the npm token.

How do you defend against CI script injection and AI CLI abuse?

Pass PR metadata into steps as quoted environment variables, never interpolated into scripts. Keep untrusted events away from secrets and make workflow tokens read-only. Replace long-lived publish tokens with OIDC trusted publishing and check provenance on install. On developer machines, do not leave AI CLIs able to run tools without confirmation, and rotate credentials if an affected version ran.

Replay this attack
Open a pull request whose title is spliced into a CI shell step and read the deployment token out of the build log — the PR-title injection that started the s1ngularity chain at Nx.
Open the live lab
A live, sandboxed lab. It recreates the technique, not this exact product.