cd /news/ai-agents/cursor-s-breach-chain-started-in-pla… · home › topics › ai-agents › article
[ARTICLE · art-169846] src=dev.to ↗ pub= topic=ai-agents verified=true sentiment=↓ negative

Cursor's breach chain started in plain-text agent traces: 23,276 public repos carry the same leak

Cursor published a final incident report on November 13 tracing a breach that began with working credentials stored in plain text inside agent transcripts, which attackers used to reach internal systems and poison a marketplace cache; the company rotated all internal credentials, moved inference traffic off the vendor, and added secret scanning. Separately, GitGuardian found 31,088 distinct secrets in .claude/settings.local.json files across 23,276 public GitHub repositories, 5,343 of them still valid, and Apiiro found that gitleaks and TruffleHog missed 215 of 1,122 files containing real secrets.

by read4 min views4 publishedNov 15, 2026

Cursor published its final incident report on November 13, two weeks after a malicious copy of Anthropic's Claude Code extension appeared in its VS Code extension marketplace. I read the whole thing. The interesting part is not the extension. It is the first link in the chain.

The report reconstructs the attack like this:

Read step 3 again. The breach did not start with a zero-day. It started with working credentials sitting in plain text inside stored agent transcripts. Everything after that was climbing. If you run sessions outside Privacy Mode, or you paste a token into a command to unblock an agent at 6pm, you are producing the same artifact class that made step 3 possible.

Cursor says traces were exposed for fewer than 0.05% of users, and API credentials for less than 0.01% of customers. Small percentages, and they still yielded enough working credentials to reach internal systems and poison a marketplace cache.

That is the arithmetic of stored secrets. An attacker does not need a large share of users leaking credentials. One valid key with the right scope is enough. Cursor's own response reads like agreement: the team rotated every credential in use across internal systems, not just the exposed ones, moved all inference traffic off the vendor, and added secret scanning across internal data sources.

Two weeks later, on the file side of the same problem, GitGuardian published a count that dwarfs the numbers Cursor had to contain. Per CSO Online's report of the research: 31,088 distinct secrets in .claude/settings.local.json files across 23,276 public GitHub repositories, with 5,343 of them still valid when detected. Of the occurrences GitGuardian could check, 67% were working credentials.

I wrote about the mechanism when Apiiro's smaller count came out: approving a command with "Yes, and don't ask again" saves the exact command string, secret included, into a project-level file. That article covered 1,379 distinct secrets in 1,122 files. Apiiro counted default branches. GitGuardian crawled every public commit back to January 2025 and found twenty times more.

The pattern holds everywhere agent tooling writes down what happened:

.claude/settings.json, carried another 8,271 secrets, 1,283 of them valid, in GitGuardian's COPY . . ignores your .gitignore. One valid Cloudflare token appeared across 559 image tags. Apiiro ran gitleaks and TruffleHog, the two most used open-source secret scanners, over all 104,185 public copies of the file. Of the 1,122 files holding a real secret, 215 were flagged by neither, close to one in five. The reason is structural. Scanners look for provider formats, a prefix followed by high-entropy string. A password after PGPASSWORD=, or inside an sshpass command, is just a word on a command line. Agent artifacts record what ran, not what was sensitive, so the exact place agents write secrets is the place format-based detection covers worst.

Order your cleanup by how the attacker actually used the data, not by how easy each step is.

First, rotate anything you ever pasted into a vendor support chat or ran through a session whose logs you do not control. Cursor's report lists "some credentials users had sent to the Cursor support team" among the exposed data. That class of credential outlives your account with the vendor.

Second, rotate credentials that reached a committed file, then clean the file. Rotation first, always, because git history and forks keep old copies. Check whether the file was ever committed on any branch:

git log --all --full-history --oneline -- .claude/settings.local.json

Third, rotate anything baked into a published image. Deleting the file from the repo does not recall published tags; one database password in GitGuardian's data sits in 643 tags across seven image repositories.

Run this audit across all five, in one pass:

.claude/settings.local.json, the file behind the 23,276 repos..dockerignore to stop it. A quick pattern probe for the config side:

grep -rnE "(PGPASSWORD=|sshpass|Bearer |AKIA[0-9A-Z]{16}|BEGIN (RSA|OPENSSH) PRIVATE KEY)" \
  .claude ~/.claude/settings.json 2>/dev/null

It will not catch everything, that is the one-in-five lesson, but it catches the shapes scanners skip.

Four habits remove most of this surface:

.claude/ and .env* to

.claude/
**/.claude/
.env*
**/.env*

Per Ground Truth's coverage of CSO's reporting, Boris Cherny, who leads Claude Code, said the tool has not done secrets scrubbing and that built-in secret scanning and an auto mode are being explored. Until something ships there, the file-level discipline is on you.

The extension malware was the loud part, and I covered the config-boundary questions when it dropped. The quiet part is that a bucket of 2025 transcripts contained working credentials at all. Your exposure is probably not a marketplace cache. It is the artifacts your own tooling writes on every machine you own, and the copies of those artifacts you never audited. Rotate first, then audit, then write the rules that keep the vault empty.

If you want the incident timeline and the indicators of compromise, the primary sources are Cursor's report and their October 30 security notice. My earlier piece on what agent configs can and cannot contain covers the extension side of this event.

── more in #ai-agents 4 stories · sorted by recency
── more on @cursor 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/cursor-s-breach-chai…] indexed:0 read:4min 2026-11-15 · —