Many companies are adopting Anthropic’s Claude Code as their AI Companion. Installing Claude Code CLI is straightforward. But as easy as it is, it also provides by default unrestricted access to the entire filesystem. This is a first approach to implementing some secure by default configurations and guardrails to limit what actions Claude can perform at the macOS level. Despite the fact I’m including useful considerations for companies deploying Claude Code CLI for the first time, this guide is intended for personal usage.

Note on personal usage. I strongly recommend to run claude code CLI using devcontainers to reduce attack surface

1. Understanding configuration scope

There are primarily 4 layers based on 3 different files. The files themselves accept the same settings, and have the same structure. What differentiates them is precedence (and location). 

Layer Configuration File Precedence Enforced Purpose
1 /Library/Application Support/ClaudeCode/managed-settings.json Highest Yes Organization-wide enforced policies
2 ~/.claude/settings.json Below Layer 1 No Personal defaults across all projects
3 .claude/settings.json Below Layers 1–2 No Project-specific configuration
4 .claude/settings.local.json Lowest No User-specific settings for a single project

2. Base Security Guardrails: Sandbox

2.1 Anthropic Sandbox

The sandbox restricts what Claude can read, write, and reach on the network, preventing it from accessing sensitive files or exfiltrating data even if manipulated. It is enforced at the OS level, in macOS using SeatBelt, below Claude’s own judgment layer.

  • When enabled it can restrict:
    • Command execution
    • Directory reading/listing
    • Network access
    • Access to specific Marketplaces only
    • Access to specific MCPs only

It is recommended to enable the sandbox in the above mentioned [[#1. Understanding configuration scope]], the managed-settings.json file and deploy this file globally using MDM tools.

An example version of this file could look like

{
  "permissions": {
    "defaultMode": "default",
    "deny": [
      "Bash(osascript *)",
      "Bash(osacompile *)",
      "Bash(security *)",
      "Bash(screencapture *)",
      "Bash(tclsh *)",
      "Bash(launchctl *)",
    ],
    "disableBypassPermissionsMode": "disable",
    "allowManagedPermissionRulesOnly": true
  },
  "sandbox": {
    "enabled": true,
    "allowUnsandboxedCommands": false,
    "filesystem": {
      "denyRead": [
        "~/.ssh",
        "~/.gnupg",
        "**/.env",
        "**/.env.*",
        "~/.bashrc",
   
      ],
      "allowWrite": [
    
      ],
      "denyWrite": [
        "/etc/cron*",
        "/etc/periodic/**",
        "/var/spool/cron/**",
        "~/Library/LaunchAgents/**",
        "~/Library/LaunchDaemons/**",
        "/Library/LaunchAgents/**",
        "/Library/LaunchDaemons/**",
        "/System/Library/LaunchAgents/**",
        "/System/Library/LaunchDaemons/**",
      ]
    },
    "network": {
      "allowedDomains": [
        "localhost",
        "127.0.0.1",
        "::1",
        "*.your_safe_domain.com",
        "*.anthropic.com",
      ],
      "allowManagedDomainsOnly": true,
    }
  },
  "allowManagedMcpServersOnly": false,
  "extraKnownMarketplaces": {
    "{your_trusted_mkt}": {
      "source": {
        "source": "url",
        "url": "https://{your_trusted_mkt}.com/claude-code/marketplace.json"
      }
    }
  },
  "strictKnownMarketplaces": [
    {
      "source": "github",
      "repo": "anthropics/claude-plugins-official"
    },
    {
      "source": "url",
      "url": "https://{your_trusted_mkt}.com/claude-code/marketplace.json"
    }
  ],
  "disableAllHooks": false
}

Claude use cases vary from individual and organizations, so you will need to find the right set of settings that most accurately captures your use case

 One considerations on the file above is that It is set on Blocklist mode, meaning that what it is not explicitly deny it is allowed. The other mode, allowlist, would be safer but it will require a significant operational work for a company environment (recommended for personal usage)

2.2 Permission Rules

I introduced here commands which usage could be risky. Inspiration came from Living off the Land binaries for macOS

 Rationale behind some of the commands I choose to introduce in the file (you can do this process as detail as you needed).

Command Risk
osascript / osacompile Arbitrary code execution via AppleScript
security Keychain access and credential extraction
screencapture Screen capture and potential data exfiltration
swift / tclsh Alternative code execution paths that bypass python/bash restrictions
nscurl Alternative HTTP client that can bypass curl deny rules
launchctl Persistence through Launch Agents and Launch Daemons
dscl / dscacheutil Local user and directory service enumeration
sysadminctl / systemsetup Account management and system configuration changes
streamzip Archive creation that may facilitate file exfiltration
  • denyWrite. Basically restricting write operations to common directories used for establishing persistence

2.23 Network control layers in Claude

First, lets understand how Claude CLI performs network calls. There are primarily two ways:

  • WebFetch. It is the native Claude Code CLI tool for retrieving web pages and docs
  • Subprocess commands. Any subprocess command, like curl/wget, run via bash
  • WebSearch (not covered here)

The network section on the managed-settings file has impact only on the subprocess commands egress request.

For instance, let’s say that this is my network section

"network": {
        "allowedDomains": [
          "github.com",
          "anthropic.com"
        ]
      }

If I run within Claude Code CLI:

!curl bitbucket.com

it will be blocked as curl is a subprocess of bash.

Now if I ask Claude to run it

Access gitlab.com

it will work, as this request is handled by the webFetch Tool. For blocking webfetch add it in the permissions section

{
  "permissions": {
    "deny": [
      "WebFetch",
        ]
  }
}

or, with more granularity, allow only domain1 and domain2 as follows

{
  "permissions": {
    "allow": [
      "WebFetch(domain:domain1.com)",
      "WebFetch(domain:domain2.com)"
    ],
    "deny": [
      "WebFetch"
    ]
  }
}

As a final note, for non-personal environments, it is recommended to pair this strategy with independent Egress filtering controls (at the host layer)

3 Additional Recommendation for Enterprise deployments

3.1 Identify and block all non company claude code instances

Once Claude Code is fully deployed company-wide, you might want to ensure that there are no Code instances that are not authenticated through SSO, meaning that they are running on non-company accounts. The risks are:

  • Potential data exfiltration 
  • Endpoint compromise (unrestricted Claude code CLI)
  • Logging and monitoring failures (no visibility of what it is being done)

To identify who is running a non-company Claude code account you can inspect the following file:

cat ~/.claude.json | jq '.oauthAccount'
{
  "accountUuid": ,
  "emailAddress": ,
  "organizationUuid": ,
  "hasExtraUsageEnabled": ,
  "billingType": ,
  "subscriptionCreatedAt": ,
  "displayName": ,
  "organizationRole": ,
  "workspaceRole": null,
  "organizationName":
}

3.2 Logging, and Monitoring

Claude Code can be configured to use an OpenTelemetry (OTEL) to ship both logs and metrics

{
  "env": {
    "CLAUDE_CODE_ENABLE_TELEMETRY": "1",
    "OTEL_METRICS_EXPORTER": "otlp",
    "OTEL_LOGS_EXPORTER": "otlp",
    "OTEL_EXPORTER_OTLP_PROTOCOL": "grpc",
    "OTEL_EXPORTER_OTLP_ENDPOINT": "http://collector.example.com:4317",
    "OTEL_EXPORTER_OTLP_HEADERS": "Authorization=Bearer example-token"
  }
}

3.3 Deployment phases and considerations

Consider

  • Deploying to test group first
  • Gathering feedback, analyze security gaps, issues and fine-tune the managed-settings file
  • Tracking the changed to the managed-settings file using git
  • Building a CICD pipeline