Claude Code admin controls: a complete guide for IT and DevOps teams (2026)
Rama Adi Nugraha
Katelin Teen
Last edited June 9, 2026

Why Claude Code needs admin controls in the first place
When you roll out a coding agent to an engineering org, the risk profile is different from deploying a chat tool. Claude Code can run shell commands, read files across an entire codebase, open pull requests, and - if given the right permissions - reach the internet or write to secrets files. Without controls, two failure modes show up: developers lock into cautious usage and confirm every action manually, or they grant blanket permissions and end up with an agent that can technically do anything.
Neither is what you want. What you actually want is something closer to Group Policy for AI: you define what the tool is allowed to do at the org level, developers get a productive environment within those bounds, and you have audit capability if anything goes wrong.
That's what Claude Code's admin controls are designed to be. Let's walk through each layer of the system.
The four-scope configuration hierarchy
Every Claude Code setting resolves through a precedence stack. From highest to lowest priority:

- Managed - deployed by IT, highest priority, cannot be overridden by anything
- CLI arguments - session-only overrides (
--model sonnet,--permission-mode plan) - Local project (
.claude/settings.local.json) - personal overrides for this repo, gitignored - Shared project (
.claude/settings.json) - team-shared, committed to git - User (
~/.claude/settings.json) - personal global defaults
The managed layer is the ceiling and user settings are the floor. Project settings are where teams standardize tooling. Array-valued settings like permissions.allow merge across scopes rather than replace each other - so an allow rule in user settings stacks with an allow rule in project settings. Scalar values follow winner-take-all from the highest scope that defines them.
One nuance worth knowing: auto mode is ignored when set in project or local settings as of v2.1.142. If you're setting defaultMode: "auto" in a project config and wondering why it has no effect, that's why - it has to come from user or managed settings.
Deploying managed settings
Four delivery mechanisms, all reading the same JSON format:
Server-managed (Teams/Enterprise): Push settings from the admin console in claude.ai. Requires a Claude for Teams or Enterprise plan. Use forceRemoteSettingsRefresh: true to block session startup until the push confirms - useful when your policy update needs to take effect before any developer can continue working.
macOS MDM (Jamf, Kandji, Mosyle): Deploy a configuration profile targeting the com.anthropic.claudecode plist domain. Top-level keys mirror the JSON field names; nested settings use plist dictionaries, arrays use plist arrays. Standard approach for orgs already managing Macs with MDM.
Windows Group Policy / Intune: Write JSON to HKLM\SOFTWARE\Policies\ClaudeCode with a Settings value of type REG_SZ. Deploy via Group Policy Object or an Intune configuration profile. For user-level policy only (when no admin-level source is present), use HKCU\SOFTWARE\Policies\ClaudeCode.
File-based: Drop managed-settings.json at:
- macOS:
/Library/Application Support/ClaudeCode/ - Linux / WSL:
/etc/claude-code/ - Windows:
C:\Program Files\ClaudeCode\
File-based also supports a managed-settings.d/ drop-in directory in the same location. Files sort alphabetically and deep-merge - scalars from later files win, arrays concatenate and deduplicate. Useful if multiple security tools or teams need to contribute separate policy fragments without overwriting each other.
For dynamic policy derived from device posture or a remote compliance service, the policyHelper key points at an executable that computes settings JSON at startup. The binary writes a JSON envelope (with settings under a managedSettings key) to stdout, and Claude Code picks it up before the session starts. Available since v2.1.136.
To verify what's active, run /status inside Claude Code. The Status tab shows a Setting sources line listing every active layer, with the delivery channel in parentheses: Enterprise managed settings (remote), (plist), (HKLM), (file).
Permissions: allow, ask, and deny rules
The permissions system is how you express what Claude can do without asking and what it can't touch at all. Three rule types:
- Allow - Claude runs the tool automatically, no prompt
- Ask - Claude prompts the developer before running (default for most tools)
- Deny - Claude cannot use the tool at all
Rules follow the format Tool or Tool(specifier). A bare deny like "Bash" removes the entire tool from Claude's context so Claude never even tries to use it. A scoped deny like "Bash(rm *)" keeps the tool available but blocks matching calls at runtime.

Evaluation order is always deny first, then ask, then allow - and the first matching rule wins regardless of which scope it came from. A deny in user settings blocks a project-level allow. A managed deny cannot be unlocked by any lower scope.
A practical baseline in .claude/settings.json for a team environment:
{
"permissions": {
"allow": [
"Bash(npm run *)",
"Bash(git commit *)",
"Bash(git diff *)",
"Bash(git log *)",
"Bash(git status)",
"Bash(git stash *)"
],
"deny": [
"Bash(curl *)",
"Bash(wget *)",
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)",
"WebFetch"
]
}
}
This auto-approves common dev commands while blocking network tools and sensitive file reads.
Permission rule patterns to know
Wildcards match across arguments. Bash(npm run *) matches npm run test --watch - the * spans multiple arguments including spaces. Bash(git *) matches git log --oneline --all. A space before * enforces a word boundary: Bash(ls *) matches ls -la but not lsof.
URL-constrained curl is fragile. Bash(curl http://github.com/ *) breaks on curl -X GET http://github.com/... (options before URL), curl https://github.com/... (different protocol), or environment variables holding the URL. For reliable domain restriction, use WebFetch(domain:github.com) for allowed domains and deny Bash network tools entirely. The full explanation is in the permissions reference.
Compound commands split before matching. An allow rule for npm test does not cover npm test && curl evil.com. Claude Code splits on &&, ||, ;, | and checks each subcommand independently.
Read/Edit patterns follow gitignore syntax. Read(./.env) and Read(**/.env) are equivalent - both block any .env at or under the current directory. Use Read(//**/.env) to block .env files anywhere on the filesystem.
Permission modes
Six permission modes change how unmatched tool calls are handled:
| Mode | What it does |
|---|---|
default | Prompt on first use of each tool |
acceptEdits | Auto-approve file edits and safe filesystem commands |
plan | Read-only - no file modifications |
auto | Background safety checks auto-approve aligned calls (research preview) |
dontAsk | Auto-deny unless pre-approved via allow rules |
bypassPermissions | Skip all prompts - for isolated containers/VMs only |
Set defaultMode in settings to lock the starting mode. To prevent bypassPermissions mode from ever activating, add to your managed settings:
{
"permissions": {
"disableBypassPermissionsMode": "disable"
}
}
This closes the --dangerously-skip-permissions flag entirely - developers see an error if they try to use it. Same pattern for auto mode: "disableAutoMode": "disable".
Managed-only settings: the admin-only lockdown controls
Several settings only take effect when deployed via managed settings. Placing them in user or project files has no effect - they're genuinely admin-only:
| Setting | What it enforces |
|---|---|
allowManagedPermissionRulesOnly | Blocks users and project settings from defining any allow/ask/deny rules. Only managed rules apply. |
allowManagedHooksOnly | Only hooks from managed settings or force-enabled plugins run. User and project hooks are blocked. |
allowManagedMcpServersOnly | Only MCP servers in allowedMcpServers from managed settings are used. |
strictKnownMarketplaces | Controls which plugin marketplaces users can add. Empty array blocks all new marketplace additions. |
strictPluginOnlyCustomization | Forces skills, agents, hooks, and/or MCP servers to come from plugins only. |
forceLoginMethod | Restrict login to claudeai accounts or console accounts. |
forceLoginOrgUUID | Require login to a specific Anthropic org UUID. |
requiredMinimumVersion | Block startup if Claude Code version is below this. |
requiredMaximumVersion | Block startup if Claude Code version is above this. |
claudeMd | Inject org-wide instructions that appear in every session. |
channelsEnabled | Enable or disable channels (integrations) org-wide. |
forceRemoteSettingsRefresh | Block startup until managed settings are freshly fetched from the server. |
The combination of allowManagedPermissionRulesOnly: true + allowManagedHooksOnly: true gives you a hard perimeter: no developer can expand what Claude is authorized to do beyond what your managed settings define. Everything runs through IT-approved rules and hooks, nothing more.
Sandbox: OS-level filesystem and network isolation

The sandbox is a separate security layer from permissions. Permissions govern what Claude tries to do. The sandbox enforces what Bash commands can actually reach at the OS level - using macOS's native process isolation (Seatbelt) and Linux seccomp/namespaces to enforce filesystem read/write boundaries and network access rules.
A baseline sandbox config for a developer machine:
{
"sandbox": {
"enabled": true,
"autoAllowBashIfSandboxed": true,
"filesystem": {
"denyRead": [
"~/.aws/credentials",
"~/.ssh/id_rsa",
"~/.ssh/id_ed25519"
],
"allowWrite": ["/tmp/build", "~/.kube"]
},
"network": {
"allowedDomains": [
"github.com",
"*.npmjs.org",
"registry.yarnpkg.com",
"api.anthropic.com"
]
}
}
}
With autoAllowBashIfSandboxed: true (the default), Bash commands that stay within sandbox boundaries run without prompting - the sandbox boundary substitutes for per-command confirmation dialogs. Developers get faster flow; you get enforcement.
Three managed-only sandbox flags are worth knowing for stricter environments:
sandbox.network.allowManagedDomainsOnly: true- only domains in managedallowedDomainsare reachable; project-level additions are ignoredsandbox.filesystem.allowManagedReadPathsOnly: true- only managedfilesystem.allowReadpaths are honoredsandbox.network.allowUnixSockets- required on macOS to allow Docker socket access (/var/run/docker.sock)
The sandbox applies only to Bash commands and their child processes. It does not restrict Claude's built-in Read/Write tools - those are governed by the permission rules above. Use both layers together for defense in depth: permission rules block Claude from attempting unauthorized access, and the sandbox prevents anything that slips through at the OS level.
For container, CI, and WSL environments, see Anthropic's sandboxing guide - the configuration differs in those environments.
Hooks for policy enforcement
Hooks are shell commands, HTTP endpoints, or LLM-evaluated prompts that fire at specific lifecycle points. For admin use, PreToolUse is the key event: it fires before any tool call and can block the call before it happens - even if an allow rule would otherwise permit it.
A shell-based security hook that blocks destructive commands:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/usr/local/bin/claude-security-check.sh",
"args": []
}
]
}
]
}
}
The hook receives the full tool call as JSON on stdin. To block:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "rm -rf blocked by org security policy"
}
}
Exit code 0 with no output means "no decision" - normal permission flow continues. The hook can deny, but silence does not approve.
For HTTP-based centralized policy, use type: "http" to post tool call events to your security service and read the decision from the response. This lets a central team run policy evaluation without distributing shell scripts to every developer machine.
Two other events worth using for governance:
ConfigChange- fires when a settings file changes mid-session. Use this to detect when developers modify their permission rules during a session, and post to your SIEM or Slack for visibility.SessionStart- fires at session open. Good for injecting audit metadata, checking version requirements, or confirming the user is on-network before allowing sensitive operations.
With allowManagedHooksOnly: true in managed settings, only hooks deployed via your managed channel run. Developer-authored hooks in project .claude/settings.json are silently ignored. See the full hooks reference for every available event.
Network and proxy configuration
For environments that route traffic through a corporate proxy, Claude Code reads standard proxy environment variables:
HTTPS_PROXY=https://proxy.example.com:8080
HTTP_PROXY=http://proxy.example.com:8080
NO_PROXY="localhost,192.168.1.1,.internal.example.com"
Set these in the env block of managed settings so they apply to every session without developer configuration:
{
"env": {
"HTTPS_PROXY": "https://proxy.example.com:8080",
"NO_PROXY": "localhost,.internal.example.com"
}
}
For enterprise TLS inspection (CrowdStrike Falcon, Zscaler), Claude Code trusts both its bundled Mozilla CA set and the OS certificate store by default. If your proxy uses a custom CA not in the OS store:
{
"env": {
"NODE_EXTRA_CA_CERTS": "/etc/ssl/certs/enterprise-ca.pem"
}
}
For mutual TLS authentication:
{
"env": {
"CLAUDE_CODE_CLIENT_CERT": "/etc/ssl/certs/claude-client.pem",
"CLAUDE_CODE_CLIENT_KEY": "/etc/ssl/private/claude-client-key.pem"
}
}
Your firewall allowlist needs these URLs at minimum:
| URL | Required for |
|---|---|
api.anthropic.com | Claude API calls |
claude.ai | Claude.ai account auth |
platform.claude.com | Console account auth |
downloads.claude.ai | Plugin downloads and auto-update |
bridge.claudeusercontent.com | Claude in Chrome extension |
raw.githubusercontent.com | Release notes and plugin marketplace |
When deploying through Amazon Bedrock, Google Vertex AI, or Microsoft Foundry, model traffic goes to your cloud provider rather than api.anthropic.com. Set CLAUDE_CODE_USE_BEDROCK=1 (or the equivalent) in the env block and configure ANTHROPIC_BEDROCK_BASE_URL if routing through an LLM gateway. Full cloud provider setup is in Anthropic's third-party integrations guide.
MCP and plugin governance
MCP servers extend Claude with external tool integrations - Jira, Notion, GitHub, internal databases. From a governance standpoint, the risk is developers connecting to untrusted servers or installing unvetted marketplace plugins.
Controlling MCP access via managed settings:
{
"allowedMcpServers": [
{ "serverName": "github" },
{ "serverName": "jira" }
],
"deniedMcpServers": [
{ "serverName": "filesystem" }
],
"allowManagedMcpServersOnly": true
}
With allowManagedMcpServersOnly: true, project .mcp.json files are ignored - only servers in the managed allowlist run. Denylist entries still merge from all scopes, so any scope can block a server even when the allowlist is in effect.
Controlling plugin marketplaces:
{
"strictKnownMarketplaces": [
{ "source": "github", "repo": "acme-corp/approved-claude-plugins" }
],
"blockedMarketplaces": [
{ "source": "github", "repo": "untrusted-org/plugins" }
]
}
strictKnownMarketplaces with a specific list means developers can only add marketplaces on that list. An empty array [] blocks all new marketplace additions entirely. blockedMarketplaces is enforced before network or filesystem operations - blocked sources never touch the disk.
strictPluginOnlyCustomization goes further, requiring all skills, agents, hooks, and MCP servers to come from plugins rather than user or project files:
{
"strictPluginOnlyCustomization": ["skills", "hooks"]
}
Pass true to lock all four surfaces (skills, agents, hooks, MCP) or an array naming just the ones you want locked. This ensures all Claude Code customization in your org flows through approved, distributed plugins rather than ad-hoc developer configuration. See the Claude Code plugin overview for context on what the plugin system enables.
CLAUDE.md as org-wide context
CLAUDE.md files are the instruction layer - they tell Claude what to prioritize, while settings files define what it's allowed to do. The claudeMd managed setting injects org-wide instructions into every session, regardless of project-level CLAUDE.md content:
{
"claudeMd": "Always run `make lint` before committing. Never modify files in /vendor. Security: use parameterized queries, never log credentials. Internal docs at wiki.internal/engineering."
}
Unlike a project-level CLAUDE.md that developers might override locally, managed claudeMd cannot be excluded or ignored. It's a reliable channel for org-wide coding standards, security requirements, and links to internal resources that should be in every session.
For project-specific context, commit CLAUDE.md to the repo root - every collaborator gets the same instructions, and the deploy Claude Code guide covers how to structure these for large monorepos. The claudeMdExcludes setting lets you skip CLAUDE.md files from vendor directories or third-party code that you don't want polluting Claude's context.
Monitoring Claude Code usage
Claude Code exports telemetry via OpenTelemetry, which integrates with any OTLP-compatible stack - Datadog, Honeycomb, Grafana:
{
"env": {
"CLAUDE_CODE_ENABLE_TELEMETRY": "1",
"OTEL_METRICS_EXPORTER": "otlp",
"OTEL_EXPORTER_OTLP_ENDPOINT": "https://your-collector:4318",
"OTEL_RESOURCE_ATTRIBUTES": "service.name=claude-code"
}
}
Available metrics include session activity, tool usage counts by type, model usage, and error rates. For cloud sessions, all operations are logged for compliance automatically.
The ConfigChange hook (covered above) gives real-time signals when settings files change mid-session. Pairing it with your SIEM gives an audit trail of configuration modifications.
For usage reporting at the team level, the usage-analytics-claude-code blog has a full walkthrough of Claude Code usage analytics setup including the available OTLP metrics and what each one tells you.
Teams vs Enterprise: what each plan adds for admins
| Capability | Teams | Enterprise |
|---|---|---|
| Project settings (.claude/settings.json) | Yes | Yes |
| MDM/file-based managed settings | Yes | Yes |
| Server-managed settings (admin console push) | Limited | Full |
| SSO and domain capture | No | Yes |
forceLoginOrgUUID enforcement | No | Yes |
| Managed policy settings org-wide | Partial | Full |
| Remote Control and web session admin controls | Yes | Yes |
| Compliance API access (SOC 2 / ISO 27001) | No | Yes |
| Centralized usage dashboard | Yes | Yes |
| Dedicated support / SLA | No | Yes |
For deploying Claude Code to teams under roughly 50 people, Claude for Teams with file-based or MDM-deployed managed settings usually covers the essentials. Enterprise adds SSO, forceLoginOrgUUID to enforce org membership, and server-managed settings pushed from a central console - the right fit for orgs with Active Directory, Okta, or similar identity management, or with compliance requirements that need Anthropic Trust Center documentation (SOC 2 Type 2, ISO 27001 both certified as of 2026).
The full enterprise Claude Code guide covers procurement, user provisioning, and the SSO configuration steps.
A quick-start managed settings template
Here's a baseline managed-settings.json that covers the essentials for most security-conscious engineering orgs. Deploy it to /Library/Application Support/ClaudeCode/managed-settings.json (macOS), /etc/claude-code/managed-settings.json (Linux), or push it via MDM/Group Policy:
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"permissions": {
"allow": [
"Bash(npm run *)",
"Bash(git commit *)",
"Bash(git diff *)",
"Bash(git log *)",
"Bash(git status)",
"Bash(git stash *)",
"Bash(make *)"
],
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(//home/**/.ssh/*)",
"Read(//root/.ssh/*)"
],
"disableBypassPermissionsMode": "disable"
},
"sandbox": {
"enabled": true,
"autoAllowBashIfSandboxed": true,
"filesystem": {
"denyRead": [
"~/.aws/credentials",
"~/.ssh/id_rsa",
"~/.ssh/id_ed25519",
"~/.ssh/id_ecdsa"
]
},
"network": {
"allowedDomains": [
"github.com",
"*.github.com",
"*.npmjs.org",
"registry.yarnpkg.com",
"api.anthropic.com",
"*.anthropic.com"
]
}
},
"claudeMd": "Follow project CLAUDE.md for coding standards. Never log credentials, tokens, or secrets. Use parameterized queries. Internal docs: wiki.internal/engineering",
"companyAnnouncements": [
"Claude Code enterprise policy applies to all sessions. Questions: security@yourcompany.com"
],
"requiredMinimumVersion": "2.1.100",
"availableModels": ["opus", "sonnet", "haiku"]
}
This template closes --dangerously-skip-permissions, blocks reads of SSH keys and AWS credentials, enables the sandbox with auto-approved sandboxed Bash, restricts outbound network to approved domains, injects a minimal security policy, and pins a minimum version.
Once you've run this for a week and audited what your developers actually need in the allow list, consider adding "allowManagedPermissionRulesOnly": true for the strictest possible lockdown. That setting is left off here intentionally - it should be added only after you're confident the allow list covers your team's real workflow.
The complete settings.json reference covers all ~80 available keys if you need to tune further, and the Claude Code best practices guide covers the developer-side setup that complements this admin layer.
Try eesel.ai

If you're thinking carefully about AI governance for your engineering org, you're probably fielding the same questions in support, ops, and other teams. eesel.ai deploys autonomous AI agents directly inside the tools those teams already use - Zendesk, Freshdesk, Slack, Jira, and 100+ others - with the same approach as Claude Code's permission system: agents operate within clear boundaries you configure, the team stays in control of what they can and can't do, and setup takes minutes from existing knowledge history. No new interface to adopt, no prompt engineering required.
Frequently Asked Questions
How do I stop developers from using --dangerously-skip-permissions in Claude Code?
permissions.disableBypassPermissionsMode to "disable" in your Claude Code managed settings. Because managed settings sit at the top of the precedence stack, this cannot be overridden by any user or project-level configuration - not even command-line arguments. See Anthropic's permissions reference for the full syntax.What's the difference between Claude Code managed settings and project settings?
.claude/settings.json, are committed to git, and apply to every collaborator on the repo, but can be overridden by local or user settings. Use managed settings for compliance policy; use project settings for team conventions.Can I restrict which Claude models developers can use in Claude Code?
availableModels to your managed settings to limit which models users can select via /model or --model - for example ["sonnet", "haiku"] to exclude Opus. Pair it with the model key to set a specific org-wide default. For Bedrock or Vertex deployments, the ANTHROPIC_DEFAULT_SONNET_MODEL env var pins exact model versions.How do I deploy Claude Code admin controls across all developer machines?
com.anthropic.claudecode plist domain), Windows Group Policy or Intune (writing JSON to HKLM\SOFTWARE\Policies\ClaudeCode), or a file dropped at /Library/Application Support/ClaudeCode/managed-settings.json on macOS or /etc/claude-code/managed-settings.json on Linux. All three read the same JSON format. For server-managed settings on Team/Enterprise plans, use the admin console.What does allowManagedPermissionRulesOnly do in Claude Code admin controls?
true in managed settings, it prevents user and project settings from defining any allow, ask, or deny permission rules. Only the rules in your managed settings apply. This is the strictest permission lockdown available - useful when security policy requires that no developer can self-authorize a tool Claude Code hasn't been pre-approved to use.
Article by
Rama Adi Nugraha
Rama is a software engineer at eesel AI with two years of experience writing about B2B SaaS, AI tools, and customer support technology. Based in Bali, Indonesia, he brings a developer's perspective to product comparisons — cutting through marketing copy to what the integrations and APIs actually do.






