Claude Code security: what the agent protects, and what you still own

Claude Code security has two parts: Anthropic guards the agent on your machine with permission modes, a sandbox and a trust dialog, and patches its flaws, while the app it writes is entirely yours. Claude Code runs no database, auth or hosting, and its review tools read code, never your live site. Review the code, then test the deployed app, where open tables, leaked keys and missing owner checks show.

The team behind Keybrum's attacksUpdated 14 min read

In short

  • Claude Code has no hosting, database or auth of its own: every security decision in your app lives in your repository and your cloud accounts.
  • For the agent: stay on a current version, keep the trust dialog, deny reads of .env files and turn on the sandbox.
  • /security-review, the security-guidance plugin and the Claude Security plugin all read code. Anthropic's docs say the review covers your checkout, not a running site or deployed service.
  • The leaks that reach production: tables without row level security, secret keys behind a NEXT_PUBLIC_ or VITE_ prefix, routes that skip the owner check, unsigned webhooks, open AI routes.
  • CLAUDE.md is context that Claude can miss. Back your rules with hooks and deny rules, and attack the live app after every deploy.
On this page

Two questions behind "Claude Code security"

Claude Code is Anthropic's coding agent. It runs in your terminal, your IDE, the desktop app or a cloud session, and it reads your repository, runs commands and writes code. Its security means two things: can the agent harm my machine or leak my secrets while it works, and can the app it built go online without leaking? The first is mostly Anthropic's job. The second is yours, and it is where user data leaks.

Unlike an app builder that hosts your app, Claude Code has no database, auth service, hosting or secret store: it writes files into your repository, and whatever it sets up in Supabase, Vercel or Stripe lives in your accounts.

AreaWhat Anthropic handlesWhat you handle
What the agent may run on your computerPermission modes, the auto mode classifier, the Bash sandbox, the workspace trust dialogWhich mode you use, your allow and deny rules, what you approve
Flaws in Claude Code itselfFixes, public advisories, auto-updateStaying on a current version
Cloud sessionsOne isolated VM per session, GitHub credentials kept out of the VM, network limitsWhich repositories and secrets you connect
Your app's database, auth, keys and hostingNothing: Claude Code does not run themAll of it
Security review of the code/security-review, the security-guidance and Claude Security plugins, Code Review on Team and EnterpriseRunning them, reading the diff, testing the deployed app
Based on Anthropic's Claude Code security and permissions documentation, November 2026.

How Claude Code protects your machine

Anthropic's safeguards cover what the agent may do on your computer:

  • Permission modes. From version 2.1.283, interactive terminal and VS Code sessions start in auto mode: a separate classifier model reviews actions and blocks the risky ones. Its default block list includes curl | bash, sending sensitive data to outside endpoints, force pushes, production deploys and migrations, and commits that would send secrets outside the repository. Manual mode lets Claude read freely and asks before most edits, shell commands and network calls.
  • Sandbox. /sandbox turns on OS-level filesystem and network isolation for shell commands, with Seatbelt on macOS and bubblewrap on Linux and WSL2. By default, sandboxed commands can write only to the working directory, a temp directory and folders you added. Reads stay open on most of the machine, including ~/.ssh, so deny the secret paths yourself.
  • Trust dialog. Opening a folder for the first time asks whether you trust it, and MCP servers declared in a project's .mcp.json need their own approval. A claude -p run shows neither prompt.
  • Cloud sessions run in an isolated VM managed by Anthropic. Your GitHub credential stays on Anthropic's servers and never enters the VM.

The tool has had real flaws. The anthropics/claude-code repository lists more than 30 published security advisories, mostly ways to get past the permission checks, the sandbox or the trust dialog. Before version 2.1.53, a committed .claude/settings.json could set the default mode to bypassPermissions and silently skip the trust dialog on first open (CVE-2026-33068). Before 2.0.65, a repository could point ANTHROPIC_BASE_URL at its own server and receive your API key before you confirmed trust (CVE-2026-21852). Both are fixed. The advisory for the second says installs on auto-update already have the fix; if you update by hand, run claude --version and claude update.

json
{
  "permissions": {
    "deny": [
      "Read(./.env)",
      "Read(./.env.*)",
      "Read(./secrets/**)"
    ]
  },
  "sandbox": {
    "enabled": true
  }
}
.claude/settings.json: keeps Claude's file tools away from env files and sandboxes shell commands. On their own, deny rules cover Claude's tools and commands such as cat, not a Python or Node script that opens the file itself. With the sandbox on, Claude Code also applies these Read deny rules to sandboxed commands at the OS level. Hooks and local MCP servers run outside the sandbox.

The stack Claude Code writes, and where it leaks

Claude Code has no default stack: it uses your repository's framework, or the one you ask for. A web app with accounts and payments still ends up with the same few pieces, and each has a mistake that stays invisible in a demo, because the app works for its owner:

PieceThe common mistakeWhat a stranger can do
Database (Supabase, Postgres)A migration runs create table without enabling row level securityRead or change every row with the public key from your JavaScript
Environment variablesA secret key gets a NEXT_PUBLIC_ or VITE_ prefix so the frontend can call an APICopy your OpenAI, Stripe or Supabase secret key from the bundle
API routes and Server ActionsThe handler checks that someone is signed in, not that the record is theirsRead or edit other users' data by changing an id
Stripe webhooksThe handler trusts the JSON without verifying the Stripe-Signature headerMark an order as paid without paying
AI routesA /api/chat route with no session check and no rate limitRun your model on your bill
Build and hostingSource maps, a .env file or a .git folder served with the siteRead your source code or your server secrets

None of this is unique to Claude Code. What changes is the pace: an agent writes migrations, env files and route handlers in minutes, often in a repository nobody else reviews.

What /security-review and Anthropic's scanners catch

Anthropic's review layers catch real bugs in the code they read: injection, unsafe DOM calls, missing authorization. Use them.

ToolWhen it runsWhat it readsAvailability
/security-reviewWhen you type itThe diff between your branch and the default branch of your origin remoteBuilt into Claude Code
Security guidance pluginOn each edit, at the end of each turn, on each commit Claude makesThe changes Claude writes in the sessionAll plans
Claude Security pluginOn demandA repository or a diff, with patches you apply yourselfBeta, paid plan, API or cloud provider
Code ReviewOn each pull requestThe pull request and the codebaseTeam and Enterprise
claude-code-security-review GitHub ActionOn each pull requestThe changed filesYour Claude API key
Claude Security (managed)ContinuouslyConnected repositoriesPublic beta, Enterprise

All of them read source code. Anthropic's security-guidance docs say it plainly: the review "reads the source code in your checkout, not a running site or deployed service." Many leaks in AI-built apps are not in the code at all:

  • RLS policies and storage buckets changed by hand in the Supabase dashboard.
  • Environment variables set in the Vercel or Netlify dashboard.
  • What actually got deployed: a stale branch, a preview wired to production data, source maps.
  • Behaviour across accounts: only two real sessions show whether user B can read user A's invoice.

The GitHub Action also leaves out rate limiting findings by default, the class an open AI route falls into, and Anthropic says it is "not hardened against prompt injection attacks": run it on trusted pull requests only.

For a deeper audit, Cloudflare's open-source security-audit skill runs inside your agent, with a fresh verifier for every candidate. Its README notes that one run found roughly half of what repeated runs found. Keybrum's code audit runs this skill, then tries to prove each finding on the live app.

How to check an app Claude Code built

Five checks, on your own project only. The first three change nothing. The last two use your deployed app the way a visitor would.

1. Review the branch before you merge

In Claude Code, run /security-review on your feature branch. It needs an origin remote. Read each finding and ask Claude to fix the real ones in the same session.

2. List the tables without row level security

sql
select schemaname, tablename
from pg_tables
where schemaname = 'public'
  and rowsecurity = false
order by tablename;
Run it in your project's SQL editor. Each row is a table that any role holding a grant can read and write in full, which on projects with the default grants includes visitors using your public key.

The Security Advisor in the Supabase dashboard flags the same tables, plus policies that could be stricter and exposed sensitive columns. The Supabase RLS checker bundles the queries and reviews your policies line by line, and the RLS guide has policies for the common cases.

3. Search your build for secret keys

bash
npm run build
grep -rlE "sk_live_|rk_live_|sk-proj-|sk-ant-|sb_secret_|PRIVATE KEY-----" .next/static dist 2>/dev/null
Lists the files your build sends to browsers (.next/static for Next.js, dist for Vite) that contain a Stripe, OpenAI, Anthropic or Supabase secret key, or a private key. Any match is a key to rotate today.

Legacy Supabase keys are JWTs, so the service role key does not match a prefix. Paste suspicious strings into the API key leak checker: it names each key and says whether it belongs in a browser.

4. Open user A's data as user B

Sign up twice, in two browser profiles. As A, create something private: an order, a note, an invoice. Copy its URL, or the API request from the network tab. Replay it as B. If B sees A's data, so can every other user. The IDOR guide covers the API side of this test.

5. Call your sensitive routes signed out

bash
# Should answer 401: no session
curl -i -X POST https://your-app.example/api/chat \
  -H "content-type: application/json" \
  -d '{"message":"hello"}'

# Should answer 400: no Stripe-Signature header
curl -i -X POST https://your-app.example/api/webhooks/stripe \
  -H "content-type: application/json" \
  -d '{}'
Against your own app only. A model's answer from the first call means anyone can spend your AI credits. A 200 from the second usually means the handler never checks the signature.

Fixes, with prompts to give Claude Code

Name the rule and the result you expect in the prompt: "make it secure" gets a vague change. Four fixes close most of the table above.

Tables: RLS in the same migration

sql
alter table public.invoices enable row level security;

create policy "Owners read their invoices"
on public.invoices for select
to authenticated
using ((select auth.uid()) = user_id);
Enable RLS, then add one policy per operation the app needs. With RLS on and no policy, the table is closed to visitors and users alike.
text
Check every migration in supabase/migrations. Every new table must enable
row level security in the same migration, with policies that limit rows to
(select auth.uid()). List any table that should stay public and say why.
Never use the service role key in client code, and never disable RLS to
make something work.
Prompt for Claude Code.

Routes and Server Actions: check the owner, not only the session

Next.js documents why this matters: an exported Server Action is reachable by a direct POST request, not only through your UI, even when nothing imports it. Each action has to verify the caller and the record on its own.

ts
// Before: any signed-in user can delete any invoice
export async function deleteInvoice(id: string) {
  const session = await auth();
  if (!session) throw new Error("Unauthorized");
  await db.invoice.delete({ where: { id } });
}

// After: only the owner can
export async function deleteInvoice(id: string) {
  const session = await auth();
  if (!session) throw new Error("Unauthorized");
  const { count } = await db.invoice.deleteMany({
    where: { id, ownerId: session.user.id },
  });
  if (count === 0) throw new Error("Not found");
}
The same action before and after the fix, in a file that starts with "use server".
text
For every route handler in app/api and every "use server" function, check
that it verifies the session and that the record belongs to the current user
(or their team). Fix the ones that only check the session. Show me the list
of handlers, what each one checked before, and what it checks now.
Prompt for Claude Code.

Keys: secrets stay on the server

Next.js inlines NEXT_PUBLIC_ variables into the JavaScript it sends to the browser, and Vite exposes VITE_ variables the same way. A secret key under either prefix is published with your site. Move the call that needs it into server code, rotate the key, and search the bundle again. The frontend API key guide lists which keys are public by design and which are not.

text
List every environment variable with a NEXT_PUBLIC_ or VITE_ prefix and
say whether each one is safe in a browser. Move every secret key to
server-only code (route handlers, server actions or Edge Functions) and give
me the list of keys I must rotate.
Prompt for Claude Code.

Webhooks and AI routes

Verify Stripe events with stripe.webhooks.constructEvent, the raw request body and your whsec_ secret. Stripe warns that a framework that parses the body first makes verification fail. Put a session check and a per-user rate limit on every route that calls a model. The Stripe webhook guide and the AI endpoint guide have the code.

Make the rules stick: CLAUDE.md, hooks and settings

A rule you type in chat lasts one session. Put it in the repository. Know the limit, though: Anthropic's memory docs say Claude treats CLAUDE.md as context, not enforced configuration, and point to a hook when an action must be blocked whatever Claude decides. Use both.

markdown
## Security rules

- Every new Supabase table enables row level security in the same
  migration, with policies based on (select auth.uid()).
  Never disable RLS to fix a bug.
- Never put a secret key in a NEXT_PUBLIC_ or VITE_ variable. Secret keys
  are read only in server code.
- Every route handler and server action checks the session and that the
  record belongs to the caller.
- Stripe webhooks verify the signature with constructEvent on the raw body.
- Routes that call an AI model require a session and have a rate limit.
- When a change touches auth, payments or database policies, say so in
  your summary so I review it.
A security section for your project's CLAUDE.md.
  • Keep it short. Anthropic suggests under 200 lines per CLAUDE.md. Rules in .claude/rules/ with a paths field load only when Claude works on matching files, for example a security.md scoped to your migrations folder.
  • Block what must never change. A PreToolUse hook runs before each edit. The hooks guide has a ready example that refuses edits to .env, package-lock.json and .git/ by exiting with code 2.
  • Feed the reviewer your threat model. With the security-guidance plugin installed, rules in .claude/claude-security-guidance.md are loaded by its end-of-turn and commit reviews.
  • Limit the database MCP. If Claude Code reaches Supabase through its MCP server, Supabase recommends one project, read-only mode, and production only when a task needs it: text stored in your tables can carry a prompt injection.

Test the live app, and retest after every deploy

Code review asks whether the code looks right. A live test asks what a stranger can do to the app that is online right now. Dashboard settings, deploy config and two-account bugs sit in the gap between the two.

That gap is what Keybrum works on. It attacks the deployed app the way a stranger would, signed out and then as two accounts, with more than 100 attacks: Supabase tables, RPC functions and storage, keys in the bundle, IDOR, unsigned Stripe webhooks, open AI routes, exposed .env files and Next.js CVEs such as the middleware bypass. Every finding comes with the request that worked. Connect Keybrum's MCP server to Claude Code (setup in the docs) and the agent reads each finding and its fix, applies it, and asks for a retest until the attack fails. Plans attack again on every deploy. Keybrum only attacks apps whose owner proved ownership.

Claude Code app security checklist

  • Claude Code is on a current version, and you read the .claude/ folder and .mcp.json of any repository you did not write before opening it.
  • .claude/settings.json denies reads of .env files, and the sandbox is on.
  • CLAUDE.md lists your security rules, and a hook blocks edits to files that must never change.
  • Every table in an exposed schema has RLS enabled, and each policy compares a column to auth.uid() unless the data is meant to be public.
  • No secret key sits in a NEXT_PUBLIC_ or VITE_ variable, and the built bundle contains no secret key prefix.
  • Every API route and Server Action checks the session and the owner of the record.
  • User B cannot open user A's records, tested with two real accounts.
  • Stripe webhooks verify the signature on the raw body, and AI routes need a session and have a rate limit.
  • /.env, /.git/config and source maps return nothing on the live site (why that matters), and the security headers checker passes.
  • /security-review runs before each merge, and the live app is attacked after each deploy.

The vibe coding security checklist goes further on each line, and vibe coding security risks explains why AI-built apps fail here.

Questions

Is Claude Code safe to use?

Claude Code limits what the agent can do on your machine with permission modes, a trust dialog for new folders and an optional sandbox. It has also had real flaws, more than 30 published advisories, all fixed in later versions. Stay current, be careful with repositories you did not write, and keep bypassPermissions for isolated containers or VMs, as Anthropic recommends.

What does the Claude Code /security-review command check?

It reviews the diff between your current branch and the default branch of your origin remote, looking for risks such as injection, auth issues and data exposure. It reads code only: it does not see your Supabase policies, your hosting settings or the deployed app. Run it before you merge, then test the live app.

How do I write secure code with Claude Code?

Put your security rules in CLAUDE.md, install the security-guidance plugin so Claude reviews its own changes, block sensitive files with hooks and deny rules, and run /security-review before each merge. Then test the deployed app, which none of those tools can see.

What is Claude Code Security?

Anthropic announced Claude Code Security on February 20, 2026, as a limited research preview for Enterprise and Team customers that scans codebases and suggests patches for human review. Today the managed scanner is Claude Security, in public beta on the Enterprise plan, and a Claude Security plugin runs a similar scan inside Claude Code. Both read source code, and neither applies a patch without your approval.

What are the most common vulnerabilities in apps built with Claude Code?

The same as in other AI-built apps: tables without row level security, secret keys in public environment variables, routes with no ownership check, unsigned Stripe webhooks and AI routes anyone can call. None of them shows in a demo, because the app works for its owner.

Does Claude Code have known CVEs?

Yes. CVE-2026-33068 let a repository's settings file skip the trust dialog (fixed in 2.1.53), and CVE-2026-21852 let a repository leak your Anthropic API key before you trusted it (fixed in 2.0.65). The repository lists more than 30 advisories in all, each with a fixed version, so stay current: run claude --version, and claude update if you update by hand.

Sources

  1. 1.Security, Claude Code Docs
  2. 2.Choose a permission mode, Claude Code Docs
  3. 3.Configure permissions, Claude Code Docs
  4. 4.Sandboxing, Claude Code Docs
  5. 5.Catch security issues as Claude writes code, Claude Code Docs
  6. 6.Scan your codebase for vulnerabilities, Claude Code Docs
  7. 7.Commands, Claude Code Docs
  8. 8.How Claude remembers your project, Claude Code Docs
  9. 9.Automate actions with hooks, Claude Code Docs
  10. 10.claude-code-security-review, Anthropic on GitHub
  11. 11.Security advisories for anthropics/claude-code, GitHub
  12. 12.CVE-2026-33068, NIST National Vulnerability Database
  13. 13.CVE-2026-21852, NIST National Vulnerability Database
  14. 14.Claude Code Security, Anthropic
  15. 15.Claude Security, Anthropic
  16. 16.How to think about data security in Next.js, Next.js Docs
  17. 17.Env variables and modes, Vite Docs
  18. 18.Row Level Security, Supabase Docs
  19. 19.Supabase Security Retro: 2025, Supabase
  20. 20.Supabase MCP Server, Supabase Docs
  21. 21.Receive Stripe events in your webhook endpoint, Stripe Docs
  22. 22.security-audit-skill, Cloudflare on GitHub
  23. 23.CVE-2025-48757, NIST National Vulnerability Database
  24. 24.Statement on CVE-2025-48757, Matt Palmer

Your app is public. So are its mistakes.

Check what any attacker can already see in it, free, in ten seconds. The full attack, with proof and fixes: €49 once, or €29 a month on a plan.

or continue with Google or GitHub