Skip to content

Enterprise Integration and Security

Claude Code enterprise integration means enforcing one policy on every developer’s sessions through managed settings: a managed-settings.json file, an MDM profile, or server-managed settings from the claude.ai admin console. Managed settings rank above command-line flags, project, and user settings. Deny rules, the sandbox, telemetry, and a managed CLAUDE.md all ship through that one channel.

This page is for the tech lead or platform engineer who has to make that rollout real, and for the CTO who signs off on it. Security approved Claude Code for 200 developers last week. Now you need every session to block .env reads, refuse --dangerously-skip-permissions, report usage to your OpenTelemetry collector, and prove all of that to an auditor. A wiki page asking people to configure it themselves will not survive the first sprint.

What you’ll walk away with from an enterprise Claude Code rollout

Section titled “What you’ll walk away with from an enterprise Claude Code rollout”
  • A decision on how policy reaches machines: server-managed, MDM, or a system file
  • A baseline managed-settings.json you can deploy today, with each lock explained
  • The reason deny rules are not a security boundary, and the sandbox settings that close the gap
  • A verification routine (/status, claude doctor, a canary probe, telemetry checks) that proves the policy is in force without inspecting every laptop
  • A failure-modes list for the ways a fleet-wide policy goes wrong, with a recovery for each

All keys and paths on this page were checked against the Claude Code settings documentation and the installed CLI, version 2.1.283, on 2026-09-26.

How do managed settings reach developer machines?

Section titled “How do managed settings reach developer machines?”

Claude Code reads managed policy from four kinds of source. Pick by how you already manage devices, not by preference:

MechanismWhere the policy livesWhen Claude Code reads itUse it when
Server-managed settingsclaude.ai Admin Settings > Claude Code > Managed settings (Team and Enterprise; Owner or Primary Owner role)At startup, then polled hourlyYou have no MDM, or developers run cloud sessions
MDM or OS policymacOS profile in the com.anthropic.claudecode domain; Windows Settings value under HKLM\SOFTWARE\Policies\ClaudeCodeAt startup, then every 30 minutesYou already run Jamf, Intune, or Group Policy
System filemanaged-settings.json (plus optional managed-settings.d/*.json drop-ins) in the system directoryAt startup, and reloaded when the file changesLinux hosts, build images, machines without MDM
HKCU registryHKCU\SOFTWARE\Policies\ClaudeCodeAt startup, then every 30 minutesFallback only; it is user-writable

The system directories are /Library/Application Support/ClaudeCode/ on macOS, /etc/claude-code/ on Linux and WSL, and C:\Program Files\ClaudeCode\ on Windows. Claude Code does not read the legacy C:\ProgramData\ClaudeCode\ path.

Three trade-offs decide the choice:

  • Tamper resistance. Endpoint-managed policy (MDM or a root-owned file) is protected by the operating system. A developer can edit the local cache of server-managed settings, but the edit lasts only until the next successful fetch.
  • Cloud sessions. A session in an Anthropic-hosted environment never sees a device’s file or MDM profile. If your developers use cloud sessions, the policy must also exist in server-managed settings.
  • Different policies per group. The claude.ai console applies one policy to the whole organization and cannot target a group yet. To give the payments team a stricter policy, ship them a different file or MDM profile.

When several sources exist on one machine, Claude Code uses the highest-ranked one (server-managed, then MDM, then files, then HKCU) and ignores the rest, unless the highest source sets managedSourcesBehavior: "merge". A few locks (for example allowManagedMcpServersOnly, sandbox.network.allowManagedDomainsOnly, forceRemoteSettingsRefresh) and env variables are read from every admin source even then, so a lower MDM profile or file can still set them. merge needs v2.1.242 or later. When a policy seems to be ignored, check this rule first: /status names the source that won.

Inside the settings hierarchy, managed settings sit above everything: managed, then command-line arguments, then .claude/settings.local.json, then .claude/settings.json, then ~/.claude/settings.json. A developer’s --settings file cannot override a managed key. For how the lower layers work, see Claude Code configuration.

The policy below is a starting point for a security-conscious organization. It blocks the obvious secret files, removes the permission-bypass flag, forces the sandbox on, sets a version floor, and sends telemetry to your collector.

{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"permissions": {
"deny": [
"Bash(curl *)",
"Bash(wget *)",
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)",
"Read(**/*.pem)",
"Edit(./.env)",
"Edit(./.env.*)",
"Edit(./secrets/**)"
],
"disableBypassPermissionsMode": "disable"
},
"sandbox": {
"enabled": true,
"failIfUnavailable": true,
"allowUnsandboxedCommands": false,
"network": {
"allowedDomains": ["github.com", "registry.npmjs.org"],
"allowManagedDomainsOnly": true
}
},
"requiredMinimumVersion": "2.1.274",
"env": {
"CLAUDE_CODE_ENABLE_TELEMETRY": "1",
"OTEL_METRICS_EXPORTER": "otlp",
"OTEL_LOGS_EXPORTER": "otlp",
"OTEL_EXPORTER_OTLP_PROTOCOL": "grpc",
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://otel-collector.internal.example.com:4317"
},
"companyAnnouncements": [
"Claude Code runs under the engineering AI policy: go/ai-policy. Secrets belong in Vault, never in .env files."
]
}

What each block does, and what it costs you:

  • permissions.deny stops Claude’s file tools and the recognized Bash file commands (cat, head, sed, tee) from touching secret paths. File rules must use Read(...) or Edit(...). A Write(./.env) rule is accepted but never consulted, and Claude Code prints a startup warning about it (v2.1.210 and later).
  • disableBypassPermissionsMode: "disable" makes Claude Code reject --dangerously-skip-permissions and ignore permissionMode: bypassPermissions in subagent definitions. If your policy forbids classifier-approved actions, also set permissions.disableAutoMode: "disable". Auto mode is the starting mode from v2.1.283 (the latest channel); see permissions and sandboxing.
  • sandbox turns on OS-level isolation for Bash commands. It is off by default (sandbox.enabled defaults to false). failIfUnavailable makes Claude Code exit instead of silently running unsandboxed when a dependency is missing. allowUnsandboxedCommands: false removes the retry-outside-the-sandbox escape hatch. allowManagedDomainsOnly ignores domains that developers add themselves.
  • requiredMinimumVersion stops older binaries from starting. 2.1.274 was the stable release channel on 2026-09-26; raise it as that channel moves.
  • env configures OpenTelemetry. Claude Code has no default OTLP protocol, so set OTEL_EXPORTER_OTLP_PROTOCOL explicitly. A repository’s .claude/settings.json cannot redirect these exporter variables, so the destination stays yours.
  • companyAnnouncements shows one message at startup. With several entries, Claude Code picks one at random per session.

The sandbox uses Seatbelt on macOS and bubblewrap on Linux and WSL2. Native Windows is not supported. On a Windows fleet, failIfUnavailable: true stops Claude Code from starting at all on native Windows, so either deploy it only to macOS and Linux machines or standardize on WSL2 or dev containers.

  1. Keep the policy in a repository. Store managed-settings.json in a platform-team repository with code owners from security. Every change is a reviewed pull request, which is the audit trail an auditor asks for.

  2. Validate the JSON in CI. A managed file that is not valid JSON makes Claude Code refuse to start on every machine it reaches. Add a check such as jq empty managed-settings.json to the pipeline so a stray comma never reaches the fleet.

  3. Deploy to one canary machine. Copy the file to the system directory, or paste the JSON into the admin console for a test organization. Then run /status in a new session. The Setting sources line must show Enterprise managed settings followed by the source, such as (file), (plist), (HKLM), or (remote).

  4. Run the probes. Run claude doctor in a terminal to list any entries Claude Code dropped, then run the canary prompt from the next section. Both must come back clean before you widen the rollout.

  5. Roll out in rings. Push to the pilot group, wait a full poll cycle (30 minutes for MDM, one hour for server-managed), check telemetry for sessions from those machines, and only then push to the next ring.

Which managed-only keys lock developers out?

Section titled “Which managed-only keys lock developers out?”

Most keys can live in any settings file. The keys below take effect only from a managed source. They trade developer flexibility for control, so turn them on deliberately:

KeyEffectTurn it on when
allowManagedPermissionRulesOnlyIgnores allow, ask, and deny rules from user, project, local, and --settings files; ignores --allowedTools; hides the “always allow” choice in promptsYour compliance regime requires one central allowlist. Expect more permission prompts until you ship a good managed allow list
allowManagedHooksOnlyRuns only managed hooks, Agent SDK hooks, and hooks from plugins your managed settings force-enableHooks from repositories are an unacceptable execution risk. It also disables every team’s own hooks, so ship the ones they need centrally
allowManagedMcpServersOnlyOnly managed allowedMcpServers entries count; deniedMcpServers still merges from every sourceYou maintain an approved MCP server list
strictKnownMarketplacesRestricts which plugin marketplaces people can addYou vet plugins. An empty array blocks every marketplace, including the official Anthropic one
disableSideloadFlagsRejects --plugin-dir, --plugin-url, --agents, and --mcp-config at startupYou need the plugin and MCP policy to hold even for command-line flags
forceRemoteSettingsRefreshBlocks startup until server-managed settings are fetched, and exits if the fetch failsYou use server-managed settings and need fail-closed behavior

A common misreading: a managed deny rule never needs allowManagedPermissionRulesOnly to hold. Claude Code evaluates deny first, then ask, then allow, across all sources, so a developer’s "allow": ["Bash(curl *)"] cannot re-enable a managed Bash(curl *) deny. allowManagedPermissionRulesOnly exists to stop developers from adding their own allow rules and pre-approvals, not to protect your denies.

Model governance uses the same channel: availableModels and enforceAvailableModels restrict which models people can pick; deniedModels blocks specific models from v2.1.283 (the latest channel), so on the stable channel rely on availableModels. A managed model sets only a default, and --model still overrides it for a session, so use availableModels when you need a restriction. For which model to allow and what each costs, see the models hub.

Why deny rules are not a security boundary

Section titled “Why deny rules are not a security boundary”

A Bash deny rule matches the command text Claude writes. Bash(curl *) stops curl https://example.com, but not /usr/bin/curl https://example.com or sh -c 'curl https://example.com'. Read and Edit rules cover Claude’s file tools and the Bash commands Claude Code recognizes. They do not cover a Python or Node script that opens the file itself.

So treat the layers as three different jobs:

  1. Deny rules stop what Claude usually attempts, cheaply and with a clear message.
  2. The sandbox enforces filesystem and network limits at the OS level for every process a Bash command starts, whatever the command text says.
  3. A PreToolUse hook inspects the full command with your own logic, for rules the first two cannot express.

If exfiltration is in your threat model, the sandbox with allowManagedDomainsOnly is the control that holds. The deny list is the first filter in front of it. For the full threat model, see the agent threat model.

Ship corporate standards with a managed CLAUDE.md

Section titled “Ship corporate standards with a managed CLAUDE.md”

A managed CLAUDE.md loads before every user and project CLAUDE.md, and developers cannot exclude it. Put it next to the managed settings file:

  • macOS: /Library/Application Support/ClaudeCode/CLAUDE.md
  • Linux and WSL: /etc/claude-code/CLAUDE.md
  • Windows: C:\Program Files\ClaudeCode\CLAUDE.md

If you deliver policy through server-managed settings or MDM, use the claudeMd key instead. It holds the same Markdown as a string, with line breaks written as \n.

Keep the file short and limited to rules that apply to every repository. Every line costs context in every session across the company. Repository-specific conventions belong in each repository’s own CLAUDE.md; see the memory system.

# Engineering rules (managed by Platform)
- Never read, print, or write secrets. Credentials come from Vault via `vault kv get`.
- Run the repository's lint and test commands before you say a task is done, and report their output.
- Database migrations need a reviewer from the owning team. Open a draft PR and stop.
- Do not add a dependency without stating its license and weekly downloads in the PR description.

CLAUDE.md is guidance, not enforcement. Claude follows it most of the time. Anything that must hold every time belongs in a deny rule, the sandbox, or a hook.

Copy-paste prompts for managing the policy

Section titled “Copy-paste prompts for managing the policy”

Run the probe in an interactive session in a throwaway repository that contains a dummy .env file. Steps 1 to 3 must be blocked. Step 3 is the one that proves the sandbox, not the deny list, is doing the work. Step 4 must succeed because github.com is on the allowlist. It is a read-only call that writes nothing to disk, so a filesystem write limit cannot turn it into a false FAIL the way a package-manager cache write can. If Claude Code asks you to approve step 3, approve it: the test is whether the sandbox then blocks the connection. If step 3 succeeds, the sandbox is not running on that machine.

Nobody can inspect 200 laptops. Verification comes from four signals that scale:

SignalWhat it provesWho checks it
/status shows Enterprise managed settings (<source>)The machine selected the managed source you shipped. A Skipped sources line names any source that lost to a higher-ranked one (v2.1.242 and later)Platform team, on canaries and on any support ticket
claude doctorWhich entries Claude Code dropped as invalid, and whether server-managed settings were fetched. Its Organization policy line (v2.1.261 and later) shows whether organization-wide admin settings, such as Remote Control and cloud sessions, reached the machinePlatform team
The canary probe aboveDeny rules and the sandbox block what the policy says they blockSecurity, after every policy change
Telemetryclaude_code.session.count arrives from each machine; a session with no metrics means telemetry, and possibly the whole policy, did not applyPlatform team, weekly

Telemetry also gives you claude_code.token.usage, claude_code.cost.usage, claude_code.lines_of_code.count, claude_code.commit.count, claude_code.pull_request.count, and claude_code.code_edit_tool.decision. Prompt text, tool arguments, and tool output are not logged unless you set OTEL_LOG_USER_PROMPTS, OTEL_LOG_TOOL_DETAILS, or OTEL_LOG_TOOL_CONTENT. Decide with your privacy officer before you turn any of them on. For dashboards and alerts, see Claude Code monitoring and cost control.

Sign-off splits cleanly: security owns the deny list, sandbox allowlist, and MCP list; the platform team owns delivery, the version floor, and telemetry; engineering leadership owns the managed CLAUDE.md. The operating model page covers who owns what in more depth.

  1. Pilot, 5 to 10 developers. Deploy the baseline policy without allowManagedPermissionRulesOnly or allowManagedHooksOnly. Have the pilot write each repository’s CLAUDE.md and shared skills in .claude/skills/, and log every permission prompt that felt wrong. Design the pilot and its exit criteria with the pilot design guide.

  2. Team, 20 to 50 developers. Add the managed allow list the pilot proved safe, turn on the MCP allowlist, and confirm telemetry arrives from every machine. Set per-team spend alerts on claude_code.cost.usage. Anthropic’s cost guide puts a typical enterprise deployment at “around $13 per developer per active day and $150-250 per developer per month” (Anthropic, Claude Code costs page, checked 2026-09-26); start your alert thresholds there and replace them with your pilot’s own numbers.

  3. Organization, 100 or more developers. Turn on the locks your compliance regime needs, raise requiredMinimumVersion on a schedule, and add Claude Code to onboarding so a new laptop gets the policy on day one. Publish an AI usage policy that matches what the settings enforce.

/status shows no managed source. Claude Code found no source with a policy key. Check the path for the operating system: it is /Library/Application Support/ClaudeCode/, not ~/Library/.... Also check that the file contains a policy key and not only control keys such as managedSourcesBehavior. For server-managed settings, run claude doctor and read the fetch result.

/status names a different source than the one you shipped. A higher-ranked source is present, for example an old MDM profile shadowing your new file. Read Skipped sources, then remove the stale source or set managedSourcesBehavior: "merge" in the highest one.

Claude Code refuses to start on every machine. A managed file, drop-in, plist, or HKLM value is not valid JSON. Roll back the last policy commit through the same tooling, then add the CI JSON check from the deployment steps.

Cloud sessions ignore the policy. Anthropic-hosted sessions never read device files or MDM profiles. Mirror the policy in server-managed settings.

A deny rule is ignored with a startup warning. It is a Write(...), NotebookEdit(...), or MultiEdit(...) path rule. Rewrite it as Edit(...), and use Read(...) in place of Glob(...).

Commands run unsandboxed on Linux. bubblewrap or socat is missing, and without failIfUnavailable Claude Code only warns. Install the packages through your configuration management, and keep failIfUnavailable: true so a missing dependency fails loudly.

Old versions keep running after you raise the floor. requiredMinimumVersion is checked at startup and does not end a running session. Announce the change, and expect long-lived sessions to lag until developers restart.

Telemetry never arrives. Usually a firewall blocks port 4317 to the collector, or OTEL_EXPORTER_OTLP_PROTOCOL is missing. Switch to http/protobuf on port 4318 if gRPC is blocked.

A developer with local admin rights edited the file. Managed settings bind the Claude Code client, not the machine owner. Have MDM redeploy the file or profile on a schedule, and remember that a developer calling the API from another tool is outside this policy entirely.

Where to go next with enterprise Claude Code

Section titled “Where to go next with enterprise Claude Code”