Is my Claude Code app secure? A practical checklist
Last updated · 3 min read
Claude Code writes real server and client code, so its apps fail in the same places as any hand-written app: secrets in the wrong place, routes without auth checks and open database rules. Put your security rules in CLAUDE.md, deny it access to .env files, review every route that reads private data, and scan the deployed site after each change.
Why Claude Code apps need their own checklist
Claude Code works in your repository and terminal: it reads files, runs commands and edits code across the whole project. That makes it fast at building complete features, and it also means a single instruction can touch authentication, database queries and deployment config at once. It follows your instructions and the patterns already in the code, so the most effective security work is telling it the rules up front and checking the result where it matters: the running app.
The problems we see most in agent-built apps are not exotic. A key is read from a public environment variable because that made an error go away. A new API route returns data without checking the session because the page that calls it is already behind a login. A database table is created without row level security because the first query worked without it.
Write the rules down in CLAUDE.md
Claude Code reads CLAUDE.md at the start of every session, so rules written there apply to every change without repeating them. Keep them short and checkable; a long essay is easier to ignore than five concrete rules.
## Security rules
- Secrets live only in server-side environment variables. Never use a NEXT_PUBLIC_ / VITE_ prefix for a key.
- Every API route and server action that reads or changes private data checks the session first and returns 401 without one.
- Every database query is scoped to the signed-in user or their organisation.
- Every new Supabase table has row level security enabled with a policy before it is used.
- Payment webhooks verify the provider's signature; prices come from the server, never from the request.
- Never print, log or paste secret values, including in commit messages and chat.Keep secrets out of reach
Claude Code respects permission rules in .claude/settings.json. Denying reads of your .env files means secret values never enter the conversation, so they cannot be pasted into code, logs or a commit by accident. The app still reads them at runtime as normal.
Add a secret scanner such as gitleaks to your pre-commit hook or CI so a key that slips into code stops the commit, whoever wrote it.
{
"permissions": {
"deny": ["Read(./.env)", "Read(./.env.*)", "Read(./secrets/**)"]
}
}Review the changes that matter
- Ask for a plan before large changes (plan mode) and read which files it intends to touch. Changes to auth, middleware, database schema or payment code deserve a closer look than UI work.
- After a feature lands, list the new or changed API routes and server actions, and check each one starts with a session check and scopes its query to the user.
- Run the built-in /security-review command on the branch before merging. It reviews the pending changes for common security problems, which catches many issues early but does not replace testing the live app.
- Check the database: every table with private data has row level security on (Supabase) or rules that require auth (Firebase).
- Run the test suite yourself. An agent that reports "all tests pass" is usually right, but a quick look at the output costs a few seconds.
Check what actually shipped
Code review sees intentions; the live site shows results. A deploy can still serve a .env file, send a key to the browser, miss a security header or answer an API request from anyone. A read-only scan of the deployed URL catches those from the outside, the same way an attacker would look.
Make the check part of the loop: deploy, scan, paste the fix prompt for anything found back into Claude Code, deploy again, and recheck. A finding should only count as fixed when the live check passes.
Questions
- Does Claude Code write insecure code?
- Not by intent, but it optimises for the task you give it. If the task does not mention authorisation or secrets, it may solve the visible problem and leave those gaps. Rules in CLAUDE.md and a scan after deploy close most of them.
- Is it safe to let Claude Code read my .env file?
- It is safer not to. A deny rule for .env files keeps secret values out of the conversation entirely, and the app does not need Claude Code to see them.
- Is /security-review enough?
- It is a good first pass on code changes. It cannot see your hosting config, database rules or what the deployed site really serves, so check the live app too.
Related Defexity checks
- SEC-016: Secret key exposed in public HTML or JavaScript
- SEC-019: API route returns data without authentication
- SEC-012: Environment file publicly accessible
- SEC-005: Content-Security-Policy missing or permissive
- CODE-008: Server secret exposed through a public env prefix (code check, with GitHub)
- CODE-013: Stripe webhook without signature verification (code check, with GitHub)
Sources
Defexity reports potential risks it can see from outside your app. It is not a guarantee of security and not legal advice.