Security, Limitations and Engineering Responsibility
A coding agent runs commands and edits files as you. That is the source of its value and of its risk. This page maps what can go wrong — privacy, credentials, prompt injection, untrusted repositories, command execution, data exposure, dependencies and plain incorrect code — and what Anthropic's documentation says controls each one. It also tests a few defences for real, including a guard script that turned out to miss four evasions, because knowing where a control stops is part of using it.
.gitignore check and a pom.xml diff. Not executed: any live prompt-injection attack against Claude Code, the sandbox, or Anthropic's classifier. The "attacker" domain is the reserved placeholder attacker.example.What an Agent Can Reach, and What Can Reach It
Chapter 6 showed the architecture: the model asks, the harness checks permission, and the tool runs on your machine. Security follows the same picture in reverse: untrusted text flows into the model's context from many places, and the model's resulting requests flow out through tools that act with your authority.
Anthropic's security page states the division of responsibility plainly: Claude Code is built with a permission-based architecture and layered protections, and you are responsible for reviewing proposed code and commands for safety before approval. It also states that no system is completely immune to all attacks (Source 1). The rest of this page is a tour of the controls, ordered by how often a developer meets the risk.
Source Code Privacy
Claude Code runs locally, but to use the model it sends data over the network: all your prompts and the model's outputs, encrypted in transit with TLS 1.2 or later. In practice that includes any file contents or command output Claude reads into the conversation (Source 2). Encryption at rest depends on the provider: infrastructure-level AES-256 disk encryption for the Anthropic API, AWS-managed keys (optionally customer-managed) on Amazon Bedrock, Google-managed keys (CMEK available) on Google Cloud's Agent Platform, and, for Microsoft Foundry, it depends on the hosting option.
| What is stored | Where | Detail from the docs (Source 2) |
|---|---|---|
| Session transcripts | Your machine, ~/.claude/projects/ | Plaintext; kept 30 days by default; adjust with cleanupPeriodDays |
| Prompts and outputs | The model provider | Retention depends on account type (next section) |
| Cloud sessions | Anthropic-managed VMs | Repository cloned into an isolated VM; transcript stored; you can delete a session at any time |
| Metrics (no code, prompts or file paths) | Anthropic and third-party logging | Opt out with DISABLE_TELEMETRY=1 |
| Error reports (internals; known secrets and paths redacted) | A third-party error-tracking service | On only for some sign-ins; opt out with DISABLE_ERROR_REPORTING=1 |
/status), what your organisation's terms say, and whether zero data retention applies. Section 3 shows the differences the docs state.Enterprise Versus Personal Usage
| Consumer plans (Free, Pro, Max, Ultra) | Commercial (Team, Enterprise, API, third-party platforms) | |
|---|---|---|
| Training on your code/prompts | You choose whether data may be used to improve future models; when the setting is on, Anthropic says it trains on it, including Claude Code use | Anthropic says it does not train generative models on code or prompts sent to Claude Code under commercial terms, unless the customer chooses to provide data (for example through the Development Partner Program) |
| Retention | 5 years if you allow data use for model improvement; 30 days if you do not | 30 days standard; zero data retention available to qualified accounts on Claude for Enterprise, enabled per organisation |
| Governing terms | Consumer Terms | Commercial Terms of Service |
The figures are from Anthropic's data-usage page (Source 2). Three further points from it: transcripts shared through /feedback are retained for five years; the optional "can Anthropic look at your transcript" survey follow-up uploads the conversation, with known key patterns redacted but source code and file contents sent as-is, and shared transcripts are kept up to six months; and on Bedrock, Google Cloud, Microsoft Foundry and Claude Platform on AWS, telemetry, error reporting and /feedback are off by default.
/status shows which credential is active, and Chapter 12's managed settings can force the login method.API Keys and Credentials
There are two separate questions: how Claude Code stores its own credentials, and whether your secrets end up where the model — or a repository — can see them.
- Its own: macOS Keychain when available; on Linux a file with mode 0600 (
~/.claude/.credentials.json); on Windows a file inheriting the user-profile access controls (Source 1). Anything that runs as you can read that file, including a hook or an MCP server. - Yours: keep secrets out of the repository, out of prompts, and out of any file Claude is likely to read. In CI store keys as secrets (Chapter 11).
- The sandbox does not hide credentials by default: its filesystem reads are allowed across most of the machine, including
~/.sshand~/.aws/credentials, until you restrict them withfilesystem.denyRead(Source 4).
Finding: the project generated by Spring Initializr would have committed a local .env file. This is not a Claude Code problem — it is a reminder that an agent which creates or reads .env files in a repository without that rule is one git add -A from publishing a secret. Pair the ignore rule with a deny rule (Read(./.env)) so the agent does not read it in the first place.
What it shows: the pattern scan finds a planted example key — and also flags the project's own CI file, which is a reference to a secret (${{ secrets.… }}), not a secret. A scanner that cries wolf gets ignored, so tune patterns and review hits. (AKIAIOSFODNN7EXAMPLE is the placeholder key from AWS's documentation, not a credential.)
Prompt Injection
Anthropic's security page describes prompt injection as an attacker inserting text that overrides or manipulates an assistant's instructions (Source 1). For a coding agent the attacker does not need access to you: any text the agent reads can carry instructions — a dependency's README, a code comment, an issue or pull-request description, a web page, an MCP tool result. To the model, data and instructions are the same stream of text (Chapter 1), which is why this cannot be fixed by a clever prompt alone.
Here is a harmless reproduction of the shape. This is a real file I wrote for the demo; the "attacker" is the reserved attacker.example domain:
The comment is invisible in a rendered README but visible to an agent that reads the raw file. Anthropic lists several built-in mitigations: the permission system requires approval for sensitive operations in Manual mode; commands that fetch web content such as curl and wget are not auto-approved by default; and WebFetch runs a separate model call over a page so Claude receives that call's answer rather than the raw page (Source 1). Auto mode adds a classifier that blocks actions that escalate beyond your request, target unrecognised infrastructure, or appear driven by hostile content — and the docs say it reduces prompts but does not guarantee safety (Source 5).
A PreToolUse hook can add a deterministic check on top. This one blocks the command shapes the poisoned file asks for:
It catches the obvious shapes and lets normal work through. Now the part that matters. Here are variants a text blocklist does not catch:
The lesson, measured: all four evasions passed; only the unmodified control was caught. Matching command text is not a security boundary — the shell and any scripting language can express the same action in endless ways. Anthropic makes the same point about deny rules: a deny rule matches the command as written, and for network enforcement that does not depend on the command text you should use sandbox network isolation (Source 1). Use the hook as a seatbelt for honest mistakes and obvious shapes; rely on the sandbox's hostname-checking proxy and an isolated environment for the rest.
The MCP specification says the same about tools in general: there should always be a human in the loop with the ability to deny tool invocations (Source 6). MCP servers that fetch external content widen your injection surface, which is why Anthropic encourages writing your own or using ones from providers you trust (Source 1).
Untrusted Repositories
Opening a repository you did not write is not just reading it: its own settings files can define hooks, environment variables, helper commands and MCP servers. Anthropic's permissions page has a precise table of what runs before you trust a folder (Source 7):
| Repository supplies… | Trusted only a parent folder | claude -p / SDK, folder never trusted |
|---|---|---|
Hooks in settings files, the env block, helper commands like apiKeyHelper | Used | Used |
permissions.allow rules and additionalDirectories | Not used until you accept the trust dialog | Not used; a warning is printed |
Servers in .mcp.json | Claude Code asks before connecting | Connected without asking |
| Subagent/plugin frontmatter hooks, repository marketplaces | Not used | Not used |
Read the first and third rows twice. In a claude -p run — the CI and scripting mode — a repository's hooks and .mcp.json servers can run without any trust prompt. The page's own advice before running claude -p in a repository you did not write:
- Pass
--setting-sources userso neither the project's settings files nor its.mcp.jsonare read. - Start with
--bare: no hooks, skills, commands, subagents, plugins or.mcp.jsonservers from the project (but the project'senvblock and some settings-file helpers still apply). - Pass
--settings '{"disableAllHooks": true}'to turn hooks off for that run; setting it only in user settings is not enough because project settings take precedence. - Add a
disabledMcpjsonServersentry to reject an.mcp.jsonserver by name.
.claude/ and .mcp.json first, and work inside a container or VM with no host secrets mounted (Source 8).Terminal Command Permissions
| Setting | What it does | Residual risk |
|---|---|---|
| Manual mode | Edits and non-read-only commands prompt you; unmatched commands need approval ("fail-closed") | Prompt fatigue; approving without reading |
| Allow rules | Pre-approve specific commands | Too-broad patterns (Bash(*)) approve everything |
| Deny rules | Block in every mode, evaluated first | Match the command as written, so they can be evaded (Section 5) |
| Auto mode | A classifier reviews actions and blocks risky ones | Reduces prompts, "doesn't guarantee safety"; needs a supported model |
| Bypass permissions | Everything runs, including protected paths | No protection against prompt injection; isolated containers/VMs only |
| Sandbox | OS-enforced filesystem and network limits for shell commands | Off by default; does not cover built-in file tools, hooks or local MCP |
Sources: 1, 5, 4. Two protections are worth knowing by name: Claude Code asks before running a Bash command it cannot fully analyse (an allow rule for part of a command such as Bash(git *) does not skip that prompt), and it blocks a command that redirects git into the main checkout from a worktree session (Chapter 10). In non-interactive runs a call that needs approval is denied unless something approves it, so give -p jobs narrow --allowedTools lists.
Data Exposure
What leaves your machine is a function of what the agent reads and what you share. A short inventory, from the data-usage and security pages (Source 2, Source 1):
- Everything Claude reads becomes model input: source files,
@references, command output, logs. A secret in a log it tailed is a secret in the conversation. - WebFetch checks hostnames: before fetching, the tool sends the requested hostname (not the URL, path or page contents) to
api.anthropic.comto check a safety blocklist; this runs regardless of provider and is not affected byCLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC. /feedback,/bug,/sharesend a copy of the conversation including code; you choose how much history to include.- Local transcripts persist for 30 days by default in plaintext.
- Cloud and Remote Control sessions: a cloud session stores its transcript on Anthropic's servers; Remote Control keeps execution local but stores the transcript on Anthropic servers while connected, to sync across devices.
--bare and --settings for unattended runs so they load only what you intend. Disable what you do not need (DISABLE_FEEDBACK_COMMAND=1 if your policy forbids sending transcripts).Dependency Vulnerabilities
An agent that adds a library to make a feature work is making a supply-chain decision for you. It may pick an outdated version, an abandoned project, or — worse — a package whose name it recalled slightly wrong. The defence is to make dependency changes visible and review them like code. On bookshelf, the JPA change added exactly these:
Review it: three are Spring Boot starters from the parent's managed set; h2 is a real database library from com.h2database, correctly scoped runtime (and an in-memory database is fine for a learning project, not for production). Questions to ask of any such diff: does every new group and artifact exist and match what you expect (check the spelling against the repository)? Is it managed by the parent BOM or pinned by hand? Is the scope right? Is it needed?
- Constrain it up front: in CLAUDE.md or the prompt, "no new dependencies without asking".
- Gate it mechanically: a CI check that fails when
pom.xmlchanges without a label or review; Chapter 11's change-budget idea applies. - Scan it: use a vulnerability scanner in your build. Limit of this page: I tried to run Maven's dependency plugins for a full tree and a scan, but the plugin artifacts could not be downloaded in this environment, so no scan output is shown rather than an invented one.
Incorrect Code, and Why You Stay Accountable
The most common failure is not an attack but an ordinary mistake, delivered fluently (Chapter 1). Every problem found while building this guide is a specimen, and each was caught by something other than the model's confidence:
| Failure (all real, this guide) | Looked like | Caught by |
|---|---|---|
Generated pom named a version that does not exist (4.1.2.RELEASE) | Valid generated project | The build |
year is reserved in H2 | Ordinary field name | The test run (SQL syntax error) |
| N+1: 4 SQL statements instead of 1 | Working endpoint | A purpose-built test |
| Missing exception mapping → HTTP 500 | Correct lookup code | Running the app and reading the trace |
| Decision-table refactor wrong for 1,710 inputs | Clean, readable rewrite | A comparison against the original |
| Guard hook missed all 4 evasions tested | A working security control | Testing it with variants |
| Secret scan flagged a reference to a secret | A real leak | A human reading the hit |
Generated .gitignore lacked .env | Standard template | git check-ignore |
The pattern is consistent: the defence was an independent check — a build, a test, an oracle, a person. That is why Anthropic's own pages keep returning to verification (Source 9) and why they place responsibility for reviewing proposed code and commands on you (Source 1). Models also have limits unrelated to attacks: a knowledge cutoff (June 2026 for the current tiers, Chapter 5), context that degrades as it fills (Chapter 1), instructions lost in compaction, checkpoints that cover file edits but not databases or deployments, and non-deterministic output.
| Question | How |
|---|---|
| What changed, and is it the size I expected? | git diff --stat; a change budget |
| Can a test fail without this change? | Break the code on purpose and run it |
| Any new dependency, permission, config or network call? | Diff pom.xml, .claude/, .github/, scripts |
| Did it read or write anything sensitive? | Check the transcript's tool calls |
| Is the claim backed by evidence I can reproduce? | Re-run the command myself |
| Would I be comfortable defending this in review or an incident? | If not, do not merge it |
Security Habits That Fail
/status.claude -p on a repo you did not write. Hooks and .mcp.json servers can run without a trust prompt. Use --bare or --setting-sources user..env not ignored, credentials readable by the sandbox, keys pasted into prompts.Key Takeaways, Exercises and Sources
- An agent acts as you. Everything it reads can steer it; everything it can do, you can do.
- Know your terms: consumer and commercial accounts differ in training, retention and defaults.
- Keep secrets out of reach — ignore rules, deny rules, no keys in prompts or repos.
- Prompt injection is structural. Mitigate in layers; no single layer, text hooks least of all, is a boundary.
- Untrusted repos can execute things — especially under
claude -p. Isolate and restrict. - Review dependency changes like code.
- Verify independently, and stay accountable. Every real failure in this guide was caught by a check that did not trust the model.
Exercise 1 Beginner
In one of your projects, check whether .env is git-ignored (git check-ignore -v .env) and run a secret-pattern grep over the tree. For each hit, decide: real secret, test fixture, or a reference like ${{ secrets.X }}.
Learning outcome: separate real exposure from noise.
Exercise 2 Intermediate
Reproduce the guard-hook test. Add a rule for nc, rebuild the test list, and then invent three new evasions that still pass. Write down what category of control would stop each (sandbox network, container, review).
Learning outcome: see why text matching is a seatbelt, not a wall.
Exercise 3 Advanced
Write a one-page policy for using a coding agent on a repository that contains customer data: which account type, which provider, what is denied, whether the sandbox is mandatory, how claude -p in CI is constrained, how dependency changes are reviewed, and who signs off. Name how you would test each control.
Learning outcome: turn this page's risks into enforceable, testable rules.
- Anthropic, Security — permission architecture, built-in protections, prompt-injection safeguards, credential storage, untrusted-content advice, MCP and cloud security, user responsibility.
- Anthropic, Data usage — training policy, retention, local data flow, telemetry, feedback, provider defaults, WebFetch hostname check.
- Anthropic, Commercial Terms and Consumer Terms — named by the pages above as authoritative; the terms themselves were not read for this page.
- Anthropic, Sandboxing — filesystem and network isolation, platforms, defaults, what it does not cover.
- Anthropic, Permission modes — Auto mode classifier behaviour, Bypass cautions.
- Model Context Protocol, specification 2025-11-25, Tools page (repository) — human-in-the-loop guidance.
- Anthropic, Permissions — "What runs before you trust a folder", workspace trust, rule evaluation.
- Anthropic, Development containers — warnings about exfiltration with bypass mode and mounted secrets.
- Anthropic, Best practices — verification, deterministic versus non-deterministic instructions.
Executed on this machine, 2026-10-30: the guard-hook runs (12 command inputs across two runs), pattern scans, .gitignore check, and git diff of pom.xml. Not executed: any attack against a live Claude Code session, the sandbox, Auto mode, or a vulnerability scanner. The OWASP LLM Top 10 page could not be retrieved from this environment, so it is not cited. This page is not a security audit, legal advice or a compliance statement.