Securing Agentic Coding

Definition

The control set for the generative-coding deployment shape, mapped to the six planes of the AAI-S RA and the nine domains of the AAI-S CMM.

Every configuration key and control name on this page belongs to Claude Code. The catalog is single-harness-deep by choice: Anthropic documents Claude Code’s security model in public at a level its competitors do not match, which lets this catalog name, grade, and check a control here instead of inferring it. The structure transfers to Cursor, Codex, and the open-source harnesses; the keys do not, and an organization running one of those must locate each equivalent and will sometimes find it absent. Read a key below as an instance of its control, local to this harness rather than a portable instruction.

The organizing claim is a ranking. Controls that constrain the process outrank controls that inspect a string, and both outrank controls that instruct the model. The GuardFall audit is the empirical basis: ten of eleven surveyed harnesses had string-inspecting guards that could be walked past with shell syntax older than the tools themselves.

Applicability

Whenever an agentic coding harness reads a repository. Which controls are load-bearing depends on which of the five shapes in Generative Coding Deployment Shapes is in play; read that page first if the deployment is not obviously interactive.

The Control Catalog

Reading guide

Control states the security property in vendor-neutral terms, so the row survives a change of harness.

Instrument names the thing that implements it. Instruments are of four kinds, distinguished by how a practitioner touches them: a settings key, given in dotted JSON-path form and set in a settings file; a session surface, such as the /sandbox slash command; a package or product, installed or purchased; or a practice with no product behind it. Keys are written once in full and then by their last segment. Minimum Claude Code versions appear where a key has one.

Grade is availability as of July 2026.

RA capability → CMM anchors the row to the AAI-S RA capability it implements and the CMM domain that scores it. The rows in this catalog are not restatements of the RA’s capability rows. The RA lists technology-neutral capabilities for agentic systems in general; this catalog lists controls for one deployment shape, at the granularity of the person configuring a harness. Some rows map onto an RA capability exactly, some map onto one at a coarser granularity, and nine map onto no RA row at all. Those nine carry and are analyzed in Controls with no RA capability.

Settings-key locations

Every settings.json key below resolves through five scopes, highest wins: managed, then command-line arguments, then the repository’s local override, then the repository’s checked-in settings, then the user’s own. Managed settings arrive two ways and do not merge with each other — a cached server-managed policy replaces the device-managed file outright:

DeliveryLocationReaches
Device-managed, deployed by MDM/Library/Application Support/ClaudeCode/ (macOS), /etc/claude-code/ (Linux and WSL), C:\Program Files\ClaudeCode\ (Windows) — managed-settings.json plus managed-settings.d/*.json merged alphabeticallyAny device the MDM enrolls, before first login
Server-managed, deployed from claude.aiDelivered to the authenticated sessionOnly accounts already authenticated into the organization

The distinction that decides whether a managed key is authoritative: boolean keys take the managed value and ignore local settings; array keys merge entries from every scope. So sandbox.enabled and failIfUnavailable cannot be relaxed locally, while excludedCommands and allowRead can be appended to by any developer. allowManagedReadPathsOnly and allowManagedDomainsOnly restore managed-only semantics for allowRead and for domains respectively. excludedCommands has no such lockdown.

Identity plane

ControlInstrumentGradeRA capability → CMM
Session pinned to a known organizationforceLoginMethod + forceLoginOrgUUID in managed settingsFirst-party, GA; full enforcement v2.1.212+— → D2
Federated identity behind that organizationSSO — Claude for Enterprise on the claude.ai side, or Claude Console SSO for API-billed organizations. Not available on Claude for TeamsCOTS, GA, plan-gatedAgent identity & lifecycle → D2
Per-workflow credential scopingOne token per environment and workflow, minimum permissionPractice; no productNHI governance → D2
Credential held outside the agent boundaryVendor credential proxy in the delegated-cloud shape; credential proxy elsewhereFirst-party for cloud; assembled elsewhereCredential proxy → D2
Attribution of an action to an agent and a humanEndor Labs AI Code GovernanceCOTS; Endor Labs is the only sourced vendorAction-to-identity tracing → D2

The organization pin covers fewer login paths than it appears to. Terminal, IDE-extension, and SDK logins are held. The two token-minting commands check only the login method, not the organization, so both can produce a credential in a different tenant. Gateway sign-in never authenticates against an Anthropic organization at all, which makes the gateway’s own identity provider the control. Bedrock, Vertex, and Foundry sessions authenticate against the cloud provider and are not blocked, so cloud IAM policy is the control there. Deploy the pin through device management: server-managed settings only reach accounts already inside the organization, and so cannot govern a first login.

No first-party feature attributes a change to the agent or the human that produced it, across any harness vendor. An organization that cannot separate agent-authored from human-authored change cannot scope a review policy or trace a defect to the tool that introduced it.

Control plane

ControlInstrumentGradeRA capability → CMM
Managed permission policy that local settings cannot overridemanaged-settings.json by MDM, or server-managed settingsFirst-party, GAPolicy engine, degenerate case → D3
Deny rules that survive autonomous modespermissions.deny; explicit deny is honored even under sandbox auto-allow and --dangerously-skip-permissionsFirst-party, GALeast-agency tier engine, block tier → D3
Content-scoped prompts that autonomy cannot suppresspermissions.ask with an argument pattern — Bash(git push *), Bash(dangerouslyDisableSandbox:true)First-party, GALeast-agency tier engine, confirm tier → D3
Lock developers out of widening policyallowManagedReadPathsOnly, allowManagedDomainsOnlyFirst-party, GA— → D3
Deterministic per-action reference monitorCedar-routed lifecycle hooks — see MaiselPractitioner prototypePolicy language / PDP engine → D3
Audit or block in-session settings changesConfigChange hooksFirst-party, GA— → D3

The permissions.ask row survives contact with an autonomous mode, and its behavior is specific enough to test. A bare Bash or Bash(*) ask rule is skipped for any command that runs sandboxed, so an organization that wrote one and then enabled the sandbox has no prompt left. An ask rule scoped to an argument pattern still fires. An ask rule on Bash(dangerouslyDisableSandbox:true) catches the escape hatch in flight.

The distinction that matters for scoring is the merge semantics described above: excludedCommands merges across scopes and has no managed-only lockdown, so a developer can always append entries that run commands outside the sandbox. Keep the managed list narrow and treat it as a reviewed artifact.

Runtime plane

ControlInstrumentGradeRA capability → CMM
OS isolation of shell subprocessessandbox.enabled, configured through the /sandbox session surface — Seatbelt on macOS, bubblewrap plus socat on Linux and WSL2, optional seccomp for Unix-socket blockingFirst-party, GA; no native Windows supportSandbox / containment → D4
OS isolation of the whole session, including MCP servers and hookssandbox-runtime`FOSS, beta research previewSandbox / containment → D4
Container isolationPublished dev container with default-deny iptables firewall; runs Claude Code as a non-root userFOSS reference configSandbox / containment → D4
Kernel-level isolationVM, microVM (Firecracker), vendor-managed cloud VMGA, varies by providerSandbox / containment → D4
Write confinement inside the sandboxallowWrite, denyWrite; default is the working directory and session temp directory onlyFirst-party, GASandbox / containment → D4
Read confinement inside the sandboxdenyRead, re-opened selectively by allowRead; exact deny beats wider allowFirst-party, GASandbox / containment → D4
Authoring-time dangerous-pattern warningSecurity Guidance plugin — pre-tool hook on Write, Edit, MultiEditFirst-party, free, warns onlyCode-output static analysis → D4
Hard failure when isolation is unavailablefailIfUnavailable, allowUnsandboxedCommandsFirst-party, GA— → D4

Four configuration facts an assessor should verify rather than assume.

Sandbox read access defaults to the whole filesystem minus explicit denies, so ~/.aws and ~/.ssh remain readable until sandbox.credentials or denyRead entries exist. The escape hatch is a tool parameter, dangerouslyDisableSandbox, which the model may set to retry a command that failed under isolation; setting allowUnsandboxedCommands makes the parameter ignored entirely, which the /sandbox panel labels strict sandbox mode. The built-in sandbox covers Bash and its child processes only — Read, Edit, and Write run under the permission system instead, which is how the Microsoft finding reached /proc/self/environ while the Bash boundary held.

The fourth is newer than the rest of this catalog and inverts a control an assessor may already have scored. filesystem.disabled (v2.1.216 and later) turns the filesystem layer off while leaving network isolation on. Setting it also disables the sandbox.credentials.files read protections, the denyRead rules, and the automatic write-deny on settings.json at every scope, while sandboxed commands stay auto-allowed. The vendor documentation flags that combination as self-escalating: a command can write a shell startup file or settings.json that widens its own access on the next run. The key is honored from user, managed, and --settings sources but not from project or local settings, and managed settings can reserve it exclusively by configuring filesystem or listing any sandbox.credentials.files entry. Verify the resolved value rather than the presence of sandbox.enabled.

One property of this plane is not a settings key at all, and so gets no row. A sandbox is a control from the moment it exists, and the harness reads workspace configuration before that moment. GHSA-wpqr-6v78-jr5g is the case on the public record: headless Gemini CLI trusted the workspace folder for configuration and environment loading and executed from an attacker-supplied .gemini/ tree before its sandbox initialized (Novee Security, 2026-04-30). Whether workspace trust is granted can be a key — Gemini CLI’s GEMINI_TRUST_WORKSPACE is one since 0.39.1. When the isolation boundary is established relative to that read is a property of the harness’s startup sequence, which no vendor documentation states. Every row above is assessable by resolving a settings value; this one is an open question to put to a vendor rather than a control to score.

Egress plane

ControlInstrumentGradeRA capability → CMM
Domain allowlist for agent subprocessesallowedDomains, deniedDomains; no domain is pre-allowed, and WebFetch(domain:...) allow rules pre-allow as wellFirst-party, GAEgress destination filtering → D5
Deny rather than prompt outside the allowliststrictAllowlist (v2.1.219+, ignored from project and local settings); allowManagedDomainsOnly for the managed-only variantFirst-party, GAEgress destination filtering → D5
TLS-terminating inspectiontlsTerminate (v2.1.199+); custom proxy via httpProxyPort with its CA installed inside the sandboxExperimental first-party; custom proxy supported— → D5
Credential masking on outbound requestssandbox.credentials.envVars with mode: mask and injectHosts (v2.1.199+); the command sees a per-session sentinel and the proxy substitutes the real valueFirst-party, GA; fails closed without TLS terminationCredential proxy, inverted → D5
Corporate proxy for all trafficHTTPS_PROXY / HTTP_PROXYFirst-party, GAMCP / A2A / LLM proxy → D5

Masking is the row most likely to be configured into a false sense of coverage. It is honored only from user, managed, and --settings sources — mask entries in a repository’s settings.json are ignored — and every injectHosts entry must itself be covered by allowedDomains. Without tlsTerminate the sentinel reaches the server unchanged and authentication fails rather than leaking, which is the right failure direction but means the control is either working or visibly broken, never silently partial.

The default proxy makes its allow decision from the client-supplied hostname without inspecting TLS. The vendor documentation states the consequence directly: a broad allowlist entry such as github.com is reachable by domain fronting. A hostname allowlist without TLS termination is a misconfiguration control. It is not an exfiltration control, and D5 should grade it that way.

Data plane

ControlInstrumentGradeRA capability → CMM
Credential file and environment-variable denialsandbox.credentials.files and sandbox.credentials.envVars with mode: deny (v2.1.187+); files are blocked for reads, variables are unset before each sandboxed commandFirst-party, GA; sandboxed Bash only— → D6
Subprocess credential scrubbing regardless of sandboxingCLAUDE_CODE_SUBPROCESS_ENV_SCRUB — strips Anthropic and cloud-provider credentials from every subprocess, and forces filesystem isolation to stay onFirst-party, GA— → D6
Self-modification protectionSandbox denies writes to settings.json at every scope and to the managed settings directory, resolving symlinks (v2.1.210+)First-party, GA; lost if filesystem.disabledCognitive file integrity → D6
Instruction-file integrityCognitive file integrity over CLAUDE.md, skills, subagentsPractice; partial product coverageCognitive file integrity → D6
Harness-configuration auditAgentShield; Endor LabsFOSS single instrument; COTS single vendorSupply-chain scanning → D8
Untrusted-input exclusion in CIDisable fork-PR execution; exclude issue and comment bodiesPractice— → D6

There is no built-in credential deny list. Only the paths and variables explicitly listed are restricted, which makes this the single most commonly skipped configuration step in the catalog. The two rows above it divide along a boundary worth stating: sandbox.credentials protects sandboxed Bash commands and nothing else, while CLAUDE_CODE_SUBPROCESS_ENV_SCRUB reaches every subprocess whether sandboxed or not. An organization that configured only the first has left MCP servers and hooks holding the credential.

Observability plane

ControlInstrumentGradeRA capability → CMM
Session telemetry to a SIEMOpenTelemetry export — CLAUDE_CODE_ENABLE_TELEMETRY=1 plus OTEL_LOGS_EXPORTER, emitting one claude_code.* event per prompt, tool decision, tool result, permission-mode change, MCP connection, and login, correlated by session and prompt IDFirst-party, GASIEM / SOAR with agent playbooks → D7
Security-relevant content inside that telemetrythe four OTEL_LOG_* gates — tool details (shell command strings, MCP tool names, skill names), user prompts, assistant responses, raw API bodiesFirst-party, GA, off by defaultOTel gen_ai.* SemConv → D7
Per-user usage and contribution analyticsClaude Enterprise Analytics API (read:analytics key, Enterprise only) or Claude Code Analytics API (Admin API key, Console organizations)GA, plan-split; not available on Claude for Teams— → D7
Fleet inventory of harnesses, MCP servers, skills, hooksEndor Labs AI Code GovernanceCOTS; Endor Labs is the only sourced vendorAI-SPM / runtime AI-BOM → D7
Pull-request security review as a gateclaude-code-security-review GitHub ActionFOSS, first-partyCode-output static analysis → D8
Cross-harness session telemetry and retrospective forensicsNumbat — filesystem session artifacts normalized to NDJSON plus a localhost OTLP receiver, spanning Claude Code, Codex, OpenCode, and PiFOSS; Perplexity, vendor-announced; forensics half also implemented by Uber ADRSIEM / SOAR with agent playbooks → D7

Content redaction is the default, and it is the finding that separates the appearance of agent audit from the fact of it. An organization that enables telemetry and stops there receives token counts, costs, durations, permission-mode transitions, and MCP connection status — and no shell command strings, no prompt text, no tool arguments. That stream cannot answer what an agent ran, which makes it a usage feed rather than a security feed. Turning it into a security feed means deciding to export prompt and tool content, with the data-handling consequences that decision carries.

The two analytics APIs are different products with different scopes, and neither substitutes for the telemetry stream. Contribution metrics are Teams and Enterprise only, in public beta, dependent on the GitHub app, unavailable to organizations running Zero Data Retention, and documented as excluding Claude Console API usage and third-party integrations. The Console dashboard covers Console-billed API usage and shows spend rather than contribution. Sessions routed through Amazon Bedrock, Google Cloud’s Agent Platform, Microsoft Foundry, or a self-hosted gateway fall outside both.

OpenTelemetry export is not disabled under Bedrock, Vertex, or Foundry; only the claude_code.internal_error event is suppressed there. The D7 regression an inference gateway causes is narrower than a total loss of visibility: it removes the first-party analytics dashboards, and OpenTelemetry remains available as the rebuild path. Step 8 of the deployment order below depends on this.

Controls with no RA capability

Nine rows anchor to a CMM domain but to no RA capability. They fall into three groups, and the groups have different implications.

Properties of a control rather than controls. failIfUnavailable and allowUnsandboxedCommands, allowManagedReadPathsOnly and allowManagedDomainsOnly, and ConfigChange auditing do not add a capability. They determine whether an existing capability fails closed, whether a local scope can widen it, and whether a change to it is visible. The RA’s capability vocabulary has no slot for these, and the omission is not specific to generative coding: every plane has controls that can be silently disabled locally or that degrade to a warning when a dependency is missing.

The RA has no representation for fail-closed and lockdown properties

A capability row records that a control exists, not that it holds when its dependency is absent or that a lower scope cannot relax it. This affects the whole RA rather than this shape. Resolving it means either a per-capability property column or a cross-cutting section, and the choice needs to be made against the RA as a whole, not decided here.

Process-environment hygiene. sandbox.credentials deny entries, CLAUDE_CODE_SUBPROCESS_ENV_SCRUB, and per-workflow token scoping cover the case where a credential is already inside the agent’s process. The RA’s Identity plane assumes the credential-proxy pattern, where the credential never enters the process at all, and so has no row for containing one that has. For a local coding harness inheriting a developer’s shell environment, the proxy assumption does not hold, so the hygiene controls carry the load.

Genuinely shape-specific. Pinning a session to a known Anthropic organization, excluding untrusted input from CI triggers, and the first-party analytics APIs are artifacts of how this particular product is licensed, triggered, and instrumented. They belong in a catalog and not in a reference architecture.

Method

A deployment order that follows the control ranking rather than the plane order:

  1. Establish the isolation boundary before reducing prompts. Enable the sandbox with failIfUnavailable and allowUnsandboxedCommands through managed settings, and only then allow autonomous modes. The reverse order — suppressing prompts first and hardening later — is the sequence that produces incidents. The same ordering holds one level down, inside a single run: ask each vendor whether its boundary is established before the harness reads workspace-supplied configuration, because one harness answered no and no vendor documentation states the ordering.
  2. Close the read side. Add sandbox.credentials deny entries for ~/.aws, ~/.ssh, and the secret environment variables in use. Nothing is denied by default.
  3. Match the boundary to the shape. Bash-only sandboxing is insufficient for unattended runs; wrap the whole process (sandbox runtime, container, or VM) wherever prompts are suppressed.
  4. Apply the Rule of Two to every non-interactive workflow. For a CI-triggered agent, remove untrusted input, or remove secrets from the process environment, or remove push and egress. Choose one explicitly and record which.
  5. Lock the network before widening it. strictAllowlist plus managed-only domains; terminate TLS if the threat model includes exfiltration rather than misconfiguration.
  6. Put the harness configuration under source control and scan it. The config tree is a supply-chain artifact; hooks, MCP manifests, acquired third-party skill packs, and CLAUDE.md belong in review and in CI.
  7. Gate on the pull request, not on the keystroke. The authoring-time plugin warns; only the CI review action can hold a merge.
  8. Export telemetry before the fleet grows. Session-correlated OpenTelemetry to the SIEM, and an inventory mechanism that survives more than one harness vendor.

Mechanism

Each step in the ordering removes a dependency on a weaker layer. OS enforcement holds regardless of how a command was spelled, which is the closure the guard canonicalization gap demands. Removing a Rule-of-Two property removes the precondition for the attack chain rather than detecting its execution. Scanning the configuration tree catches the persistence mechanism: an injected hook survives the session that installed it, turning CVE-2026-25725 from a session compromise into a sandbox escape.

Limits

The single-harness scope stated at the top has a sharper edge than convenience. GuardFall’s finding suggests the open-source equivalents are weaker rather than merely different, so an organization that maps this catalog onto another harness should treat a missing key as a missing control until it has evidence otherwise, not as a naming difference. The reverse direction is the newer risk: another harness may hold a control surface this catalog has no row for, and a defect there is invisible to a reader working from these rows. Workspace trust is that surface — Gemini CLI grants or withholds it through GEMINI_TRUST_WORKSPACE, Claude Code has no equivalent key, and the control’s absence from the catalog is a property of the catalog rather than a finding about either product.

Cross-harness coverage now has one sourced instrument, and it covers only part of the catalog. Numbat attaches to hooks, session artifacts, and OTLP across several harnesses behind one interface. It narrows the gap for observability and for blocking without closing it: the harness-native identity, sandboxing, and egress controls in the rows above have no cross-harness equivalent, so a second harness still inherits whatever isolation its own settings provide.

A security skill installed into the harness is an acquired instruction pack, and it runs under the boundary this catalog configures. Semgrep’s survey of open-source AI code-security harnesses records four such sets distributed for Claude Code and Codex: Trail of Bits’ plugin marketplace, Cloudflare’s security-audit-skill, Capital One’s vulnhunter, and Google’s mantis (Semgrep, July 2026). Two of them drive execution against the repository under audit, per the LLM-generated per-tool summaries in that survey: the Cloudflare skill may build and run code to confirm a finding, and Trail of Bits’ constant-time and zeroize skills compile and inspect assembly. The Runtime-plane and Egress-plane rows above bound every such run, and the skill supplies no boundary of its own, so step 6 covers the acquisition and the sandbox covers the execution. The installing population is the security team itself, so the function that scores the harness-audit row is also the function that acquires the packs it would score. The open-source harness landscape carries the per-project comparison.

Every control above is ordered against an adversary, and one relevant threat model has none. The accidental meltdown case — an agent crossing a boundary while pursuing the user’s actual goal after an ordinary environmental error — passes through content filtering and injection classifiers untouched, because it never presents the malicious input they test for. The isolation and Rule-of-Two controls still hold, since they cap reach without reference to intent. The detection controls largely do not.

Several load-bearing instruments are single-sourced. Sandbox runtime is a beta research preview. The COTS control plane in the attribution, harness-audit, and fleet-inventory rows is Endor Labs AI Code Governance in all three cases — one vendor’s product material, with no dated GA announcement and no independent evaluation. AgentShield is one open-source scanner. No competing implementation of the fleet-inventory capability is sourced here, so that row records a market gap as much as a control.

Nothing here addresses code quality. Every control in the catalog governs what the agent may do. Whether the code it writes is correct is a separate problem, addressed by review capacity that the throughput data suggests is already the binding constraint. One practitioner pattern attacks that problem from the other end, by governing what the agent is told before it writes: Gupta’s MCP server retrieves the ticket, the architecture document, the applicable OWASP cheat sheets and the organization’s own standards into the prompt, then verifies the generated code against those same requirements. It belongs to no plane above because it constrains generation rather than execution, and it carries the enforcement weakness that placement implies — the agent calls the server because the tool description persuaded it to, which Gupta states does not happen every time.

That pattern also answers the cross-harness limit above from a second direction. Numbat narrows the gap for observability across harnesses; a control delivered over MCP is portable for the same structural reason, since every product in this market ships MCP support as a condition of entry. For a fleet whose majority sits on a harness whose keys this catalog does not carry, the pre-generation control and the telemetry instrument are the two entries here that transfer by design, and both are weaker than the harness-native rows they stand in for. An organization in that position should treat this catalog as the specification for the harness it can configure, and read the two portable instruments as partial cover for the remainder of the fleet.

Promotion Path

If a standards body publishes a control set for agentic software development — the natural candidates being an SSDF extension or an OWASP agentic-coding guide — this page becomes a crosswalk to it rather than a standalone catalog.