Skip to main content
AI-driven development & productivity
Claude Code
AI駆動開発
セキュリティ
AI

Security governance for rolling Claude Code out to an organization — permission modes, managed settings, sandboxing and CI

What to decide before handing Claude Code to a team: which of the six permission modes to allow, the deny→ask→allow evaluation order, delivering managed settings and the keys users can't override, the sandbox that is off by default, hook governance, and the CI trust trap, per the official docs as of October 2026.

Published
Reading time
17 min read
Author
友田 陽大
Share

The short answer first. When you bring Claude Code into an organization, the thing to design is not how clever the model is. It is what an agent running on a developer's machine, with that developer's permissions, may do without asking, what it must confirm, and what it may never do. You then put those decisions into managed settings that developers can't override, and cover what permission rules can't stop with the sandbox and device management.

How an individual or a small team hardens its own settings.json is covered in Running Claude Code in production — permissions, hooks, CLAUDE.md and security gates. This article picks up where that one stops: the design a CTO, infrastructure lead or security lead applies when handing Claude Code to a whole team. Whether to adopt a given MCP server is split out into Trusting and governing third-party MCP servers.

Every setting key, path and default here was checked against the official documentation (code.claude.com/docs) as retrieved on 2026-10-12. Claude Code ships quickly and many behaviors depend on the version, so confirm them against the version you actually deploy.


1. Threat model: an agent running with the developer's own permissions

What you are protecting is not "the Claude Code tool" but the developer's machine and everything it can reach. Claude Code runs locally, reads and writes files, and runs shell commands with the developer's user permissions. The official Security page says the working-directory boundary is only a permission prompt, and that "a Bash command you approve can still write anywhere your user account can."

Thinking about the blast radius in five channels keeps you from missing anything.

ChannelWhat can happenMain controls
FilesReading secrets, rewriting files outside the working directoryRead/Edit rules, sandbox filesystem settings
ShellRunning arbitrary commands, getting around rules via child processesPermission modes, Bash rules, the sandbox
NetworkExfiltration, connecting to unapproved hostsSandbox network settings, WebFetch rules
CredentialsLeaking ~/.ssh, ~/.aws or environment variablesdenyRead, sandbox.credentials, scrubbing the environment
CIRuns nobody is watching, instructions planted in untrusted pull requests--bare, dontAsk, the Action's trigger rules

The entry point that deserves the most attention is prompt injection: instructions hidden in outside content (an issue body, a web page, an MCP server's response) that try to take over the agent's decisions. The basic stance for an organization is not to rely on the model's judgment, but to use settings to define a range the agent can't reach even if its judgment is hijacked.

Before everyone on the team gets it

Permissions and governance for using Claude Code safely as an organization

2. Permission modes: which of the six to allow, and for whom

As of October 2026 there are six permission modes. The first organizational decisions are to keep bypassPermissions off developer machines, and whether to allow auto mode.

ModeWhat runs without askingIntended use (per the docs)Example organizational policy
default (shown as Manual)Reads onlyReviewing every action yourself, sensitive workAllowed for everyone; the default for sensitive repositories
acceptEditsReads, file edits and common filesystem commands such as mkdirIterating on code you're reviewingAllowed for day-to-day development
planReads (plus classifier-approved commands when auto mode is available)Exploring before changing anythingAllowed for everyone
autoEverything, with background safety checksLong tasks, less prompt fatigueA policy call; to block it, disableAutoMode
dontAskReads in the working directories and pre-approved tools; anything that would prompt is deniedLocked-down CI and scriptsCI only
bypassPermissionsEverythingIsolated containers and VMs onlyDisabled on developer machines

In auto mode, a separate classifier model reviews actions instead of the user and blocks the ones it judges unsafe. Note that from v2.1.283, auto is the starting mode for sessions launched in a terminal. To block it organization-wide, set disableAutoMode (also accepted as permissions.disableAutoMode) to "disable" in managed settings.

bypassPermissions removes the prompts and safety checks. The docs warn to use it only in isolated environments such as containers, VMs or dev containers without internet access. Setting permissions.disableBypassPermissionsMode to "disable" also makes Claude Code reject the --dangerously-skip-permissions flag.

Deny rules work regardless of mode: the docs state that "deny rules block in every mode, including bypassPermissions." Also, defaultMode: "bypassPermissions" or "auto" in a project's .claude/settings.json doesn't take effect from that file, so a cloned repository can't loosen the mode on its own.

3. The allow / ask / deny order, and denies that cross scopes

Rules are evaluated deny, then ask, then allow, and the first match decides the outcome. Writing a more specific rule doesn't change that order.

The order also crosses scopes. In the docs' words, "a user-level deny blocks a project-level allow, because deny rules from any scope are evaluated before allow rules." A deny in managed settings can't be overridden by --allowedTools, while --disallowedTools can add further restrictions.

That has two implications for an organization.

  • Anything you put in deny loses to no allow anywhere below it. Put the operations you must never let through, such as reading secrets or git push --force, in the managed deny list.
  • Allow widens access, so you may want to control where it comes from. With allowManagedPermissionRulesOnly: true, Claude Code ignores allow, ask and deny rules from user, project, local and --settings files, ignores --allowedTools, and hides the "always allow" choices. It is powerful, but it increases prompt fatigue, so rolling it out first to the most regulated teams is the realistic path.

Note also that permissions.allow rules in a project's .claude/settings.json apply only after someone accepts the workspace trust dialog for that folder. Deny and ask rules aren't affected, since they only restrict.

4. Where rule syntax stops: neither Bash rules nor Read denies are a boundary

Permission rules match the form of command Claude usually writes. They are not a fence around the program itself. Misread this and you leave holes you think you have closed.

For Bash rules, the docs say plainly that a deny or ask rule "isn't a security boundary around the program." A deny on Bash(curl *) doesn't match /usr/bin/curl https://example.com or sh -c 'curl https://example.com'. And curl and wget are merely not auto-approved by default; they are not on a built-in blocklist. If you want them stopped, put them in deny, and if the restriction must hold, combine that with the sandbox network allowlist.

Read and Edit denies are similar. They apply to the built-in file tools, to file commands Claude Code recognizes such as cat, head and sed, and to redirection targets like > file. They don't apply to grep -r pattern ., which reads files without naming them, or to a Python or Node script that opens files itself. A .claudeignore file has no effect, so if you rely on one, move its entries into Read deny rules.

Path syntax has its own trap. /path is anchored at the settings file's location, not the filesystem root. Read(/secrets/**) in user settings blocks ~/.claude/secrets/**. Write absolute paths as //path and home-relative paths as ~/path.

5. The settings hierarchy and how to deliver managed settings

Managed settings are the top layer: no user setting, project setting or --settings value overrides them. From highest to lowest, the order is managed settings → --settings on the command line → .claude/settings.local.json → .claude/settings.json → ~/.claude/settings.json. List keys such as permissions.allow are merged rather than overridden.

There are four delivery mechanisms.

  • File: /Library/Application Support/ClaudeCode/managed-settings.json on macOS, /etc/claude-code/managed-settings.json on Linux and WSL, and C:\Program Files\ClaudeCode\managed-settings.json on Windows. The legacy C:\ProgramData\ClaudeCode\managed-settings.json is not read. Split files in a managed-settings.d/ directory next to it are merged in alphabetical order.
  • MDM / OS policy: the com.anthropic.claudecode managed preferences domain on macOS, and a REG_SZ or REG_EXPAND_SZ value named Settings under HKLM\SOFTWARE\Policies\ClaudeCode on Windows.
  • Server-managed settings: delivered from the claude.ai admin console. They require Claude for Teams or Claude for Enterprise, and the Owner or Primary Owner role to edit.
  • HKCU registry: user-writable, so it doesn't count as an admin source.

The easily missed part is what happens when you use more than one mechanism. By default (managedSourcesBehavior set to "first-wins"), Claude Code uses only the highest-ranked source that contains a policy key and ignores the rest instead of merging them. The ranking is server-managed → MDM → file → HKCU. So you can try out server-managed settings briefly and find that the sandbox policy you were delivering by file has stopped applying. If you need both, consider managedSourcesBehavior: "merge", and use /status to see which source is in effect.

Server-managed settings come with two more constraints.

  • The docs state that they "operate as a client-side control, not a security boundary. On unmanaged devices, a user doesn't need admin or sudo access to bypass them."
  • If a provider variable such as CLAUDE_CODE_USE_BEDROCK, or a non-default ANTHROPIC_BASE_URL, is exported in the shell, the fetch is skipped. Organizations on Amazon Bedrock, Google Cloud's Agent Platform (formerly Vertex AI) or Microsoft Foundry deliver policy through endpoint management or a self-hosted Claude apps gateway instead.

6. Managed-only keys versus keys any file can set

Keep two kinds of keys apart: keys that are enforced because they sit in managed settings, and keys any file can set, which become non-overridable only once you place them in managed settings. The Scope line in the settings reference is the authority.

KindMain keysWhat it means
Managed onlyallowManagedPermissionRulesOnly, allowManagedHooksOnly, allowManagedMcpServersOnly, managedMcpServers, strictKnownMarketplaces, blockedMarketplaces, disableSideloadFlags, sandbox.network.allowManagedDomainsOnly, sandbox.filesystem.allowManagedReadPathsOnly, forceRemoteSettingsRefreshLocks that have no effect outside managed settings
Any filepermissions.disableBypassPermissionsMode, disableAutoMode, allowedMcpServers, deniedMcpServers, enableAllProjectMcpServers, sandbox.enabled, sandbox.allowUnsandboxedCommands, cleanupPeriodDays, envCan't be overridden when set in managed settings, but also work from lower files
Exceptions where a stricter lower value winspermissions.blockReadsOutsideWorkingDirectories: true, disableClaudeAiConnectors: true and othersA true from any scope applies, even over a managed false

That allowedMcpServers is not managed-only is especially easy to get wrong. Unless you also set allowManagedMcpServersOnly, users can widen the allowlist in their own settings. The MCP article covers this in detail.

7. The sandbox: off by default, and ~/.ssh is readable even when on

The sandbox is off by default. Even when it is on, by default it can read most of the machine, including ~/.ssh and ~/.aws/credentials. For organizational use, put enabling it and blocking those reads into managed settings together.

The sandbox wraps the shell commands Claude runs, and their child processes, with Seatbelt on macOS and bubblewrap on Linux and WSL2. Its defaults are:

  • Writes: the working directory, a per-user temp directory and directories you've added.
  • Reads: most of the machine. Close paths off with sandbox.filesystem.denyRead; paths in your Read deny rules are merged in as well.
  • Network: no direct route out. A local proxy checks each host against allowedDomains, which starts empty.
  • Environment variables: inherited from Claude Code, so any secrets there are visible.

Know what runs outside it, too. Built-in tools such as Read, Edit, Write, WebFetch and WebSearch follow permission rules rather than the sandbox (denyRead doesn't stop the Read tool). Command hooks, local MCP servers, LSP servers, the status line command and apiKeyHelper run with the user's full access.

The docs' configuration for enforcing it is three keys: enabled: true, failIfUnavailable: true and allowUnsandboxedCommands: false. Without the last one, Claude can retry a command that failed inside the sandbox outside it, using dangerouslyDisableSandbox. With failIfUnavailable, Claude Code exits at startup on native Windows, where the sandbox doesn't run, so either move Windows developers to WSL2 or a container, or deliver a different policy per operating system.

Keep allowed domains narrow. The proxy doesn't terminate or inspect TLS by default, and the docs warn that allowing a broad domain such as github.com can create paths for exfiltration, including through domain fronting. Allowing /var/run/docker.sock via allowUnixSockets effectively hands over access to the host. To keep developers from widening the policy, consider allowManagedDomainsOnly and allowManagedReadPathsOnly.

8. Secrets: where they live and how to hide them

Think about secrets in three layers: don't let the tools read them, don't pass them to child processes, and don't leave them in plaintext.

  1. Don't let tools read them: write both a Read deny (for the built-in tools) and sandbox.filesystem.denyRead (for shell commands). If a secret file has to stay usable while its contents stay hidden, sandbox.credentials lets you set deny or mask per file or variable.
  2. Don't pass them on: with CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1, credentials are stripped from the environments of the subprocesses Claude Code starts, such as Bash commands, hooks and stdio MCP servers (GitHub tokens and proxy settings are left in place).
  3. Don't leave them in plaintext: values in a settings file's env block are plaintext and reach every subprocess. Fetch API credentials from a vault on demand with apiKeyHelper. Session transcripts are also stored in plaintext under ~/.claude/projects/, for 30 days by default; shorten that with cleanupPeriodDays.

Claude Code's own API keys and tokens are stored in the macOS Keychain when available, and on Linux in a file with mode 0600.

9. Hooks: run only the ones the organization ships

Hooks run shell commands with the user's full permissions, so whose hooks run is itself something to govern. With allowManagedHooksOnly: true in managed settings, only managed hooks, Agent SDK hooks and hooks from plugins that managed settings force-enable will run; user, project and local hooks are blocked.

Conversely, hooks the organization ships can't be turned off by disableAllHooks in a lower scope. A PreToolUse hook returning "allow" doesn't override a deny rule, so hooks are safest as reinforcement in the blocking direction.

For auditing configuration changes, use a ConfigChange hook. It fires when user, project or local settings files, or skill files, change during a session, and it can log or block the change. It can't block a change to managed files, though, and it doesn't fire at all for changes to server-managed settings, macOS managed preferences or the Windows registry.

10. Data handling: training, retention and ZDR

Under commercial terms (Team, Enterprise, API and third-party platforms), code and prompts sent to Claude Code are not used for training unless the customer chooses to provide them. When checking against internal policy, cover these points.

  • Standard commercial retention is 30 days.
  • Transcripts sent with /feedback and similar commands are retained for 5 years. Decide how to treat that when they contain work code.
  • Zero data retention (ZDR) is for qualified Claude for Enterprise accounts. It is not included in the standard Enterprise plan and cannot be enabled from admin settings; it needs separate enablement by Anthropic and applies only to Anthropic's direct platform.
  • Traffic is encrypted with TLS 1.2 or later. The usage metrics Claude Code sends never include code, prompts or file paths, and DISABLE_TELEMETRY=1 turns them off.

11. Observability and audit

Usage can be exported to your own collector with OpenTelemetry, and administrators can set this for everyone through the env block in managed settings. Set CLAUDE_CODE_ENABLE_TELEMETRY=1 and the OTEL_* exporters. When managed settings name the destination, developer-set destinations are removed at startup, and a repository's settings files can't set the exporter variables at all.

On the privacy side, logging prompt text (OTEL_LOG_USER_PROMPTS) is off by default, as is logging tool arguments (OTEL_LOG_TOOL_DETAILS). Decide what to record together with your employment and personal-data policies.

On Team and Enterprise, Admins and Owners can see usage in the claude.ai analytics dashboard. For audit logs of settings changes, the docs say they are available through the compliance API or audit log export, and direct you to your Anthropic account team.

12. CI: the -p trust trap and GitHub Actions

The most dangerous thing in CI is that claude -p never shows the workspace trust dialog. Without --bare, it runs the hooks in the repository's .claude/settings.json and connects the servers in its .mcp.json without asking, even in a folder you have never trusted. The docs recommend --bare for scripted calls and the SDK. The project's env block still applies under --bare, though, so don't rely on it alone.

The basic shape for a CI job is --permission-mode dontAsk plus --allowedTools listing exactly the tools it may use, so anything that would prompt is denied.

With GitHub Actions (anthropics/claude-code-action), settle these points first.

  • Who can trigger it: on issue and pull request events, the triggering user must have write access to the repository. Bypassing that with allowed_non_write_users is described as "a significant security risk." Bots are rejected unless listed in allowed_bots.
  • Configuration on pull requests: when it runs against a pull request, the action restores configuration paths such as .claude/, .mcp.json and CLAUDE.md from the base branch before starting Claude, so Claude doesn't run with configuration the pull request rewrote.
  • pull_request_target and workflow_run: these run with the base repository's secrets, so never check out an untrusted ref into the workspace root before the action.
  • Hidden instructions: the action strips HTML comments, invisible characters and similar content, but its docs acknowledge that new bypass techniques may emerge. Keep permissions minimal for workflows where Claude reads issues or pull requests written by outsiders.
  • API keys: never commit them; store them as GitHub Secrets.

13. What each setting prevents, and what it doesn't

No setting is complete on its own. In a rollout review, use this table to find the gaps.

SettingWhat it preventsWhat it doesn't prevent
Read(...) in permissions.denyReads through the built-in file tools and recognized commandsReads by scripts or subprocesses that open files themselves
Bash(curl *) in permissions.denycurl in the form Claude usually writesA full path, sh -c, or a different network tool
disableBypassPermissionsModeBypass mode, including --dangerously-skip-permissionsAuto mode (that needs disableAutoMode)
sandbox.enabled + allowUnsandboxedCommands: falseShell commands and their children going beyond allowed files and hostsHooks, local MCP servers, built-in tools, commands the user types at !
sandbox.filesystem.denyReadSandboxed commands reading secret filesThe Read tool (needs a Read deny)
sandbox.network.allowedDomainsConnections to hosts outside the listExfiltration through a broadly allowed domain, TLS contents
Server-managed settingsOverrides on managed devicesBypass on unmanaged devices, sessions on third-party providers
allowManagedHooksOnlyHooks brought in by individuals or repositoriesDefects in the hooks the organization ships
--bare (CI)Auto-loading the repository's hooks, skills and .mcp.jsonThe project's env block

14. An example baseline managed-settings.json

The example below is a starting point built only from keys confirmed in the official docs. Don't ship it as is: change the values to match your package registry and internal MCP servers, and verify it with a pilot group before widening it.

{
  "permissions": {
    "deny": [
      "Read(.env)",
      "Read(.env.*)",
      "Read(secrets/**)",
      "Read(~/.ssh/**)",
      "Read(~/.aws/**)",
      "Bash(curl *)",
      "Bash(wget *)"
    ],
    "ask": [
      "Bash(git push *)"
    ],
    "disableBypassPermissionsMode": "disable"
  },
  "sandbox": {
    "enabled": true,
    "failIfUnavailable": true,
    "allowUnsandboxedCommands": false,
    "filesystem": {
      "denyRead": ["~/.ssh", "~/.aws"],
      "allowManagedReadPathsOnly": true
    },
    "network": {
      "allowedDomains": ["registry.npmjs.org", "packages.example.internal"],
      "allowManagedDomainsOnly": true
    }
  },
  "allowManagedHooksOnly": true,
  "allowManagedMcpServersOnly": true,
  "allowedMcpServers": [
    { "serverUrl": "https://mcp.example.internal/*" }
  ],
  "env": {
    "CLAUDE_CODE_ENABLE_TELEMETRY": "1",
    "OTEL_METRICS_EXPORTER": "otlp",
    "OTEL_LOGS_EXPORTER": "otlp",
    "OTEL_EXPORTER_OTLP_PROTOCOL": "grpc",
    "OTEL_EXPORTER_OTLP_ENDPOINT": "https://otel.example.internal:4317"
  },
  "cleanupPeriodDays": 14
}

Some notes on the intent.

  • The Bash(curl *) deny only stops the usual form. What reliably stops exfiltration is the sandbox's network allowlist.
  • github.com is deliberately not in the allowed domains, because a broad domain can become an exfiltration path. If git operations need it, either add it knowing the trade-off, or move specific commands out with excludedCommands (excluded commands run with full access).
  • disableAutoMode, which blocks auto mode, is not included. Decide that as a policy matter and add it here if you block it.
  • Because of failIfUnavailable, deliver a different file to native Windows machines or move those users to WSL2.
  • After delivering it, open /status on one machine and confirm the Setting sources line shows Enterprise managed settings (file).

15. A staged rollout: pilot → policy → managed → CI

Pushing a strict policy to everyone on day one multiplies exception requests and workarounds in personal settings. Four stages are the realistic path.

  1. Pilot: with a small team, work mainly in Manual and acceptEdits, and record which commands, domains and MCP servers are actually needed. Review the real permissions regularly with /permissions.
  2. Policy: from the pilot's record, decide what everyone may do, what needs confirmation and what is forbidden. Also decide here whether to allow auto mode, which MCP servers to approve and where secrets live.
  3. Managed settings: deliver the policy by file or MDM. If you also use server-managed settings, plan around the first-wins behavior and the fact that unmanaged devices can bypass them. Watch that it is in effect with ConfigChange hooks and OpenTelemetry.
  4. CI: finally, lock down unattended runs with --bare, dontAsk, --allowedTools and the Action's trigger rules.

Summary: governing the tool and reviewing what it built are different jobs

Rolling Claude Code out to an organization means deciding how far an agent running with the developer's permissions may go. Write the denies first, put them in managed settings so they can't be overridden, and cover what permission rules can't reach with the sandbox and device management. Above all, don't treat as a boundary anything the docs themselves say is not one.

This is about using the tool safely. Finding vulnerabilities in the app you built with Claude Code is a separate job; if you need the app's authorization or RLS checked, see Security reviews for AI-generated code.

If you want outside help turning your policy into managed settings, sandbox configuration, an MCP allowlist and CI settings, I take enquiries at Claude Code security governance for organizations.

Frequently asked questions

What should we set first when rolling Claude Code out company-wide?
Whether to block bypassPermissions mode, and deny rules for secrets. Set permissions.disableBypassPermissionsMode to "disable" and deliver it in managed settings, and developers can no longer use --dangerously-skip-permissions. Then turn the sandbox on and close off paths it can read by default, such as ~/.ssh, with denyRead. That is the first step the official docs support as of October 2026.
If I add Read(./.env) to permissions.deny, is the secret safe?
Not necessarily. Per the docs, a Read deny applies to the built-in file tools and to commands Claude Code recognizes, such as cat, but not to a Python or Node script that opens the file itself. A .claudeignore file has no effect either. To stop reads at the OS level, enable the sandbox and add sandbox.filesystem.denyRead as well.
Can server-managed settings from the claude.ai admin console govern everything on their own?
No. The docs state that server-managed settings are a client-side control, not a security boundary, and that on unmanaged devices a user can bypass them without admin access. The fetch is also skipped when a session uses Bedrock, Agent Platform (formerly Vertex AI), Foundry or a custom ANTHROPIC_BASE_URL. Design on the assumption that you pair them with MDM or file-based delivery.
Is code sent to Claude Code used for training?
Under commercial terms (Team, Enterprise, API and others), the docs say it is not used for training unless the customer chooses to provide data for model improvement. Standard commercial retention is 30 days. Zero data retention (ZDR) is for qualified Claude for Enterprise accounts, is not included in the standard plan, and cannot be turned on from admin settings.
What is the biggest pitfall when running Claude Code in CI?
claude -p never shows the workspace trust dialog. Without --bare, it runs the hooks in the repository's .claude/settings.json and connects the servers in its .mcp.json, even in a folder you have never trusted. The docs recommend --bare for scripted calls. The project's env block still applies under --bare, though, so also narrow the job's permissions and allowed tools.

References

友田

友田 陽大

Developer of a METI Minister's Award–winning product. With TypeScript + Python + AWS, I deliver SaaS, industry DX, and production-grade generative AI (RAG) end to end — from requirements to infrastructure and operations — single-handedly.

Before everyone on the team gets it

Permissions and governance for using Claude Code safely as an organization

Permission modes, allow / ask / deny rules, managed settings, the sandbox, MCP server allowlists, hooks and CI use — decided as team policy and turned into configuration. Built only on features in the official docs, layered with device management.

Available for both project-based (contract) and advisory engagements. Start with a free 30-minute consult.

Also worth reading