Security configuration scanner for Claude Code
Project description
Clauditor
Security configuration scanner for Claude Code.
Clauditor audits your Claude Code settings and repository configuration to detect security misconfigurations.
Table of Contents
- Features
- Built-in Checks
- Installation
- Usage
- Configuration Scopes
- How Findings Work
- Enforcing a Minimum Scope
- Check Format
- Generating a Settings File
- Adding a Custom Check
- Architecture
- License
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-codeflag --base-levelflag 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_valuechecks → sets the key to its required valueconfig_containschecks → builds/merges the required list entries (e.g. multiple checks writing topermissions.denyare merged automatically)config_setchecks → skipped (e.g.forceLoginOrgUUIDrequires your org-specific UUID; reported separately)file_content/file_existschecks → 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
- Create a new YAML file in
checks/following the format above. - Assign the next available
CC###ID. - Run
clauditor list-checksto verify it loads correctly. - Run
clauditor scanto 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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7d98dedecf992aa5030c0d1b21bfe3e3e4381a427d2c33958da0ce9eaaf7d114
|
|
| MD5 |
b4eddc76da414fd2a4f9765e96dcecd2
|
|
| BLAKE2b-256 |
d77740e0fe6d23cca36250a5f228bbad09cc04499c7a96230c43e91c085b22fd
|
Provenance
The following attestation bundles were made for clauditor-0.3.0.tar.gz:
Publisher:
python-publish.yml on gabrielsoltz/clauditor
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
clauditor-0.3.0.tar.gz -
Subject digest:
7d98dedecf992aa5030c0d1b21bfe3e3e4381a427d2c33958da0ce9eaaf7d114 - Sigstore transparency entry: 1089924288
- Sigstore integration time:
-
Permalink:
gabrielsoltz/clauditor@9077b702f4754eef7d1ea40aa7a006feca47245a -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/gabrielsoltz
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@9077b702f4754eef7d1ea40aa7a006feca47245a -
Trigger Event:
release
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0c27904ef2dd0f283efb061a6eea1c6d6270e396ee7fdb13eacf67021a0bc978
|
|
| MD5 |
71f2b77a811acbddb6846568a0e17c01
|
|
| BLAKE2b-256 |
45674294038aaf35061207823e84067d6b1ddab3040ff218d9d704099380f5ca
|
Provenance
The following attestation bundles were made for clauditor-0.3.0-py3-none-any.whl:
Publisher:
python-publish.yml on gabrielsoltz/clauditor
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
clauditor-0.3.0-py3-none-any.whl -
Subject digest:
0c27904ef2dd0f283efb061a6eea1c6d6270e396ee7fdb13eacf67021a0bc978 - Sigstore transparency entry: 1089924338
- Sigstore integration time:
-
Permalink:
gabrielsoltz/clauditor@9077b702f4754eef7d1ea40aa7a006feca47245a -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/gabrielsoltz
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@9077b702f4754eef7d1ea40aa7a006feca47245a -
Trigger Event:
release
-
Statement type: