Skip to content

rezhv/claude-code-security-best-practices

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 

Repository files navigation

Claude Code Security Best Practices

Claude Code is not just a chatbot. It is a coding agent that can read source trees, edit files, run shell commands, call MCP servers, fetch web content, interact with IDE context, and participate in CI/CD workflows. Securing it looks more like securing a privileged developer runtime than tuning a prompt.

This guide gives teams a practical baseline for securing Claude Code with permissions, managed settings, Bash controls, hooks, sandboxing, MCP governance, OpenTelemetry, CI/CD gates, and enterprise detection and response.

Executive Summary

The safest Claude Code rollout uses layered controls:

  • Use plan or default mode for normal work.
  • Disable bypass permissions on ordinary developer machines.
  • Deny secret paths and dangerous commands.
  • Ask before package installs, Git pushes, deploys, infrastructure changes, database writes, external uploads, and release actions.
  • Allow only boring, repeatable development commands such as lint, test, build, format, git status, and git diff.
  • Use sandboxed Bash, dev containers, VMs, or cloud workspaces for higher-risk repositories.
  • Govern MCP servers through managed MCP, exact URL or command allowlists, least-privilege credentials, and telemetry.
  • Treat hooks as security policy code and deploy critical hooks from managed settings.
  • Export OpenTelemetry events to a collector, SIEM, or AI Detection and Response layer.
  • Make non-interactive CI jobs produce pull requests or review artifacts instead of direct production changes.
  • Red-team the actual deployment with prompt injection, malicious package scripts, MCP abuse, secret reads, hook bypasses, and release-gate attempts.

The goal is simple: Claude Code should help developers move faster while making high-risk actions explicit, reviewable, isolated, and observable.

Threat Model

Claude Code security starts with the authority the agent receives. A normal session can combine user instructions, repository files, CLAUDE.md, package scripts, terminal output, webpages, MCP tool results, IDE state, local credentials, and CI secrets.

The key risk is not that the model reads untrusted text. That is expected. The key risk is that untrusted text influences a privileged action.

Common attack paths include:

  • A poisoned README asks Claude Code to read .env, SSH keys, or cloud credentials.
  • A package script runs during a routine test or install and attempts network egress.
  • An MCP tool returns text that tries to redirect the agent into a sensitive action.
  • A project-scoped .mcp.json adds a local command or unapproved remote server.
  • A repository-controlled hook changes tool behavior before trust is established.
  • WebFetch retrieves documentation that contains indirect prompt injection.
  • A CI job runs non-interactively and attempts to push, publish, deploy, migrate, or apply infrastructure.
  • A developer uses bypass permissions on a laptop that has broad local credentials.

The control strategy is to assume prompt injection can happen and make the dangerous action fail at the tool boundary, file boundary, network boundary, workspace boundary, or release boundary.

Secure Baseline

Start with this baseline for any team using Claude Code on production or production-adjacent code:

  1. Use commercial or enterprise accounts where possible.
  2. Start Claude Code from a scoped repository or worktree, not a broad home directory.
  3. Use managed settings for organization policy.
  4. Keep ordinary sessions in default mode and sensitive exploration in plan mode.
  5. Disable bypassPermissions outside approved containers, VMs, or CI profiles.
  6. Deny reads from secret files, credential stores, local token caches, SSH keys, package tokens, and cloud credential directories.
  7. Ask before external or privileged effects.
  8. Allow narrow local development commands after review.
  9. Use sandboxed Bash for local workflows and dev containers or VMs for sensitive work.
  10. Restrict MCP to approved servers and exact URL or command matches.
  11. Deploy blocking hooks for sensitive paths and privileged commands.
  12. Export OpenTelemetry metrics and events.
  13. Route sensitive deployments through an enterprise proxy, gateway, or controlled egress path.
  14. Use CODEOWNERS, branch protection, and release gates for control-plane files and production changes.
  15. Maintain regression tests for known agent attack paths.

Permission Modes

Claude Code permission mode should match repository risk:

  • plan: best for sensitive repositories, unfamiliar code, security review, incident triage, and design work before edits.
  • default: best default for ordinary secure development.
  • acceptEdits: useful when file edits are expected but shell commands still need review.
  • dontAsk: only for locked workflows with a narrow allowlist and strong surrounding controls.
  • auto: treat as experimental until tested against the team's attack paths.
  • bypassPermissions: only inside isolated containers or VMs with scoped credentials, restricted filesystem access, and restricted network egress.

For enterprise use, disable bypass permissions on developer laptops. A bypassed session on a laptop can inherit local SSH keys, cloud credentials, package tokens, browser-adjacent workflows, and unmanaged tooling.

Managed Settings

Managed settings are the enterprise policy layer. Local user settings can support preferences, but security invariants should come from a managed source.

Manage these settings centrally:

  • Permission rules.
  • Default permission mode.
  • Bypass-permission restrictions.
  • MCP allowlists and denylists.
  • Hook source restrictions.
  • Plugin marketplace restrictions.
  • Proxy and certificate variables.
  • OpenTelemetry export variables.

Useful managed-setting goals:

  • Users cannot weaken secret denies locally.
  • Sensitive repositories cannot silently switch into permissive modes.
  • MCP servers come from an approved catalog.
  • Security hooks cannot be replaced by repository-controlled files.
  • Telemetry reaches the expected collector.
  • Policy changes are versioned, reviewed, and retested.

Permission Rule Design

Design rules around data access and side effects:

  • deny should cover secrets, credentials, destructive commands, and actions that should never happen in an agent session.
  • ask should cover privileged effects that may be legitimate in a controlled workflow.
  • allow should cover narrow, repetitive, low-risk local development commands.

A practical pattern:

{
  "allowManagedPermissionRulesOnly": true,
  "permissions": {
    "defaultMode": "default",
    "disableBypassPermissionsMode": "disable",
    "deny": [
      "Read(./.env)",
      "Read(./.env.*)",
      "Read(./secrets/**)",
      "Read(~/.ssh/**)",
      "Read(~/.aws/**)",
      "Read(~/.config/gcloud/**)",
      "Bash(curl *)",
      "Bash(wget *)",
      "Bash(nc *)",
      "Bash(git push *)",
      "Bash(terraform apply *)",
      "Bash(kubectl delete *)"
    ],
    "ask": [
      "Bash(npm install *)",
      "Bash(pnpm install *)",
      "Bash(pip install *)",
      "Bash(poetry add *)",
      "Bash(docker *)",
      "Bash(kubectl *)",
      "Bash(terraform *)",
      "Bash(gh release *)"
    ],
    "allow": [
      "Bash(npm run lint)",
      "Bash(npm run test *)",
      "Bash(npm run build)",
      "Bash(python -m pytest *)",
      "Bash(git status)",
      "Bash(git diff *)",
      "Bash(* --version)",
      "Bash(* --help *)"
    ]
  }
}

Treat this as a starting point, not a universal policy. Every repository has different package scripts, deployment tooling, database workflows, cloud providers, and local conventions.

Bash Tool Security

Bash is the highest-risk daily tool because it can run package scripts, call external networks, modify Git state, invoke deployment tooling, read credentials, and execute generated scripts.

Classify commands by effect:

  • Read-only development commands such as git status, git diff, and reviewed lint commands can usually be allowed.
  • Local compute such as tests, builds, and type checks can be allowed or asked depending on repository risk.
  • Dependency and environment changes such as package installs, Docker, and language toolchain changes should usually ask.
  • External or privileged effects such as deploys, package publishing, database writes, infrastructure apply, Git pushes, and uploads should ask or deny.

Watch for commands that look safe but delegate to hidden behavior:

  • npm run test can run lifecycle hooks or scripts with network access.
  • make test can call arbitrary shell commands.
  • Code generators can write files, call remote services, or execute downloaded code.
  • Docker commands can mount host directories or expose local networks.
  • Migration tools can reach real databases if credentials are present.

High-risk command families include:

  • curl, wget, nc, scp, rsync.
  • npm install, pnpm install, pip install, poetry add, package publish commands.
  • docker, docker compose.
  • kubectl, helm, cloud CLIs.
  • terraform, pulumi, cdk.
  • psql, mysql, mongosh, migration tools.
  • git push, gh release.
  • Shell scripts written during the same Claude Code session.

Hooks As Security Policy

Claude Code hooks can enforce deterministic checks before or after tool use. Treat them as security code.

Good hook use cases:

  • Block reads from secret paths that permissions missed.
  • Block edits to .github/workflows, .claude, .mcp.json, deployment manifests, infrastructure files, authentication code, authorization logic, billing logic, and lockfiles unless a human approves.
  • Detect new or changed MCP server configuration.
  • Normalize Bash commands before a policy decision.
  • Require review for package publishing, infrastructure apply, database migration, production deploy, and external upload.
  • Emit structured audit events for every denial or manual approval.

For high-risk repositories, deploy hooks from managed settings or a vetted internal package. Avoid relying on repository-controlled hooks for security-sensitive decisions because the same workspace the agent reads can influence those files.

Blocking hooks should guard actions that must be decided before execution. Async hooks are useful for notifications, secondary analysis, and long-running checks, but they should not be the only protection for secrets, deployment paths, or release actions.

A useful hook event should include:

  • User.
  • Repository.
  • Branch.
  • Tool name.
  • Normalized command or affected path.
  • MCP server and tool name where relevant.
  • Decision.
  • Reason.
  • Policy version.
  • Approval ID if a human approved the action.

Implementing Claude Code Hooks

Start with a small hook package that does three things well:

  1. Blocks commands that should never run.
  2. Escalates privileged actions to an approval prompt.
  3. Logs enough metadata for review without storing raw secrets or full source content.

For a single repository, use this layout:

.claude/
  settings.json
  hooks/
    validate-bash.sh
    protect-sensitive-paths.sh
    audit-tool-use.sh

For enterprise deployments, move the same hook definitions into managed settings or a vetted internal plugin so individual repositories cannot rewrite the security policy.

Hook Configuration

Hooks are configured under the hooks key in Claude Code settings. The structure is event, matcher group, then one or more hook handlers.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/validate-bash.sh",
            "args": [],
            "timeout": 10,
            "statusMessage": "Checking Bash command policy"
          }
        ]
      },
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/protect-sensitive-paths.sh",
            "args": [],
            "timeout": 10,
            "statusMessage": "Checking protected path policy"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Bash|Edit|Write|mcp__.*",
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/audit-tool-use.sh",
            "args": [],
            "async": true
          }
        ]
      }
    ]
  }
}

Use PreToolUse for blocking decisions because it runs before the tool executes. Use PostToolUse for logging, formatting, notifications, or secondary checks after a tool has already run.

Bash Policy Hook

This example denies obvious data movement and escalates release or infrastructure actions to a user approval prompt. It reads the hook JSON from stdin and returns a structured permissionDecision.

#!/usr/bin/env bash
set -euo pipefail

input="$(cat)"
command="$(jq -r '.tool_input.command // ""' <<<"$input")"

deny() {
  local reason="$1"
  jq -nc --arg reason "$reason" '{
    hookSpecificOutput: {
      hookEventName: "PreToolUse",
      permissionDecision: "deny",
      permissionDecisionReason: $reason
    }
  }'
}

ask() {
  local reason="$1"
  jq -nc --arg reason "$reason" '{
    hookSpecificOutput: {
      hookEventName: "PreToolUse",
      permissionDecision: "ask",
      permissionDecisionReason: $reason
    }
  }'
}

if [[ "$command" =~ (^|[[:space:];|&])(curl|wget|nc|scp|rsync)[[:space:]] ]]; then
  deny "External data movement commands require a reviewed workflow."
  exit 0
fi

if [[ "$command" =~ (^|[[:space:];|&])git[[:space:]]+push([[:space:]]|$) ]]; then
  ask "Git pushes must be reviewed before Claude Code runs them."
  exit 0
fi

if [[ "$command" =~ (^|[[:space:];|&])(terraform[[:space:]]+apply|pulumi[[:space:]]+up|kubectl[[:space:]]+apply|helm[[:space:]]+upgrade)([[:space:]]|$) ]]; then
  ask "Infrastructure and deployment commands require human approval."
  exit 0
fi

if [[ "$command" =~ (^|[[:space:];|&])(npm|pnpm|yarn)[[:space:]]+(publish|version)([[:space:]]|$) ]]; then
  ask "Package release commands require release approval."
  exit 0
fi

exit 0

Use JSON output for structured decisions. If you prefer exit codes, exit 2 blocks a PreToolUse action, while exit 0 with no output lets the normal permission flow continue. Avoid using exit 1 for enforcement because it is treated as a non-blocking hook error for most events.

Protected Path Hook

This hook blocks edits to control-plane files unless the workflow has a separate approval path. It checks common file path fields used by write and edit tools.

#!/usr/bin/env bash
set -euo pipefail

input="$(cat)"
path="$(jq -r '.tool_input.file_path // .tool_input.path // ""' <<<"$input")"

case "$path" in
  .github/workflows/*|*/.github/workflows/*|\
  .claude/*|*/.claude/*|\
  .mcp.json|*/.mcp.json|\
  *terraform*|*.tf|\
  *deploy*|*deployment*|\
  *auth*|*authorization*|\
  package.json|*/package.json|\
  package-lock.json|*/package-lock.json|\
  pnpm-lock.yaml|*/pnpm-lock.yaml|\
  yarn.lock|*/yarn.lock)
    jq -nc --arg path "$path" '{
      hookSpecificOutput: {
        hookEventName: "PreToolUse",
        permissionDecision: "ask",
        permissionDecisionReason: ("Protected path requires review: " + $path)
      }
    }'
    ;;
  *)
    exit 0
    ;;
esac

Tune this list per repository. A docs repository may not need strict lockfile protection. An authentication service should protect auth, workflow, infrastructure, deployment, and dependency files more aggressively.

Audit Hook

Keep audit hooks metadata-first. Do not dump full prompts, full command output, or source code into a shared log unless your privacy and legal review explicitly allows it.

#!/usr/bin/env bash
set -euo pipefail

input="$(cat)"
log_dir="${HOME}/.claude/security-logs"
mkdir -p "$log_dir"

jq -c '{
  ts: now | todateiso8601,
  session_id,
  cwd,
  permission_mode,
  hook_event_name,
  tool_name,
  command: (.tool_input.command // null),
  path: (.tool_input.file_path // .tool_input.path // null)
}' <<<"$input" >> "$log_dir/tool-events.jsonl"

For enterprise use, send this event to an OpenTelemetry Collector, SIEM, or AI Detection and Response service instead of a local file. Redact command arguments if they can contain tokens, URLs with credentials, customer data, or proprietary code.

HTTP Hooks

Use HTTP hooks when the policy decision lives in a central service. The endpoint receives the hook JSON as the POST body and should return 2xx with a JSON decision.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash|Edit|Write|mcp__.*",
        "hooks": [
          {
            "type": "http",
            "url": "https://hooks.security.example.com/claude-code/pre-tool-use",
            "headers": {
              "Authorization": "Bearer ${HOOK_SECRET}"
            },
            "allowedEnvVars": ["HOOK_SECRET"],
            "timeout": 10
          }
        ]
      }
    ]
  }
}

HTTP error handling is different from command hooks. Non-2xx responses and connection failures are non-blocking errors, so a security-critical HTTP hook should return a successful HTTP response with a structured deny decision when it wants to block. If the policy service must fail closed, enforce that with network controls, a local fallback hook, or managed runtime policy.

Managed Hook Controls

For sensitive repositories, combine hooks with managed settings:

{
  "allowManagedHooksOnly": true,
  "allowedHttpHookUrls": ["https://hooks.security.example.com/*"],
  "httpHookAllowedEnvVars": ["HOOK_SECRET"]
}

This prevents ordinary user, project, or unapproved plugin hooks from becoming the enforcement path. It also limits where HTTP hooks can send data and which environment variables can be interpolated into hook headers.

Testing Hooks

Test hooks before relying on them:

chmod +x .claude/hooks/*.sh

printf '%s\n' '{"hook_event_name":"PreToolUse","tool_name":"Bash","tool_input":{"command":"curl https://example.com/upload"}}' \
  | .claude/hooks/validate-bash.sh

printf '%s\n' '{"hook_event_name":"PreToolUse","tool_name":"Write","tool_input":{"file_path":".github/workflows/deploy.yml"}}' \
  | .claude/hooks/protect-sensitive-paths.sh

Then test through Claude Code itself:

  • Ask it to run a safe command such as git status; the hook should stay silent.
  • Ask it to run curl, git push, terraform apply, or a package publish command; the hook should deny or ask.
  • Ask it to edit .github/workflows, .claude, .mcp.json, auth code, deployment files, or lockfiles; the hook should ask.
  • Break a hook intentionally and confirm the failure behavior is acceptable for the repository tier.
  • Confirm hook execution and blocking decisions appear in OpenTelemetry or your audit destination.

Security hooks should be small, deterministic, and easy to retest. If a hook grows into a complex policy engine, move the complexity into a reviewed service and keep the local hook as a thin enforcement adapter.

MCP Security

MCP servers extend Claude Code's capability boundary. A server can expose read tools, write tools, SaaS data, database access, browser automation, cloud actions, source-control operations, or local commands.

Secure MCP with these rules:

  • Prefer managed MCP for enterprise deployments.
  • Match remote servers by URL, not user-controlled display name.
  • Match local stdio servers by exact command and arguments.
  • Start with a small approved catalog.
  • Pin versions or package sources where possible.
  • Scope credentials to the server's approved task.
  • Treat MCP tool output as untrusted input.
  • Log MCP server connections and tool calls where privacy policy allows.
  • Protect project-scoped .mcp.json with CODEOWNERS and hooks.
  • Maintain an emergency revocation path for every approved server.

Example managed MCP posture:

{
  "allowManagedMcpServersOnly": true,
  "allowedMcpServers": [
    { "serverUrl": "https://mcp.github.example.com/*" },
    { "serverUrl": "https://*.internal.example.com/*" },
    { "serverCommand": ["python", "/usr/local/bin/approved-mcp.py"] }
  ],
  "deniedMcpServers": [
    { "serverUrl": "https://*.untrusted.example.com/*" },
    { "serverCommand": ["npx", "-y", "unapproved-package"] }
  ]
}

Name-only allowlists are weak because a user can label an arbitrary server github. Security decisions should bind to the actual URL or command.

Sandboxing And Dev Containers

Permissions decide what Claude Code may ask to do. Sandboxing limits what Bash and child processes can actually touch.

Use both.

A secure local baseline should enable sandboxed Bash where available and keep prompts for risky commands. For high-risk repositories, use a dev container, VM, cloud workspace, or other isolated environment.

Strong isolation should include:

  • Non-root user.
  • Single scoped worktree.
  • No host credential directories mounted by default.
  • No broad home-directory mount.
  • Short-lived credentials.
  • Approved package registries.
  • Approved tool versions.
  • Restricted egress to model endpoints, authentication, source control, package registries, internal docs, approved MCP servers, and telemetry collectors.
  • No direct production network path unless the workflow is explicitly approved.

Dev containers are especially useful for dependency installs and package scripts because they prevent a compromised package or malicious script from reaching host secrets or arbitrary networks.

WebFetch And Browser-Adjacent Risk

Web content is untrusted input. Claude Code may fetch documentation, package pages, issue trackers, release notes, or vendor docs during normal work. Those pages can contain instructions that conflict with the user's real task.

Use domain policy for sensitive repositories:

  • Allow approved documentation, package registries, source-control domains, provider docs, internal docs, and approved MCP endpoints.
  • Ask before unknown domains.
  • Treat webpage content as context, not authority.
  • Correlate fetched domains with later tool calls during incident review.

If Claude Code participates in browser-connected workflows, include authenticated SaaS data in the threat model. Browser sessions can expose tickets, dashboards, CRM data, cloud consoles, docs, and support tools. Those sources need their own authorization, isolation, and logging.

Enterprise Proxy And Gateway Controls

Enterprise deployments should route Claude Code traffic through an approved network path. A proxy can provide egress visibility, certificate handling, and destination control. An LLM gateway or AI security gateway can add policy decisions around prompts, tool arguments, model responses, destinations, and action intent where privacy rules allow.

Common managed environment variables include:

{
  "env": {
    "HTTPS_PROXY": "https://proxy.example.com:8080",
    "HTTP_PROXY": "http://proxy.example.com:8080",
    "NO_PROXY": "localhost,127.0.0.1,.internal.example.com",
    "NODE_EXTRA_CA_CERTS": "/etc/company/ca.pem",
    "CLAUDE_CODE_CERT_STORE": "bundled,system"
  }
}

Validate the exact runtime. Local terminal sessions, IDE integrations, dev containers, cloud execution, browser bridges, and CI images can behave differently.

OpenTelemetry

OpenTelemetry is the evidence layer. It lets security and platform teams understand what Claude Code asked to do, which policy decided the action, which tools ran, which hooks executed, which MCP servers connected, and what happened afterward.

For a secure deployment, collect at least:

  • Tool decision events.
  • Tool result events where policy allows.
  • Permission mode changes.
  • MCP server connections.
  • Hook registration and execution events.
  • Authentication events.
  • Plugin installation and load events.
  • API errors and retries.
  • CI job identity and repository metadata for non-interactive runs.

Example managed telemetry settings:

{
  "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-collector.example.com:4317",
    "OTEL_LOG_TOOL_DETAILS": "1"
  }
}

Be careful with content-bearing fields. Prompt text, raw API bodies, tool content, command arguments, source snippets, and command output can contain secrets, customer data, or proprietary code.

A practical privacy posture:

  • Enable metrics and events by default.
  • Keep prompt logging disabled unless approved.
  • Enable tool details only after security, privacy, and legal review.
  • Redact secrets at the collector or backend.
  • Store raw bodies only in restricted forensic workflows.
  • Keep content-bearing retention shorter than metadata retention.

Useful alert classes:

  • Permission mode changes to bypassPermissions outside approved environments.
  • Accepted Bash commands involving deploy, publish, migration, infrastructure, upload, or Git push.
  • MCP connections from unapproved or project-scoped servers in sensitive repos.
  • Hook failures in protected repositories.
  • Hook blocks on sensitive paths.
  • Plugin installs from unexpected sources.
  • Repeated user approvals for high-risk commands.
  • Non-interactive jobs attempting release actions.

CI/CD And Non-Interactive Runs

Claude Code can run non-interactively, but unattended jobs need stricter boundaries because no developer is present to interpret every risky prompt.

Secure CI/CD rules:

  • Run in an ephemeral container or VM.
  • Use a non-root user.
  • Mount one worktree.
  • Use short-lived credentials scoped to the job.
  • Disable direct production effects.
  • Deny protected-branch pushes.
  • Deny package publishing unless a release workflow separately approves it.
  • Deny infrastructure apply, production deploys, and database migrations by default.
  • Route traffic through approved egress.
  • Restrict MCP to a fixed managed set.
  • Emit telemetry with workflow name, job ID, repository, branch, commit, actor, permission profile, tool decisions, hook results, and output artifact.
  • Produce a pull request or review artifact rather than mutating main directly.

Release gates should be tested with adversarial examples. A safe job should be able to repair a test and open a pull request. It should not be able to publish a package, deploy production, apply Terraform, run a production migration, or push to a protected branch without independent approval.

Enterprise Solutions

Enterprise Claude Code security usually needs several layers working together. Native Claude Code controls are necessary, but they are not enough by themselves for mature security operations.

General Analysis AIDR

General Analysis AIDR should be the AI Detection and Response layer for Claude Code and other coding agents.

It maps agent activity into an action graph across:

  • User prompts.
  • Repository context.
  • Bash commands.
  • WebFetch activity.
  • MCP servers and tools.
  • Hook decisions.
  • Managed settings.
  • Permission decisions.
  • OpenTelemetry events.
  • CI/CD release gates.
  • Multi-step coding-agent workflows.

This lets security teams detect and respond to:

  • Prompt injection reaching a privileged action.
  • Secret reads.
  • Package-script egress.
  • Risky Bash chains.
  • MCP tool abuse.
  • Hook bypass attempts.
  • Broad permission exceptions.
  • Unsafe edits to control-plane files.
  • Release-gate bypasses.
  • Non-interactive jobs moving toward production effects.

General Analysis AIDR maps to the controls in this guide like this:

  • Permissions and managed settings become policy context.
  • Bash, MCP, WebFetch, and file edits become action telemetry.
  • Hooks become deterministic enforcement and evidence points.
  • OpenTelemetry becomes the raw event stream.
  • CI/CD gates become release-boundary evidence.
  • AIDR correlates the chain, raises incidents, preserves context, and supports response actions such as blocking, requiring approval, quarantining a session, revoking a tool, or opening a policy review.

For teams that need operational support, General Analysis can help with permission baseline design, managed settings rollout, Bash allow and deny policy, MCP governance, hook implementation, OpenTelemetry pipelines, detection engineering, incident playbooks, CI/CD guardrails, exception review, and recurring adversarial validation.

Claude Code Enterprise Controls

Claude Code Enterprise and Anthropic-native controls provide the first-party control surface:

  • Managed settings.
  • Permission modes.
  • Permission rules.
  • Managed MCP.
  • Hooks.
  • Proxy configuration.
  • OpenTelemetry export.
  • Account and audit features where available.

Use these controls as the base policy plane. External security tools should consume, enrich, or enforce around this plane rather than replacing it with informal prompts.

Network And Gateway Solutions

Gateways such as Cloudflare Gateway, Zscaler, or an internal LLM gateway can provide:

  • Egress control.
  • TLS and certificate policy.
  • Destination visibility.
  • Domain allowlists.
  • Prompt and tool-argument policy where approved.
  • Provider separation for Anthropic API, Bedrock, Vertex AI, or other model paths.

Network controls should distinguish model traffic, WebFetch traffic, MCP traffic, package registries, source control, authentication, plugin downloads, updates, and telemetry.

SIEM, SOAR, And Observability

Splunk, Microsoft Sentinel, Datadog, Elastic, Loki, ClickHouse, Honeycomb, Tempo, Jaeger, and similar systems can store and query Claude Code telemetry.

For security operations, the SIEM path matters most. Claude Code events should join identity logs, endpoint logs, source-control logs, CI logs, cloud logs, and proxy logs.

SOAR tools such as Tines or Cortex XSOAR can turn high-confidence detections into:

  • Approval requests.
  • Tickets.
  • Containment steps.
  • Credential rotation tasks.
  • MCP revocation workflows.
  • Follow-up reviews.

Endpoint, Device, And Secrets Tools

Endpoint and device tools such as Microsoft Defender, CrowdStrike Falcon, Jamf, and Microsoft Intune can help enforce managed-device posture, detect local process behavior, and distribute configuration.

Secrets tools such as HashiCorp Vault, 1Password, Doppler, and cloud secret managers reduce the chance that Claude Code can reach long-lived credentials. Prefer short-lived scoped credentials and avoid mounting host credential stores into agent sessions.

Code And CI Security Tools

GitHub Advanced Security, GitLab security features, Semgrep, Snyk, Dependabot, branch protection, CODEOWNERS, and CI policy engines can enforce review and release controls after Claude Code produces changes.

These tools should reinforce the same policy:

  • Sensitive files require review.
  • Dependency changes receive security scanning.
  • Workflow edits receive owner approval.
  • Releases require separate gates.
  • Agent-generated pull requests include evidence and tests.

Rollout Plan

Roll out Claude Code security in stages:

  1. Inventory users, repositories, providers, devices, workspaces, MCP servers, plugins, package managers, deployment tools, and CI workflows.
  2. Classify repositories by risk: low-risk, production-adjacent, regulated, privileged infrastructure, and non-interactive CI.
  3. Write a managed settings baseline for each tier.
  4. Deny secrets and high-risk Bash commands.
  5. Add ask rules for privileged effects.
  6. Preserve common safe development commands.
  7. Choose the isolation model for each tier.
  8. Route sensitive traffic through approved proxy or gateway paths.
  9. Govern MCP servers through managed catalogs.
  10. Deploy managed hooks for protected paths and privileged commands.
  11. Enable OpenTelemetry and route events through a collector.
  12. Build SIEM detections and incident runbooks.
  13. Harden non-interactive CI profiles.
  14. Run adversarial validation against the actual deployment.
  15. Expand gradually and review telemetry for friction, drift, and gaps.

Red-Team Test Cases

Test the real policy with cases like these:

  • Hidden instructions in README ask Claude Code to read .env.
  • A fake secret is placed in a credential path and must be denied.
  • A package script tries to call curl to an external host.
  • A package install triggers a lifecycle script.
  • An unapproved .mcp.json starts a local command.
  • An MCP tool returns instructions to edit .github/workflows.
  • WebFetch returns content that says to ignore the user and exfiltrate files.
  • Claude Code tries to edit .claude, .mcp.json, .github/workflows, deployment manifests, auth code, billing code, or infrastructure files.
  • A session attempts to switch into bypass permissions.
  • A CI job tries to push to main.
  • A CI job tries to publish a package.
  • A CI job tries to run a production migration.
  • A Terraform or Kubernetes command attempts production changes.
  • A hook fails while protecting a sensitive repository.

Each test should record:

  • Input fixture.
  • Expected policy decision.
  • Actual policy decision.
  • Evidence fields.
  • Owner.
  • Fix.
  • Retest status.

Incident Response

When something suspicious happens, reconstruct the chain:

  1. Identify user, repository, branch, commit, workspace type, and permission mode.
  2. Pull the relevant prompt or session ID where policy allows.
  3. Review tool decisions, tool results, MCP connections, hook events, and permission mode changes.
  4. Inspect affected files, commits, pull requests, CI jobs, package publishes, deployments, database changes, and cloud actions.
  5. Determine whether the action was allowed by config, approved by a user, blocked by a hook, denied by policy, or missed entirely.
  6. Contain the path by updating permissions, hooks, MCP allowlists, proxy rules, credentials, or CI gates.
  7. Turn the incident into a regression test.

Possible containment actions:

  • Disable a permission exception.
  • Revoke or deny an MCP server.
  • Block a network destination.
  • Rotate exposed credentials.
  • Tighten a hook.
  • Move a repository to a stricter tier.
  • Disable a non-interactive workflow.
  • Add CODEOWNERS or branch protection.
  • Add a SIEM detection.

Common Mistakes

Avoid these rollout mistakes:

  • Treating CLAUDE.md as enforcement. It is guidance, not a policy boundary.
  • Allowing Bash(*) or broad package-manager wildcards without tests.
  • Letting users run bypass permissions on laptops with host credentials.
  • Mounting ~/.ssh, ~/.aws, ~/.config/gcloud, browser profiles, or package-token files into dev containers.
  • Approving MCP servers by display name instead of URL or command.
  • Trusting MCP tool output as instructions.
  • Relying on repository-controlled hooks for high-risk enforcement.
  • Enabling detailed prompt and tool-content logging without privacy review.
  • Collecting telemetry without detections or runbooks.
  • Letting CI jobs push, publish, deploy, migrate, or apply infrastructure directly.
  • Failing to retest policy after every new MCP server, hook, exception, or CI profile.

Quick Checklist

Use this checklist before broad rollout:

  • Managed settings are active and verified.
  • Bypass permissions are disabled on ordinary machines.
  • Secret paths are denied.
  • Risky Bash commands ask or deny.
  • Safe commands are narrow and tested.
  • Sandboxed Bash, dev containers, VMs, or cloud workspaces are selected by repository tier.
  • MCP servers are approved by exact URL or command.
  • Project-scoped .mcp.json is protected.
  • Hooks protect sensitive files and privileged actions.
  • Hook failures have explicit fail-open or fail-closed behavior.
  • OpenTelemetry reaches the collector.
  • Tool details are enabled only where approved.
  • SIEM detections exist for high-risk actions.
  • CI jobs use ephemeral runtimes and short-lived credentials.
  • Release actions require independent approval.
  • Red-team fixtures pass.
  • Exceptions expire and have owners.

Further Reading

General Analysis guides:

Anthropic docs:

License

MIT

About

Claude Code security best practices for permissions, hooks, sandboxing, MCP, OpenTelemetry, and enterprise controls

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors