CLAUDE CODE AGENT SECURITY PATTERNS
The workflow problem: an agent with your shell
Claude Code runs in your terminal with your user account’s privileges. It inherits your shell environment, your PATH, your ~/.aws and ~/.ssh, and every service your session can reach. The binary itself is not the risk — Anthropic’s platform security is covered in Is Claude Code Safe? — the risk is that four different configuration surfaces (permissions, hooks, CLAUDE.md, MCP servers) all shape what the agent does, and on a team, several of those surfaces are writable by anyone who can open a pull request.
This page is about the day-to-day workflow: how a team scopes permissions, reviews agent configuration as code, keeps secrets out of sessions, and audits what a session actually did. For step-by-step hardening of a single install, see How to Secure Claude Code; for the pre-merge checks, the Claude Code Security Checklist.
Permission modes are team policy, not personal preference
Claude Code’s default mode prompts for approval on every shell command and file write. That per-call gate is the strongest control in the whole system, and it erodes in a predictable way: each developer quietly grows a personal allowlist until the agent runs almost everything unprompted. Individually rational, collectively invisible — nobody knows what the team’s real approval posture is.
Treat the allowlist as policy. Project-level permissions live in .claude/settings.json, which is checked into the repo and applies to everyone; personal additions go in settings.local.json, which is gitignored. That split gives you a reviewable artifact: the shared allowlist changes only via pull request, and the deny list hard-blocks dangerous shapes regardless of what any individual allows locally.
// .claude/settings.json — shared, reviewed in PRs
{
"permissions": {
"allow": ["Read", "Grep", "Bash(git diff:*)", "Bash(npm test:*)"],
"deny": ["Bash(curl:*)", "Bash(git push:*)", "Bash(rm -rf:*)"]
}
}
The --dangerously-skip-permissions flag deserves a written team rule, not an informal norm: it removes the only synchronous human gate between the model and your filesystem, so it is acceptable only inside a disposable container (see the sandboxing section below), never on a workstation with real credentials.
Hooks are code execution, review them like CI config
Hooks in settings.json run arbitrary shell commands on agent events — before a tool call, after an edit, when a session stops. They execute automatically on every teammate’s machine that pulls the repo and runs a session. A pull request that adds a hook is therefore a code-execution change with the blast radius of a CI pipeline edit, wearing the costume of a config tweak.
The failure shape: a PR titled “chore: add lint-on-edit hook” adds a PostToolUse hook whose command fetches and pipes a remote script. Reviewers skim JSON config faster than they skim code, and the hook runs silently from the next session onward. Put .claude/ behind a CODEOWNERS entry, review hook commands with the same scrutiny as .github/workflows/, and be suspicious of any hook that touches the network at all — see Poisoned CI and DevOps Leaks for how this class of pipeline compromise plays out.
CLAUDE.md is injectable configuration
CLAUDE.md is read into the model’s context every session. That makes it two things at once: a place where developers paste secrets they shouldn’t (keys land in git history and in every transcript thereafter), and an instruction channel writable by anyone with commit access. A malicious or careless edit to CLAUDE.md steers every teammate’s agent — “always use package X,” “skip the auth middleware on internal routes” — without ever touching application code.
The same injection logic applies to anything else the agent reads: a README in a vendored dependency, a comment block in a fixture file, an issue body pasted into the prompt. The agent does not distinguish your instructions from instructions embedded in content. The general pattern is covered in Indirect Prompt Injection; the workflow defense is narrow and boring — treat CLAUDE.md as a public document with placeholder values only, review its diffs in every PR that touches it, and run git log -p -- CLAUDE.md when auditing a repo you inherited.
MCP servers: one vetted list, scoped tokens
An MCP server runs as the user that launched Claude Code — full filesystem, full network, full shell. On a team, the practical control is a single vetted server list rather than per-developer improvisation: a short, written allowlist of approved servers, a named owner for additions, and scoped credentials in the config (a read-only GitHub token, not the broadest PAT someone had lying around).
The attack that matters is not “obviously evil server.” It is a legitimate-looking server whose tool descriptions carry instructions the model obeys — summarize the workspace, include the contents of .env, POST the result. That mechanism is dissected in MCP and Tool-Spec Injection, and the Claude Code-specific configuration detail is in Is Claude Code Safe?. The workflow rule: audit the MCP manifest whenever it changes, and treat a new server the way you treat a new production dependency.
Secrets in the workspace are secrets in the session
The agent reads what your account can read. When a session debugs a failing API call, the natural next step for the model is to cat .env — and now the key is in the transcript, in the context window, and available to be echoed into generated code or reached by any MCP tool in the session. Nothing malicious happened; the workflow just made the secret reachable.
Practical containment for a team:
- Keep production credentials off development machines entirely; use per-environment tokens so a dev-shell leak cannot touch prod.
- Scope environment variables per project (direnv or equivalent) so an agent session in repo A cannot see repo B’s tokens.
- Use placeholder values in fixtures and example configs — agents propagate nearby example credentials into new code.
- Scan your deployed app for keys that already escaped with the Token Leak Checker.
Review the session, not just the diff
A Claude Code session produces two artifacts: the transcript and the git diff. Most teams review neither with intent. The diff is the one that ships, so anchor the review there — the whole branch, not the file you were focused on, because the agent edits adjacent files it decides are related.
The known drift pattern to watch for: asked to fix a failing test, the agent relaxes the assertion instead of the code, or disables the security check that made the test fail. So review with a short mechanical pass before the human pass: grep the diff for new eval(, exec(, dangerouslySetInnerHTML, string-concatenated SQL, and for deletions of requireAuth, csrf, verifyJwt; diff the dependency manifests; check .claude/ and CLAUDE.md for new entries; run the security tests separately from the full suite. The full team-level review process is in the Agentic Code Review Guide.
Sandboxing options, cheapest to strongest
Match isolation to the task’s blast radius rather than applying one rule everywhere:
- Feature branch plus branch protection — the free tier. The agent can commit anything; it cannot reach
mainwithout a human PR review. - Devcontainer or Docker — the agent gets a real shell in an environment with no host credentials and read-only mounts on anything you care about. This is the only context where auto-approving all permissions is defensible.
- Dedicated user account or VM — for sessions that must touch semi-sensitive systems, a separate account boundary limits what a bad command can reach.
- Egress restrictions — for the paranoid tier, block outbound network from the sandbox except the model API and your package registry, which turns most exfiltration paths into connection errors.
The rule of thumb: the less you intend to read each command before approving, the stronger the sandbox has to be.
Related resources
- Is Claude Code Safe? Security Analysis — platform-level trust model
- How to Secure Claude Code — step-by-step hardening
- Claude Code Security Checklist — pre-session and pre-merge checks
- Claude Code Security Overview
- Agentic Code Review Guide — reviewing agent output at team scale
- Agentic Coding Risks — the cross-tool risk taxonomy
- Cursor Composer Security and Devin Security Practices — the same workflow lens for other agents
- MCP and Tool-Spec Injection / Indirect Prompt Injection
Scan the code your agent ships
Workflow discipline catches what happens on the machine. What reaches production still needs its own gate — run the Vibe Code Scanner against the deployed app to catch the auth gaps, leaked keys, and CORS misconfigurations that survive review.
SCAN YOUR DEPLOYED APP
Paste your live URL. We probe exposed keys, missing auth, open databases, and broken access control — results in under 60 seconds. 14-day trial, no card.
14-day free trial · No credit card · Cancel anytime