Claude Code Security: Is It Safe? Three Incidents and Our Scan

Mert DüzgünPublished 8 minute read

Claude Code had three public security incidents between October 29 and November 9, 2026: a tampered copy of its editor extension, saved shell approvals that leaked secrets to GitHub, and an email leak in a request header. We also scanned 2,195 repos behind the CCM catalog on November 14, 2026. Below are checks to run before you install a plugin, skill, mod or Model Context Protocol (MCP) server.

Is Claude Code safe

By default Claude Code asks before it runs shell commands or edits files. The permissions docs say these rules "are enforced by Claude Code, not by the model," so a prompt or a CLAUDE.md file can't change them. Only one of this fall's incidents was outside Claude Code: a tampered build in Cursor's store. The other two came from Claude Code's own behavior.

Three incidents in fall 2026

A tampered Claude Code extension on the Cursor marketplace

On October 29, the Claude Code extension on Cursor's extension marketplace was replaced with a version that planted a Secure Shell (SSH) backdoor. BleepingComputer reports it was live for about 11 hours, from 2:27 a.m. to 1:35 p.m. Pacific Time per Cursor's notice, and that up to 5,000 developers were exposed. Cursor told Help Net Security the version "was not developed by Anthropic."

Phorion's write-up lists 2.1.313 and, after Cursor revised its notice, 2.1.312. The payload added an SSH key with the comment svc-telemetry to ~/.ssh/authorized_keys, opened a reverse SSH tunnel and sent host details to the attacker's server. Phorion found that coding errors likely made the SSH step fail on many machines. Phorion says uninstalling the extension does not remove the backdoor.

Which stores were affected is disputed. Help Net Security reports that Phorion spotted 2.1.313 on Open VSX, and that Manifold Security disputes this; Phorion's revision log later corrected the store to Cursor. The Hacker News reports that Anthropic security engineer David Dworken said the official VS Code and Open VSX versions "are not affected and this only impacts Cursor users."

If you used Cursor that day, check for the key and the macOS startup files.

  1. In your terminal, look for the key:

    grep svc-telemetry ~/.ssh/authorized_keys
    
  2. In your terminal, look for the startup files:

    ls ~/Library/LaunchAgents/com.apple.sysmond.plist ~/.config/.smt
    

If either prints a match, follow Phorion's remediation steps.

"Don't ask again" approvals saved secrets to public repos

When you pick "Yes, and don't ask again" on a Bash prompt, Claude Code saves the command, or a prefix of it, as an allow rule in .claude/settings.local.json. If the command had a password or key in it, that value is now in the file in plain text. Apiiro published research on this on November 5. Its page did not load for us; these numbers come from Let's Data Science and BuildMVPFast. We could not confirm these counts.

Apiiro reported 1,122 of 104,185 public settings.local.json files with a real secret, 1,379 distinct secrets in current files, and 2,539 when it counted file history, the shared settings.json and saved transcripts. It reported that more than a third of the secrets open a database directly. Neither Gitleaks nor TruffleHog flagged 215 of the leaking files; Apiiro traces that gap to passwords typed into commands, such as after PGPASSWORD=. On Hacker News on November 7, Boris Cherny, who leads Claude Code, wrote "Historically Claude Code has not done secret scrubbing," per BuildMVPFast, and that the team is "looking into what we can do to prevent this," per Let's Data Science.

The settings docs say Claude Code adds **/.claude/settings.local.json to your global git excludes file the first time it writes the file. That protects your machine. It does not cover a file you created by hand, or one already committed.

Account email in the User-Agent header

GitHub issue #107757, opened November 5 on v2.1.318, reports that Claude Code sent the account's email address in the User-Agent header during web searches. A maintainer replied that a built-in mod, cc-plugin-privacy, blocks this "in v2.1.317 and later" and is on by default, though the report itself was on v2.1.318. On November 9 a user (not a maintainer) reported that the mod did not block a curl command on v2.1.319 and asked whether it covers only Claude Code's web tools. No maintainer had confirmed this as of November 15, and the issue is open.

What we found in the repos behind CCM

CCM lists skills and marketplaces from 6,321 GitHub repos. On November 14, 2026 we took the top 2,200 by GitHub stars, read the file tree of each default branch, and checked a few files by pattern. 2,195 scans finished (5 failed). We counted matches and never stored or published a value. The limits: we looked at the default branch only (no history, no forks), at the most-starred repos only, and a pattern match is not proof that a key is real or live.

File we looked for Repos Files What we found
.claude/settings.local.json 42 45 0 files with secret-shaped strings
.env files 60 142 1 repo with what looks like a private key
.mcp.json 395 720 0 files with secret-shaped values
Hook configs 477 n/a 3,597 command handlers, 10 call curl or wget

None of the 45 settings.local.json files had a secret-shaped string. They hold 672 allow rules, 563 of them for Bash. Our 45 files are a small sample next to Apiiro's 104,185, and they did not show the problem.

60 repos commit a .env file. Our pattern flagged 13 of them, and we then checked each hit by hand. Most were test fixtures, placeholders, local demo keys or keys that are public by design, such as browser search keys. Two repos commit keys on purpose: one marks a maps key "for testing only", and one ships local development defaults. One repo has what looks like a private API key. We did not test it, and we do not publish the name.

Those 10 hook commands are the lines to read before you install.

How Claude Code permissions work

Permission rules live under permissions in a settings file, in three lists: allow, ask and deny. Per the permissions docs, rules are checked in that order: deny, then ask, then allow, and the first match wins. A deny rule from any file beats an allow rule from any other file.

This example, adapted from the settings docs, lets lint and tests run without a prompt and blocks reads of .env files:

{
  "permissions": {
    "allow": ["Bash(npm run lint)", "Bash(npm run test *)"],
    "deny": ["Read(./.env)", "Read(./.env.*)"]
  }
}

To see every rule and the file it came from:

  1. Inside Claude Code, type:

    /permissions
    

A Read deny rule does not stop a script that opens the file itself; for that the docs point to the sandbox.

How to check your own repo

  1. In the project's own .gitignore, add this line, so every clone ignores the local settings file:

    .claude/settings.local.json
    
  2. In your terminal, at the repo root, check whether the file was ever committed, on any branch:

    git log --all --oneline -- .claude/settings.local.json
    
  3. If that prints commits, rotate any secret in the file first. Deleting the file does not remove it from history, forks or clones.

  4. In your terminal, stop tracking the file:

    git rm --cached .claude/settings.local.json
    
  5. In your terminal, commit the change:

    git commit -m "Stop tracking settings.local.json"
    

When you approve a command that needs a secret, keep the secret in an environment variable so the saved rule holds $VAR, not the value.

How to check a plugin, skill, mod or MCP server before you install it

A plugin's settings hooks are in its hooks/hooks.json. Open it on GitHub and read every command. Look for curl and wget. Our post on Claude Code hooks covers the events.

Mods run inside Claude Code. The mods docs say a mod "is code that runs with your permissions," can read your environment variables and isn't sandboxed. You can list what a mod does before you load it.

  1. Clone the plugin's repo to your machine.

  2. In your terminal, run this (replace ./some-mod with the path to the cloned plugin):

    claude plugin validate ./some-mod
    

The hooks: and calls: lines show the events it handles and what it asks Claude Code to do. To start one session with no installed mods or other customizations:

  1. In your terminal, run:

    claude --safe-mode
    

More in our post on Claude Code mods.

For MCP servers, read the env block in .mcp.json before you approve it. The MCP docs say Claude Code asks before it uses a project's servers in an interactive session, and that ${VAR} references expand from your shell. Commit ${API_KEY}, never the key. In claude -p runs it loads them without asking.

On CCM, skills and marketplaces must come from public GitHub repos, and we reject archived repos and repos that link to installers or binaries inside them. These checks do not replace reading the code.

What we would install first

These are in our catalog and add a check before risky actions:

  • git-guardrails-claude-code sets up hooks that block git push, reset --hard, clean and branch -D before they run.
  • atc-blast-radius is a mod that holds rm -rf, force pushes and migrations and shows what they would delete.
  • git-safety adds pre-commit secret scanning with Gitleaks and TruffleHog (these catch token formats, not passwords typed into commands).
  • skill-security-auditor scans agent skills for prompt injection, data exfiltration and unsafe file operations.

To install the first two:

  1. In your terminal, install the skill:

    npx -y skills add mattpocock/skills --skill git-guardrails-claude-code --agent claude-code
    
  2. Inside Claude Code, add the mod's marketplace:

    /plugin marketplace add atc-net/atc-agentic-toolkit
    
  3. Inside Claude Code, install the mod:

    /plugin install atc-blast-radius@atc-agentic-toolkit
    

More in /skills, /plugins and /mcp.

More from the blog