← All posts

Explainer

What your security team will ask before a coding agent touches the repo

What your security team will ask before a coding agent touches the repo

Somewhere between the pilot and the rollout there is a forty-minute conversation with someone whose job is to say no. It is the meeting that decides whether your team adopts a coding agent at all, and it is usually lost in one of two ways.

The first is the vendor answer — SOC 2, encryption in transit, a trust page. None of it is untrue and none of it addresses the question, which is not "is the company careful" but "what can this process do on a developer's laptop." The second is the engineer answer: it's fine, I watch it. That one loses faster, because everyone in the room knows what watching a terminal for six hours actually looks like.

The questions below are the ones that get asked. Each has an honest answer available from current documentation. Some of those answers are reassuring. Three of them are versions of nothing stops that — here is what you do instead, and saying so is what makes the rest credible.

Verified against: Claude Code 2.1.224 (npm latest; the stable tag was 2.1.220), @openai/codex 0.147.0, and MCP specification revision 2026-07-28, all checked on 2026-08-07 against code.claude.com/docs, learn.chatgpt.com and modelcontextprotocol.io. Every mechanism named below exists in those docs today; where a control people assume exists does not, the post says so rather than filling the gap. Nothing here describes an unpublished vulnerability.

First, the thing the whole review turns on

Almost every specific answer below is an instance of one structural fact, so it is worth stating once. A coding agent has four places a control can sit, and they are not interchangeable — they differ in what can argue with them.

WEAKEST — persuadable by text The model and its system prompt refuses, notices, declines — probabilistically. This is not a control. Permission rules, hooks, deny lists deterministic, evaluated before the call — but only over the command string it parses OS sandbox — Seatbelt, bubblewrap, seccomp kernel-enforced on Bash and its children — not on MCP servers, not on hooks Container or VM, with an egress proxy everything on the host — and still sends every file the agent reads to the model STRONGEST — enforced regardless of what the model decided Nothing below the top row can be talked out of its decision. Nothing at any row stops the upload to the model.
A security review is really an argument about which of these four rows you are relying on. Most teams answer as though they are on row three and are actually on row one.

Anthropic states the boundary between the first two rows about as directly as documentation ever puts anything: "Permission rules are enforced by Claude Code, not by the model. Instructions in your prompt or CLAUDE.md shape what Claude tries to do, but they don't change what Claude Code allows." Keep that sentence in view for the next seven sections.

1. Where does our source code go, and to whom?

It goes to the model provider. All of it that the agent reads, plus your prompts, plus tool output. There is no configuration that changes this, and it is worth refusing the softer phrasings up front — Anthropic's own sandbox comparison page says it in the middle of a warning about isolation: "Isolation also does not change what is sent to the model. Your prompts and the files Claude reads are transmitted to the Anthropic API or your configured provider with or without a sandbox."

So "our code doesn't leave the building" is false for every tool in this category, including the ones with the best security stories. The answerable questions are narrower and better:

Now the part that turns this from a policy question into a configuration question. All of the above is a property of the account the engineer signed into, not of the repository they opened. A personal Pro login and a corporate Enterprise seat produce identical-looking sessions in the same checkout with materially different data postures. The ZDR page is explicit about the failure mode: "If a developer signs in to Claude Code with a personal account or with an API key from a different organization, those sessions are not covered." The fix is forceLoginMethod and forceLoginOrgUUID delivered through managed settings, and if your review produces one action item, that is a good candidate for it.

On routing through your own cloud: Bedrock, Google Cloud's Agent Platform and Microsoft Foundry change where inference happens and turn telemetry, error reporting and /feedback off by default. They do not make the client silent. The WebFetch domain safety check sends the requested hostname to api.anthropic.com before every fetch, and the docs are specific that this "runs regardless of which model provider you use and is not affected by CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC." One hostname, no path, no content, and you can disable it with skipWebFetchPreflight at the cost of the blocklist. Small. But if you tell your security team "on Bedrock nothing reaches Anthropic," you have told them something the documentation does not say, and that is the kind of thing that gets found later.

2. What can the agent execute, and what stops rm -rf?

Out of the box, less than people fear. Claude Code starts read-only, ships a fixed list of read-only commands like ls, cat and git status that run without a prompt, and asks before anything that can modify the system. Writes are confined to the directory it was started in and below.

The honest answer to rm -rf specifically has three parts.

The model is not what stops it. Two things are. A deny rule, evaluated before the call, first-match-wins in the order deny → ask → allow, and unoverridable: "If a tool is denied at any level, no other level can allow it." A bare tool name in deny goes further and removes the tool from the model's context entirely, so it never appears as an option. And an OS sandbox, where a forbidden write fails at the kernel rather than at a policy check.

The sandbox is off by default and it fails open. sandbox.enabled defaults to false. When it is on, macOS uses Seatbelt and Linux and WSL2 use bubblewrap; native Windows is not supported. Its default read boundary is wider than most reviewers expect — "read access to the entire computer, except certain denied directories. Note that this default still allows reading credential files such as ~/.aws/credentials and ~/.ssh/." And if it cannot start, Claude Code "shows a warning and runs commands without sandboxing" unless you set sandbox.failIfUnavailable. For a managed deployment, that setting is not optional; a security control that silently degrades to nothing is worse than no control, because you stop watching.

In the permissive modes, the floor is very low. Running with --dangerously-skip-permissions, the docs say you are "only prompted for explicit ask rules, connector tools your organization set to ask, MCP tools marked requiresUserInteraction, and removals targeting / or your home directory." So there is a floor and it is your home directory. Inside the working tree, nothing stops a destructive command in that mode except the fact that the working tree is a git repository — which is the real answer, and the reason the working-directory boundary matters more than any pattern-matching rule. Committed work survives. Six hours of uncommitted work does not.

The curl | bash in the README

Reading a README does nothing; it is text arriving in a context window. The risk is the agent proposing the command afterwards, and the defaults here are decent: network-fetching commands are not auto-approved, unmatched commands fail closed to a manual prompt, and suspicious command patterns require approval even when previously allowlisted.

Where this goes wrong is not the attacker's move, it is yours. Someone gets tired of approving curl and adds an allow rule. Anthropic prints a warning about exactly this, and it is worth reading slowly because it explains why argument-scoped Bash rules are a trap: "Bash permission patterns that try to constrain command arguments are fragile. For example, Bash(curl http://github.com/ *) intends to restrict curl to GitHub URLs, but won't match variations like" — options before the URL, a different protocol, a redirect, or URL=http://github.com && curl $URL. There is a companion caveat on the file side: Read and Edit deny rules cover the built-in tools and recognised shell commands, but "don't apply to arbitrary subprocesses that read or write files indirectly, like a Python or Node script that opens files itself."

The generalisation is uncomfortable and correct: a permission rule that tries to be clever about arguments is a suggestion; a rule that denies a whole tool, and a boundary the kernel enforces, are controls. If your review wants argument-level guarantees, the answer is the sandbox's domain allowlist, not a regex. Our guide to pre-approval policies covers the hook-based version of the same decision.

Codex CLI answers this question in a different shape, and it is worth knowing which shape your reviewer wants. Where Claude Code gates the decision and makes the OS boundary opt-in, Codex constrains the capability first: a sandbox mode is always in force, with read-only, workspace-write and danger-full-access as the dial, and network off by default in the first two. See Codex CLI sandbox modes. If your security team's instinct is "I don't want to rely on a config file being right," that is the family of answers they are reaching for.

3. How do credentials reach it — and what happens when it shells out?

The agent's own credential is the easy half. It is an OAuth token or an API key, stored in the macOS Keychain where available and behind file permissions elsewhere.

The hard half is every other secret on the machine. GH_TOKEN, NPM_TOKEN, AWS_SECRET_ACCESS_KEY, a database URL in a .env your test runner sources. Those reach the agent the same way they reach every other program you launch from that terminal: inheritance. The sandboxing docs state it plainly — "sandboxed Bash commands inherit the parent process environment by default, including any credentials set there" — and note that settings.json's env block applies "to every session and to subprocesses Claude Code spawns from it."

And it does not stop at the child. An environment block is copied at every fork. The agent runs npm test; npm runs your test script; your test script spawns a worker; somewhere in there a dependency's postinstall executes. Every one of those processes holds the same token, and none of them was named in any permission rule, because the permission system saw one command: npm test.

your shell GH_TOKEN=ghp_… claude the agent Bash tool npm test test script workers, tooling post- install a dep one environment block, copied at every fork — the permission system saw a single command CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1 → cuts arrow 2, for Anthropic and cloud provider variables only sandbox.credentials envVars deny → cuts arrow 2 for variables you name, one at a time sandbox.credentials envVars mask → a sentinel travels the chain; the proxy swaps in the real value on the way out
This is not an agent bug — it is how processes have always worked. What is new is how often, and how unsupervised, that first command runs.

Claude Code has three controls here, and they are worth knowing individually because they are not equivalent.

ControlWhat it actually does
CLAUDE_CODE_SUBPROCESS_ENV_SCRUB One switch, no enumeration. Strips Anthropic and cloud provider credentials from subprocess environments — Bash, hooks and MCP stdio servers. "The parent Claude process keeps these credentials for API calls, but child processes cannot read them." On Linux it also runs Bash subprocesses in an isolated PID namespace so they cannot read other processes' environments via /proc. It does not touch GH_TOKEN.
sandbox.credentialsdeny Named variables are unset before each sandboxed command; named file paths become unreadable inside the sandbox. Precise, and it breaks the tools that needed the credential. "There is no built-in credential deny list, so only the files and variables you list are restricted." Sandboxed Bash only.
sandbox.credentialsmask The interesting one, and under-known. The subprocess sees a per-session sentinel; the sandbox proxy substitutes the real value on outbound requests to the hosts you list in injectHosts. "The command and anything it logs never hold the real credential, but its requests still authenticate." Requires network.tlsTerminate, since the proxy has to see the request to rewrite it. 2.1.199+.

Only the third of those survives the failure mode that actually bites, which is a credential ending up in a log, a transcript or an error message rather than being stolen outright. And note what none of them do: they are all scoped to what Claude Code spawns. Nothing here reaches a process your Makefile starts in the background.

Which is why the durable answer to this question is not a settings key. It is: do not export long-lived credentials into the shell you launch an agent from. Short-lived, narrowly scoped tokens minted per task, and a secret manager the agent has to ask for rather than a variable it inherits. That is ordinary hygiene which most teams have already half-implemented; the agent just makes the cost of not finishing it much more visible.

4. What about prompt injection through content the agent reads?

Your agent reads an issue body, a dependency's README, a CI log, a web page. All of it arrives as text in the same context window as your instructions, and from the model's position there is no typographic difference between a bug reporter describing a crash and a bug reporter writing a paragraph addressed to the agent. This is not a bug that gets patched. It is what "reading" means for a language model.

Vendors do publish defences, and Anthropic's list is worth quoting because of its ordering. Under "Protect against prompt injection", the core protections are: "Permission system: Sensitive operations require explicit approval", "Context-aware analysis: Detects potentially harmful instructions by analyzing the full request", "Input sanitization", and "Network command approval" — with a separate note that web fetch "uses a separate context window to avoid injecting potentially malicious prompts." The page ends with a warning Anthropic did not have to print: "While these protections significantly reduce risk, no system is completely immune to all attacks."

Read that list again and notice that the first item is the only one that is not a model-side heuristic. Context-aware analysis and input sanitization are probabilistic defences applied by, or on behalf of, the very component the attack targets. The permission system is different in kind: it does not read the text, it does not evaluate the argument, and there is nothing an attacker can write that addresses it. It is not a smarter reader. It is not a reader.

So the useful form of this question in a review is not how good is the injection classifier. It is: on the day the classifier is wrong, what was on the allow list? If the answer includes a broad Bash allow, or bypassPermissions outside a container, the classifier was carrying the whole load and you now know how much load that was. If the answer is "reads and edits inside the repo, and everything that publishes or spends comes to a human", the blast radius of a successful injection is a bad commit on a branch.

One nuance specific to the egress side. If you have the sandbox on with a network allowlist, that is a real containment boundary — but read its documented limits before you present it as one. "Allowing broad domains such as github.com can create paths for data exfiltration", and because the built-in proxy makes its decision from the client-supplied hostname without terminating TLS, "code running inside the sandbox can potentially use domain fronting or similar techniques to reach hosts outside the allowlist." An allowlist containing your source host is an allowlist containing a write channel.

The version of this that composes with third-party instructions — a skill or an agent file that tells the agent to trust its inputs — we traced end to end in the security model of agent skills.

5. What is written down, and who can read it?

Two answers, because there are two logs with different audiences, and only one of them exists by default.

On the laptop, always. Claude Code writes a full transcript per session to ~/.claude/projects/<project>/<session>.jsonl"every message, tool call, and tool result" — plus subagent transcripts, spilled large tool outputs, pre-edit file snapshots under file-history/, and history.jsonl, which is "every prompt you've typed, with timestamp and project path." Default lifetime 30 days, adjustable with cleanupPeriodDays.

The documentation does not soften what that means, and neither should your review:

Transcripts and history are not encrypted at rest. OS file
permissions are the only protection. If a tool reads a .env
file or a command prints a credential, that value is written
to projects/<project>/<session>.jsonl

So the honest answer to "who can read it" is: anyone who can read that user's home directory. Full disk encryption is the control, and it belongs to your endpoint team, not to the agent. If your threat model cannot accept a plaintext copy of everything the agent touched sitting on a laptop for a month, lower cleanupPeriodDays, or set CLAUDE_CODE_SKIP_PROMPT_HISTORY to stop transcript writes entirely — and accept that you have also given up session resume, which developers will notice within a day.

Off the machine, only if you build it. Claude Code emits OpenTelemetry metrics and events to a collector you configure, enabled with CLAUDE_CODE_ENABLE_TELEMETRY=1 — a separate thing from the Anthropic-bound product telemetry that DISABLE_TELEMETRY turns off. Fifteen event types, of which one matters more than the rest for a security team: claude_code.tool_decision, carrying the tool name, a tool_use_id that matches the hooks and trace spans, the decision, and a source that distinguishes config, hook, user_permanent, user_temporary, user_reject and user_abort. That field is the difference between "a human approved this" and "a rule someone wrote in March approved this."

Content is off by default and gated per category: prompts are redacted unless OTEL_LOG_USER_PROMPTS=1, tool parameters and commands need OTEL_LOG_TOOL_DETAILS=1, and there is a trap in the middle — "When OTEL_LOG_ASSISTANT_RESPONSES is unset, OTEL_LOG_USER_PROMPTS controls it instead." Turn on prompt logging expecting prompts and you get responses too. Administrators can pin the destination through managed settings, and when they do, Claude Code "removes conflicting developer-set variables at startup to prevent signal routing around the managed collector."

The summary a reviewer should walk away with: the default configuration produces a detailed private record on each developer's disk and no central record anywhere. That is exactly backwards from what most compliance regimes want, and it is a day of work to fix.

6. If something goes wrong, can we tell afterwards what it did?

Partly, and less than the transcript's richness suggests. Be precise about what each artifact is worth, because this is where a confident wrong answer does real damage six months later.

What does not exist, and you should not promise: a vendor-side, per-tool-call audit trail for Claude Code. Claude Enterprise has a Compliance API and an audit log covering organization events with a 180-day window, and a separate analytics API for aggregated usage and cost. Neither is a record of which commands an agent ran in which repository. That record is the local transcript plus your own collector, and nothing else.

One trap worth naming out loud. A session run in bypassPermissions or a fully automatic mode produces a transcript that looks the same whether the run was routine or hostile, because nothing was ever refused and no decision was ever recorded. The forensic value of an approval log is that it contains denials. A log of a session where nothing could be denied is a narrative, and narratives are what you get instead of evidence.

So decide the incident question before the pilot. If the required answer is "we can produce a per-tool-call record with the human decision attached", that is a collector plus managed settings plus ConfigChange hooks to catch someone loosening the policy mid-session. All of it is documented and none of it is default.

7. What about extensions, skills and MCP servers?

This is the question your security team is most right to press on, and the one where the honest answer is weakest.

Start with the mechanics. A stdio MCP server configured in a project file is a process launched on the developer's machine, with the developer's environment, when the session starts. Adding one to .mcp.json is not adding a config entry; it is agreeing to run a binary. And it runs outside every boundary discussed so far — the sandbox comparison page states that with the built-in Bash sandbox, "MCP servers and hooks are separate processes that run unconstrained on the host." Hooks carry the same weight; Anthropic's own disclaimer reads: "Command hooks execute shell commands with your full user permissions. They can modify, delete, or access any files your user account can access."

Next, what the protocol guarantees — and here it pays to read the specification more carefully than the summaries do. Its security principles sound absolute: "Tools represent arbitrary code execution and must be treated with appropriate caution" and "Hosts must obtain explicit user consent before invoking any tool." But those sentences are in lower case, and the specification opens by stating that RFC 2119 keywords apply "when, and only when, they appear in all capitals." Immediately after the principles comes the line that settles it: "While MCP itself cannot enforce these security principles at the protocol level, implementors SHOULD…" build consent flows, implement access controls, follow best practices. If someone brings you "the MCP spec requires consent before every tool call", it does not. Consent is a promise each host keeps or does not.

There are genuinely normative requirements, and they are the ones worth citing. On the tools page: "clients MUST consider tool annotations to be untrusted unless they come from trusted servers", and "there SHOULD always be a human in the loop with the ability to deny tool invocations." On authorization, the sentence that answers the local case outright — "Implementations using an STDIO transport SHOULD NOT follow this specification, and instead retrieve credentials from the environment." A local MCP server is exempt from MCP's authorization model by design, and told to read its secrets from the same inherited environment we walked through in question three.

The specification's own security guidance is unusually candid about what that means. Under "Local MCP Server Compromise" it lists the risks as "Arbitrary code execution. Attackers can execute any command with MCP client privileges" and "No visibility. Users have no insight into what commands are being executed", and it imposes one real requirement: a client offering one-click server configuration "MUST implement proper consent mechanisms prior to executing commands", showing the exact command without truncation. Sandboxing those servers is a SHOULD. Nowhere is it required.

And the ecosystem is not curated. Anthropic says so directly: "Anthropic reviews connectors against its listing criteria before adding them to the Anthropic Directory, but does not security-audit or manage any MCP server." Note also what the spec does not name: "tool poisoning", "rug pulls" and "tool shadowing" are terms from third-party research, not from the specification. Useful vocabulary; do not attribute it to the standard in a review, because someone will check.

There are two specific gaps worth writing into your review, because both are the sort of thing that is fine right up until it is not:

The practical posture is not "ban extensions". It is to treat agent configuration as privileged source: .mcp.json, .claude/settings.json, hook scripts and skill files go behind CODEOWNERS, get reviewed by a human who knows what they do, and get an inventory somebody owns. Our piece on setting up Claude Code for a team covers which of those files should be committed and which must never be, and the agent skills security model covers the case where the privileged file is a Markdown document nobody thought to review.

The answer sheet

If you need one page to take into the meeting, this is it.

They askHonest answerThe control that helps
Where does our code go? To the model provider, always. Not trained on under commercial terms; 30-day standard retention. forceLoginMethod / forceLoginOrgUUID; ZDR if you qualify
What can it execute? Whatever your rules allow. Read-only by default; the OS sandbox is opt-in and fails open. Bare-tool deny; sandbox.enabled + failIfUnavailable
What stops rm -rf? A deny rule or the kernel. In bypass mode, only / and your home directory still prompt. Deny rules, a container for unattended runs, and git
How do secrets reach it? By inheritance, all the way down to a dependency's postinstall script. Nothing stops that by default. CLAUDE_CODE_SUBPROCESS_ENV_SCRUB, sandbox.credentials mask, short-lived tokens
Prompt injection? Unsolved, and the model-side defences are probabilistic. Not a reason to refuse; a reason to bound. The permission gate on anything that writes, publishes or spends
What is logged? Everything, in plaintext, on the developer's disk, for 30 days. Nothing centrally. cleanupPeriodDays, disk encryption, an OTel collector
Can we investigate? From git, EDR and the local transcript. There is no vendor per-tool-call audit trail. tool_decision events; ConfigChange hooks; copy transcripts early
The extension supply chain? A real gap. MCP servers and hooks run unconstrained, and the protocol cannot enforce consent. CODEOWNERS on agent config; an inventory; managed-only hooks

Notice how few of those controls are exotic. Managed settings, a deny list, a collector, CODEOWNERS, short-lived tokens, full disk encryption. A security team that hears this list recognises its own vocabulary, which is the actual goal of the meeting — not to prove the agent is safe, which is not a property anything has, but to show that its risks land in categories you already manage.

Where Backgrind fits

One honest note, and it is deliberately narrow, because a security post that resolves into a product pitch deserves to be dismissed.

Every answer above ultimately rests on a human decision at a gate being a real decision. That is a user-interface property, not a security property: an approval prompt sitting in a terminal behind a browser, an IDE and four other tabs gets answered on autopilot, and an autopilot approval is indistinguishable in the log from a considered one. Backgrind runs the CLI you already have — your login, your .claude/, your permission rules — in an always-on-top window, and surfaces a held PreToolUse ask as an ambient prompt with the command in front of you, wherever you happen to be looking. Its own "always allow" writes a scoped repo·tool·command rule locally with a decision log next to it, so a rule you granted at 2 a.m. is something you can read back. Because it is bring-your-own-CLI, agent content never reaches our server, which is the only claim in this paragraph that belongs on a data flow diagram.

It is not a security control and we would not put it in the table above. It is the difference between a gate you configured and a gate you actually operate. If you want the configured half done properly first, start with pre-approval policies, then what your team should commit — or see the overlay in the live demo.

Is it safe to let a coding agent run in a repo with production credentials in .env?

Treat it as no. Not because the agent is hostile, but because anything a tool reads is written to the session transcript in plaintext, and Anthropic names that case specifically: if a tool reads a .env file, that value lands in the .jsonl. Add the file to permissions.deny for Read, add it to sandbox.credentials as a denied path, and if the workflow genuinely needs the credential, use mask mode so the subprocess only ever holds a sentinel.

Does routing through Amazon Bedrock mean nothing reaches Anthropic?

Not quite, and the documentation does not claim it. Using Bedrock, Google Cloud's Agent Platform or Microsoft Foundry turns off telemetry, error reporting and /feedback by default, and inference happens on that platform under its retention policy. But the WebFetch domain safety check still sends the requested hostname — not the path or contents — to api.anthropic.com, and it is explicitly not covered by CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC. Disable it with skipWebFetchPreflight if your policy requires zero egress, and accept that WebFetch then consults no blocklist.

Is running the agent in a container enough?

It is the strongest single answer for the execution question and it does nothing for the data question. A container bounds what a compromised session can reach on the host, which is exactly what you want before running anything unattended. It does not change which files are uploaded to the model, it does not stop credentials mounted into the container from being inherited by every process inside it, and it does not give you an audit trail. Anthropic's own framing: sandbox isolation "reduces the impact of a breach, but it does not eliminate risk."

Can we just deny curl and wget and call the network handled?

No. Denying those two names blocks those two names. Any language runtime the agent is already allowed to run has an HTTP client, and Anthropic's permissions page warns separately that argument-scoped Bash patterns do not survive options, protocol changes, redirects or a variable holding the URL. Network egress is answerable at exactly one layer: a sandbox or proxy with a domain allowlist, enforced below the process. Anything above that is a speed bump.

What is the smallest configuration that would satisfy a reasonable review?

Roughly five things, all in managed settings so they cannot be loosened locally: pin the login to your organization; deny reads of credential paths and deny the tools you never want offered; enable the sandbox with failIfUnavailable on; set disableBypassPermissionsMode to "disable" outside containers; and point telemetry at a collector you own. Then put agent configuration files behind CODEOWNERS. That is an afternoon, and it converts most of the answers in this post from "it depends on the developer" to "it is enforced".

Sources

Training policy, retention periods, /feedback and session-survey uploads, telemetry variables, provider defaults and the WebFetch preflight: Claude Code — Data usage (checked 2026-08-07, v2.1.224). ZDR eligibility and the personal-account gap: Zero data retention. Permission enforcement, deny/ask/allow precedence, bare-name removal, permission modes, disableBypassPermissionsMode, the fragile-Bash-pattern warning and the Read/Edit subprocess caveat: Configure permissions. Prompt-injection protections, MCP review posture, trust verification and the -p exception: Security. Sandbox defaults, OS primitives, credential deny and mask, failIfUnavailable, and the "Security limitations" section including domain fronting: Configure the sandboxed Bash tool. Isolation comparison, "does not change what is sent to the model", unconstrained MCP servers and hooks, and the config-persistence warning: Choose a sandbox environment. Hook disclaimer, PreToolUse decision contract and ConfigChange: Hooks reference. Transcript paths, plaintext storage and cleanupPeriodDays: The .claude directory and Settings. OpenTelemetry events, tool_decision attributes and the content flags: Monitoring usage. Security principles, the RFC 2119 casing rule and the "cannot enforce at the protocol level" line, specification revision 2026-07-28: Model Context Protocol specification; untrusted annotations and the human-in-the-loop requirement: Tools; the STDIO authorization exemption: Authorization; local server compromise and the one-click consent requirement: Security best practices. Codex sandbox modes, the network-off default and the sandbox/approval split: Codex — agent approvals and security and Sandboxing, cross-checked against @openai/codex 0.147.0. Versions read from the npm registry on 2026-08-07.