Skip to main content

Security configuration scanner for Claude Code

Project description

Clauditor

Clauditor

Security configuration scanner for Claude Code.

Tests Security Lint PyPI Python License

Clauditor audits your Claude Code settings and repository configuration to detect security misconfigurations.


Table of Contents


Features

  • Scans all Claude Code configuration scopes: user, project, local, and managed
  • Checks repository-level files (CODEOWNERS, CLAUDE.md, etc.)
  • Checks are defined as YAML files — easy to read, extend, and contribute
  • Each check maps to a concrete threat, severity, and remediation
  • Scan a local path, a remote git URL, or just the current directory
  • Rich terminal output with optional verbose remediation steps
  • CI-friendly --exit-code flag
  • --base-level flag to enforce a minimum required scope

Built-in Checks

ID Name Severity Scope Threat Mitigated
CC001 CODEOWNERS Enforcement for Claude Code Paths HIGH repository Supply chain attacks via unreviewed config changes
CC002 Disable Bypass Permissions Mode CRITICAL user, project, local, managed Unrestricted tool execution via --dangerously-skip-permissions
CC003 Enforce Managed Permission Rules Only LOW managed User/project permission rules bypassing IT policy
CC004 Deny Sensitive File Operations LOW managed Credential theft via .env, secrets/**, credential files
CC005 Disable Auto-Approval of Project MCP Servers LOW managed Supply chain attacks via malicious .mcp.json
CC006 Enforce Managed Hooks Only LOW managed Arbitrary code execution via project/user hooks
CC007 Force SSO Login Method MEDIUM managed Unmanaged personal accounts bypassing corporate identity
CC008 Require SSO Organization UUID MEDIUM managed Cross-tenant auth or unbound SSO enforcement
CC009 Require Approval for Network-Fetching Tools LOW managed Unlogged outbound requests via curl/wget
CC010 Enable Bash Sandboxing LOW user, project, local, managed Unrestricted shell access bypassing permission limits
CC011 Restrict Sandbox Filesystem Write Paths MEDIUM user, project, local, managed Writes to /etc, /usr, ~/.ssh, ~/.aws enabling persistence
CC012 Restrict Sandbox Filesystem Read Paths MEDIUM user, project, local, managed Exfiltration of SSH keys, cloud credentials, .env secrets
CC013 Block Sandbox Escape Hatch HIGH user, project, local, managed Silent sandbox bypass via auto-retry of failed commands
CC014 Block Weaker Nested Sandbox Mode HIGH user, project, local, managed Weakened bubblewrap isolation on Linux/WSL2
CC015 Block Unrestricted Unix Socket Access in Sandbox HIGH user, project, local, managed Docker socket access granting root-equivalent host control
CC016 Enforce Managed Network Domain Allowlist HIGH managed Project settings bypassing IT network egress controls
CC017 Enforce Managed MCP Servers Only HIGH managed Unauthorized MCP server injection via project/user settings
CC018 Restrict Plugin Marketplace Sources CRITICAL managed Supply chain attacks via malicious marketplace plugins
CC019 Disable Remote Sessions HIGH managed Remote takeover of local execution context via web interface
CC020 Enforce Stable Update Channel MEDIUM managed Unreviewed Claude Code releases reaching developer fleet
CC021 Enforce Short Transcript Retention Period MEDIUM user, project, managed Credential-containing session transcripts accumulating on disk
CC022 Block bypassPermissions as Default Mode CRITICAL managed All permission checks disabled globally for every session
CC023 Restrict HTTP Hook Destination URLs HIGH managed Session data exfiltration via unrestricted HTTP hook endpoints
CC024 Restrict Environment Variables Exposed to HTTP Hooks HIGH managed Credential exfiltration via hook request headers
CC025 Deny Direct Read Access to .env and Secrets Files HIGH managed, project .env reads bypassing .claudeignore restrictions
CC026 Deny Filesystem MCP Server HIGH managed, project Filesystem MCP server bypassing permissions.deny rules
CC027 Block apiKeyHelper in Project and Local Scope HIGH project, local Arbitrary shell execution on session start via committed config
CC028 Block otelHeadersHelper in Project and Local Scope HIGH project, local Persistent periodic shell execution via committed config
CC029 Block Unrestricted Bash in Project Permissions Allow List HIGH project Supply chain RCE via allow-all Bash rule in committed settings
CC030 CODEOWNERS Enforcement for .mcp.json HIGH repository Unreviewed MCP server additions with full session authority
CC031 Configure Sandbox Network Domain Allowlist HIGH managed, project Unrestricted sandbox network egress enabling data exfiltration
CC032 Disable Filesystem Server in MCP JSON Servers MEDIUM user, project, managed Defense-in-depth block on high-risk filesystem MCP server
CC033 Block Unrestricted WebFetch in Permissions Allow List MEDIUM project, managed Prompt injection via unrestricted web content fetching

Installation

The recommended way to install Clauditor is with pipx, which installs CLI tools in isolated environments and makes them available system-wide:

pipx install clauditor

Install pipx if you don't have it yet:

# macOS
brew install pipx && pipx ensurepath

# Linux / WSL
python3 -m pip install --user pipx && pipx ensurepath

Alternative — pip inside a virtual environment:

python3 -m venv .venv
source .venv/bin/activate
pip install clauditor

From source:

git clone https://github.com/gabrielsoltz/clauditor
cd clauditor
python3.13 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"

Usage

# Scan current directory (project + user scope settings)
clauditor scan

# Scan a specific local repository
clauditor scan --path /path/to/repo

# Clone and scan a remote repository
clauditor scan --url https://github.com/org/repo

# Filter by severity
clauditor scan --severity CRITICAL,HIGH

# Show remediation steps for failed checks
clauditor scan -v

# Exit with code 1 if any failures found (for CI)
clauditor scan --exit-code

# List all available checks
clauditor list-checks

# Generate a settings file (user scope by default)
clauditor generate

# Generate a managed settings file covering all checks
clauditor generate --scope managed -o managed-settings.json

Configuration Scopes

Claude Code reads settings from multiple locations. Each location is a scope. Understanding scopes is key to understanding Clauditor's output.

See the official Claude Code settings documentation for details.

The four Claude Code scopes

Column Scope File Who it applies to
M managed System path (platform-specific) Everyone on the machine; deployed by IT
L local .claude/settings.local.json You, in this repo only; gitignored
P project .claude/settings.json All collaborators; committed to git
U user ~/.claude/settings.json You, across all projects

Scope precedence

When the same setting exists in multiple scopes, Claude Code applies the highest-precedence scope:

managed  >  local  >  project  >  user
(highest)                        (lowest)

managed is set by an administrator and cannot be overridden by anyone. local takes precedence over project, which means a developer can use .claude/settings.local.json to override what the team committed in .claude/settings.json.

Repository scope (Clauditor extension)

Column Scope What it checks
R repository VCS governance files: CODEOWNERS, workflow configs, etc.

repository is not a Claude Code scope — it's Clauditor's own concept for checks that look at repository governance files rather than Claude Code JSON settings. It has no precedence relationship with the config scopes above.


How Findings Work

Per-scope icons in the output table

Each scope column shows one icon:

Icon Meaning
Setting is correctly configured at this scope
Setting is present but has the wrong value
Covered — a higher-precedence scope already passes, so this scope is irrelevant
Skipped — the settings file for this scope was not found or is empty
· N/A — this check does not apply to this scope

How the effective (overall) status is decided

The effective status in the Status column is determined by the highest-precedence scope that is not skipped:

  • If managed=PASS → effective is PASS, regardless of lower scopes. All lower scopes show (covered).
  • If managed=FAIL → effective is FAIL, regardless of lower scopes. A wrong value at the top level locks everyone.
  • If managed=–, local=–, project=PASS → effective is PASS, user shows (covered).
  • If all config scopes are (not configured anywhere) → effective is FAIL. A missing setting is not a passing setting.

Scenario examples

Scenario A — Enforced via managed settings (best)

M L P U Status
✔ PASS

Setting is in managed. Everyone on the machine is protected. Lower scopes are irrelevant.

Scenario D — Nobody has it set

M L P U Status
✘ FAIL

The setting is not configured anywhere. This is always FAIL — a missing setting provides no protection.


Enforcing a Minimum Scope

By default, Clauditor marks a check as PASS if the setting is correctly configured at any scope. However, you may want to require enforcement at a specific level.

# Require the setting to exist at project scope or above (for team-wide enforcement)
clauditor scan --base-level project

# Require enterprise-wide enforcement through managed settings only
clauditor scan --base-level managed

With --base-level project, a setting that is only present in the user scope becomes FAIL — the setting is only personal and doesn't protect the team.

--base-level What passes
user (default) Any scope: user, project, local, or managed
project Must be in project, local, or managed (not just user)
local Must be in local or managed (not just project/user)
managed Only managed qualifies

Check Format

Checks live in the checks/ directory as YAML files. Example structure:

id: CC001
name: CODEOWNERS Enforcement for Claude Code Paths
description: >
  Ensures that /.claude/ and /CLAUDE.md have CODEOWNERS entries
  requiring security team review.

scope:
  - repository

severity: HIGH  # CRITICAL | HIGH | MEDIUM | LOW | INFO

threat: >
  Without CODEOWNERS enforcement, contributors can silently modify
  Claude Code settings, hooks, or instructions without security review...

category: access_control

check_type: file_content  # config_value | config_contains | config_set | file_content | file_exists

check_config:
  search_paths:
    - CODEOWNERS
    - .github/CODEOWNERS
  required_entries:
    - pattern: "/.claude/"
      owner: "@security-team"
    - pattern: "/CLAUDE.md"
      owner: "@security-team"

remediation: >
  Add to CODEOWNERS:
    /.claude/ @security-team
    /CLAUDE.md @security-team

fix_available: true

references:
  - https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
  - https://code.claude.com/docs/en/settings

Check Types

check_type check_config keys Description
config_value key, expected_value Verifies a key/value in a JSON settings file
config_contains key, required_values Verifies a list key contains all required values
config_set key Verifies a key is present and non-empty (any truthy value)
file_content search_paths, required_entries Verifies required lines exist in a file
file_exists paths, any_of Verifies file(s) exist in the repository

Generating a Settings File

clauditor generate produces a ready-to-deploy JSON settings file containing all the values needed to remediate the applicable checks.

clauditor generate                          # All checks → user settings
clauditor generate --scope managed         # Full managed settings file
clauditor generate --scope project         # Project-level (.claude/settings.json)
clauditor generate --severity CRITICAL     # Only critical checks
clauditor generate --checks CC002,CC010    # Specific checks only
clauditor generate --scope managed -o managed-settings.json

Scope controls which checks are included:

--scope Checks included
user (default) user-scoped checks only
project project + user checks
local local + project + user checks
managed All config checks: managed + local + project + user

What gets generated:

  • config_value checks → sets the key to its required value
  • config_contains checks → builds/merges the required list entries (e.g. multiple checks writing to permissions.deny are merged automatically)
  • config_set checks → skipped (e.g. forceLoginOrgUUID requires your org-specific UUID; reported separately)
  • file_content / file_exists checks → skipped (repository governance files, not settings values)

Example output (clauditor generate --scope managed):

{
  "disableBypassPermissionsMode": "disable",
  "allowManagedPermissionRulesOnly": true,
  "permissions": {
    "deny": [
      "Read(.env)",
      "Read(**/.env)",
      "Read(secrets/**)",
      "Write(secrets/**)",
      "Read(**/credentials)",
      "Bash(curl:*)",
      "Bash(wget:*)"
    ]
  },
  "enableAllProjectMcpServers": false,
  "allowManagedHooksOnly": true,
  "forceLoginMethod": "claudeai",
  "sandbox": {
    "enabled": true,
    "filesystem": {
      "denyWrite": ["/etc", "/usr", "~/.ssh", "~/.aws"],
      "denyRead": ["~/.ssh", "~/.aws/credentials", ".env", "**/.env"]
    }
  }
}

Adding a Custom Check

  1. Create a new YAML file in checks/ following the format above.
  2. Assign the next available CC### ID.
  3. Run clauditor list-checks to verify it loads correctly.
  4. Run clauditor scan to see results.

No code changes required.


Architecture

clauditor/
├── cli.py              # Typer CLI entry point
├── scanner.py          # Orchestrates checks against providers
├── loader.py           # YAML check loader with Pydantic validation
├── aggregator.py       # Scope precedence + base_level logic
├── generator.py        # Settings file generator
├── models/
│   ├── check.py        # Check, Scope, Severity, CheckType models
│   └── finding.py      # Finding, FindingStatus models
├── providers/
│   ├── base.py         # BaseProvider interface
│   ├── config_provider.py   # User, Project, Local, Managed providers
│   └── repository_provider.py  # Repository file provider + git clone
├── checkers/
│   ├── config_value.py     # Logic for config_value checks
│   ├── config_contains.py  # Logic for config_contains checks
│   ├── config_set.py       # Logic for config_set checks
│   ├── file_content.py     # Logic for file_content checks
│   └── file_exists.py      # Logic for file_exists checks
└── output/
    └── console.py       # Rich terminal output

checks/                  # YAML check definitions

License

Apache 2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

clauditor-0.3.0.tar.gz (42.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

clauditor-0.3.0-py3-none-any.whl (72.3 kB view details)

Uploaded Python 3

File details

Details for the file clauditor-0.3.0.tar.gz.

File metadata

  • Download URL: clauditor-0.3.0.tar.gz
  • Upload date:
  • Size: 42.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for clauditor-0.3.0.tar.gz
Algorithm Hash digest
SHA256 7d98dedecf992aa5030c0d1b21bfe3e3e4381a427d2c33958da0ce9eaaf7d114
MD5 b4eddc76da414fd2a4f9765e96dcecd2
BLAKE2b-256 d77740e0fe6d23cca36250a5f228bbad09cc04499c7a96230c43e91c085b22fd

See more details on using hashes here.

Provenance

The following attestation bundles were made for clauditor-0.3.0.tar.gz:

Publisher: python-publish.yml on gabrielsoltz/clauditor

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file clauditor-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: clauditor-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 72.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for clauditor-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0c27904ef2dd0f283efb061a6eea1c6d6270e396ee7fdb13eacf67021a0bc978
MD5 71f2b77a811acbddb6846568a0e17c01
BLAKE2b-256 45674294038aaf35061207823e84067d6b1ddab3040ff218d9d704099380f5ca

See more details on using hashes here.

Provenance

The following attestation bundles were made for clauditor-0.3.0-py3-none-any.whl:

Publisher: python-publish.yml on gabrielsoltz/clauditor

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page