The 29-Million-Secret Problem: How an npm Install Turned Your Coding Agent into a Credential Scanner
Site Owner
发布于 2026-07-29
s1ngularity weaponized Claude Code, Gemini CLI, and Amazon Q through one npm install, stealing 2,349 secrets across 1,079 GitHub repos. Here's why AI-assisted code leaks credentials at 2× the baseline, and what to do this week.
The 29-Million-Secret Problem: How an npm Install Turned Your Coding Agent into a Credential Scanner
On August 26, 2025, a single npm install stole 2,349 secrets across 1,079 compromised GitHub repositories. The attackers didn't bring a credential scanner. They found a coding agent that was already installed, already authenticated, and already authorized to read the developer's entire home directory — and they handed it the job.
This is the inside story of s1ngularity, the worst supply-chain attack to weaponize Claude Code, Gemini CLI, and Amazon Q in production. It also explains why AI-assisted code leaks secrets at roughly twice the baseline rate, and what you can do this week to make sure your own setup isn't a future telemetry.js away from a similar result.
The 60-Second Version
A poisoned version of the Nx build package landed on npm. Nx pulls roughly four million downloads a week (npm package registry, August 2025), and the malicious release carried a postinstall hook pointing at a file called telemetry.js. That file did something most credential stealers don't do. It checked for an already-installed AI coding agent on the victim machine, picked from one of three, and invoked it with the flag that disables the permission prompt:
on Claude Code
#AI Agent#AI代码#AI工程#Agent
--dangerously-skip-permissions
--yolo on Gemini CLI
--trust-all-tools on Amazon Q
Then it sent the agent a prompt that reads like a routine task: recursively scan from $HOME down eight levels, find any file matching .env, id_rsa, keystore, or wallet formats, write the absolute paths to /tmp/inventory.txt, and please don't use sudo. The agent did exactly that, because nothing in its execution path told it not to.
The inventory got base64'd and pushed to a public GitHub repository created under the victim's own account. With the GitHub token now in hand, the attackers flipped the victim's private repositories to public, exposing whatever those repos held on top of the credentials lifted from the local machine.
There was no exploit. No privilege escalation. No sandbox escape. The agent was running as the developer, with the developer's filesystem access, and a single flag was all an attacker needed to redirect that access into an inventory file. The maintainers of the original s1ngularity incident notes (and Snyk's independent reconstruction) agree on the chain.
Why the Attack Worked: Three Flags Wrote the Whole Exploit
Most malware authors ship a scanner, walk the filesystem, and call it a day. s1ngularity skipped that work. It looked for an agent that was already authorized and outsourced the searching to it.
The mechanism is a 30-line lookup table that selects a CLI and a flag, then runs whichever binary it finds:
The --dangerously-skip-permissions family of flags exists because confirming every Read and Bash call gets tedious once you trust the task — and that trust posture is exactly what the attacker is counting on. The prompt asks the agent not to use sudo, and that detail is worth lingering on. sudo would prompt for a password, blow the agent's silent-execution cover, and give the game away. The attacker is hiding inside a workflow you've already approved.
This is the part of the threat model that most security teams miss. We reason about agents as new tools, then reason about what they can reach. The actual property under attack is that the agent runs as you. It carries your tokens, your git credentials, your SSH keys. The flag isn't the vulnerability. The flag just tells the agent to do exactly what you already told it to do, with no friction.
Why Coding Agents Leak at 2× the Baseline
GitGuardian's State of Secrets Sprawl 2026 reports roughly 28.65 million hardcoded secrets pushed to public GitHub in 2025, up 34% year over year. Within that total, AI-assisted code leaks credentials at approximately twice the GitHub-wide baseline. This is across-the-board, not a worst-case outlier.
The mechanism is straightforward once you watch an agent work. To wire up an API integration, the agent reads the project's .env to figure out what the key is called. From that moment, a live credential sits inside the model's working context, and from that context it can drift into a generated config, a test fixture, or a commit. Nothing in the workflow distinguishes the real value from the placeholder that belonged there. A developer reviewing the change has a beat to notice. An agent generating and committing at machine speed doesn't, and in many cases the reviewer doesn't either, because they're reading ten such diffs a day.
That's the accelerator. Without the agent, the leak rate tracks the rate at which developers handle credentials by hand. With the agent, it tracks the rate at which the agent reads .env, and that rate is much higher. The agent reads .env on every integration task. The agent reads it on every test scaffold. The agent reads it whenever a developer says "make this work," and the developer says it often.
The increased velocity of code generation is the same thing that produces more features per week and more leaks per quarter. You can't fix one without addressing the other.
The Real CVE Isn't Code, It's Identity
There is a clean way to read this incident. Forget the npm package. Forget telemetry.js. The vulnerability is that your AI coding agent and your shell account share an identity.
When --dangerously-skip-permissions is on, every command the agent runs lands in your shell history, with your UID, with access to everything you can read. When the agent generates a config file, it does so from a process context where the live credentials are sitting in memory. When it commits and pushes, it does so through your authenticated session. The same property is what causes the "agent committed my AWS key" outage and the "attacker exfiltrated my SSH key" breach. The accident and the attack need identical conditions. Neither would work if the agent had its own narrower identity.
This is also why the standard playbook — "rotate the leaked credential" — only addresses one wave. GitGuardian counted 1,100+ stolen secrets that were still valid at the time of their analysis of the s1ngularity incident. The attacker pivots from the lifted local key to whatever that key authenticated to, and the rotation job scales with the blast radius. A developer with five cloud accounts and a GitHub token just signed up for a five-account credential rotation across every tool those keys touched.
The reason attacks like this keep landing is that we keep answering the wrong question. The right question isn't "what did this agent do?" It's "what is the smallest scope of identity we could run this agent in, and why are we not doing that?"
What You Can Do This Week
The mitigation isn't theoretical. Most of it ships with a npm install of its own.
1. Audit your skip-permissions usage. Grep your shell history and CI logs for --dangerously-skip-permissions, --yolo, and --trust-all-tools. For every occurrence, ask: was the task scoped narrowly enough to justify the global grant, or did you flag-and-forget?
2. Stop letting the agent see your home directory. Tools like Docker Sandboxes run the agent in a microVM with a workspace-scoped filesystem. The microVM has its own kernel, its own filesystem, and per the project's docs, per-user configuration outside the workspace — including ~/.ssh, ~/.aws, and the .env files in question — isn't present in the VM. The agent can Read what you gave it to read, and nothing else.
3. Move credentials out of files the agent can see. Docker Sandboxes takes this further with proxy-injected credentials: secrets set with sbx secret stay in the host OS keychain, the agent inside the VM holds a sentinel placeholder (proxy-managed), and the real value gets substituted at the network boundary. The credential never enters the VM, so a compromised sandbox has nothing to exfiltrate. The same architecture works with a vault resolver — 1Password publishes an integration that fetches the real value at launch, so neither the host nor the guest ever writes it to disk.
4. Treat the prompt as untrusted. Any coding-agent invocation that asks the agent to recursively enumerate files across $HOME, read wallet patterns, or write paths to a system temp directory should be treated as malicious, the same way you'd treat a curl to an unknown IP. If your agent does that in a sandbox, it finds nothing. If your agent does that on your laptop, you have a telemetry.js problem.
None of this carries a meaningful cost. The sandbox approach runs on the same hardware you already have. The audit is grep. The vault integration is one CLI call. The reason most teams don't do this is that none of it is breaking — and breaking is what budgets respond to.
The Bigger Pattern
s1ngularity won't be the last attack of this shape. The pattern is too cheap: find a tool that runs with broad authority, prompt it like a normal task, exfiltrate whatever it touches. The natural next targets are the codegen plugins growing inside GitHub repositories, the sub-agents that run inside larger agent frameworks, and the integration paths that hand credentials to a model because the integration was designed when the model was just a summarizer.
The standard "rotate the key, write the postmortem" playbook will continue to underrate the systemic risk. The unit of compromise is no longer a server or an account. It's an identity that runs as you, with the velocity of an agent and the privileges of a developer account, and it executes without waiting for permission.
The fix is also systemic. Run the agent in a narrower identity. Move credentials to a place it can't see. Audit the flags that turn off the human-in-the-loop. None of those changes the way you ship code. They change the thing you're trusting when you ship code.
The agent isn't the threat. The fact that it runs as you is.
Data sources
GitGuardian, State of Secrets Sprawl 2026 — ~28.65M hardcoded secrets in 2025 (+34% YoY); AI-assisted code leak rate ~2× GitHub baseline.
GitGuardian, Inside the s1ngularity Credential Leak — 2,349 secrets across 1,079 compromised repos; 1,100+ still valid at time of analysis.
Snyk, Weaponizing AI Coding Agents for Malware in the Nx Malicious Package — independent reconstruction of the prompt and CLI selection logic.
Docker, Coding Agent Horror Stories Part 4: The 29 Million Secret Problem — architectural breakdown and sandbox commands.