> ## Documentation Index
> Fetch the complete documentation index at: https://ccsafetynet.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Secret protection reference

> Complete catalog of CC Safety Net's built-in secret-protection rules: sensitive basenames, protected home directories, key-file variants, credential extensions, the two coding CLI tiers, deny paths, and every exemption.

Secret protection blocks reads and writes of credential-bearing files — SSH keys, `.env` files, cloud credential stores, coding-agent auth tokens — before command analysis runs. It applies in **every** safety level and fails closed on inputs it cannot analyze.

This page is the rule catalog: every built-in rule id, what it matches, and its default state. It is the reference for two questions the other pages defer: *is this file protected?* and *which id turns that rule off?* For the `secret_protection` configuration schema see [Policy](/docs/configuration/policy#secret-protection); for where the stage sits in the guard flow see [Architecture](/docs/guides/architecture#the-ordered-guard-stages); for command-level behavior and worked examples see [Blocked commands](/docs/reference/blocked-commands#sensitive-paths).

There are **132 registered rules**. Most belong to generated families that share one id pattern, so the tables below list families with their id form rather than every id. Every rule is on by default except the ten-rule [Coding CLI config tier](#coding-cli-config-tier-off-by-default).

## Where it runs

Sensitive-path protection is a guard stage that runs **before** command analysis, across the supported **command**, **path**, **search** (grep/glob), and **patch** shapes. For a tool CC Safety Net does not recognize, it inspects both the command-candidate extraction and the path-like values — without ever treating that tool's arbitrary text as a shell command.

| Shape                     | What is inspected                                                                                                                                                                                                                   |
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `command`                 | Path targets extracted from the parsed command, including segments, pipes, redirection targets, command substitutions, `VAR=value` assignment values, and the fallback text of assigning expansions (`${VAR:=path}`, `${VAR=path}`) |
| `path`                    | The extracted path-like tool values (read, write, edit tool inputs)                                                                                                                                                                 |
| `search` (`grep`, `glob`) | File operands, distinguished from pattern-supplying flags                                                                                                                                                                           |
| `patch`                   | The extracted path-like tool values                                                                                                                                                                                                 |
| unknown tool              | Both the command-candidate extraction **and** the path values                                                                                                                                                                       |

A match denies with intent `hard_stop` and carries the matched rule id, so the [block message](/docs/guides/how-it-works#what-a-block-looks-like) and the [audit log](/docs/reference/audit-log) name the exact rule. Reads are blocked, not just writes: `cat .env`, `strings id_rsa`, and `dd if=.env` all block.

An expansion that assigns its fallback exposes that fallback as a path, unquoted or double-quoted alike: `cat "${X:=.env}"` and `cat ${X=.env}` both block under `secret.basename.env`. Single-quoted text stays inert, so `cat '${X:=.env}'` does not block.

## Match order

Each candidate path goes through the checks below in order. The first match wins; the exemptions only apply to the rules that come after them.

1. **Configured [deny paths](/docs/configuration/policy#deny-paths)** — checked before every built-in rule and before every exemption. A hit attributes to `secret.deny-path`.
2. **Env-template exemption** — the template basenames stay readable; see [Exemptions](#exemptions).
3. **[Home directory rules](#home-directory-rules)** — whole protected directories such as `~/.ssh`. These take priority over the public-key exemption, so `~/.ssh/id_rsa.pub` still blocks.
4. **[Coding CLI rules](#coding-cli-credential-tier-on-by-default)** — the per-agent credential and config paths.
5. **Public-key exemption** — `id_rsa.pub`, `id_ed25519.pub`, and `id_ecdsa.pub` are non-secret outside the protected directories.
6. **[Basename rules](#basename-rules)**, then the **`.env.*` pattern**, then the **[key-variant rules](#key-variant-rules)**.
7. **Vendored-directory exemption** — suppresses only the remaining two families; see [Exemptions](#exemptions).
8. **The broad SSH basename pattern**, then the **[extension rules](#extension-rules)**.

## Basename rules

Nine rules block an exact basename in any directory.

| Rule id                           | Basename           |
| --------------------------------- | ------------------ |
| `secret.basename.env`             | `.env`             |
| `secret.basename.npmrc`           | `.npmrc`           |
| `secret.basename.pypirc`          | `.pypirc`          |
| `secret.basename.netrc`           | `.netrc`           |
| `secret.basename.git-credentials` | `.git-credentials` |
| `secret.basename.id-rsa`          | `id_rsa`           |
| `secret.basename.id-ed25519`      | `id_ed25519`       |
| `secret.basename.id-ecdsa`        | `id_ecdsa`         |
| `secret.basename.credentials`     | `credentials`      |

Two boundaries worth knowing:

* `secret.basename.credentials` matches the exact name `credentials` only. `credentials.json` does not match it — or any other built-in rule.
* There is no `id_dsa` basename rule. An exact `id_dsa` still blocks, through the broad pattern `secret.pattern.ssh-key-basename` below.

One pattern rule extends the `.env` family: `secret.pattern.env-variant` blocks every basename starting with `.env.` — `.env.local`, `.env.production`, `.env.template.local` — except the [exempt templates](#exemptions).

## Home directory rules

These rules protect locations under the home directory: the directory itself and everything inside it.

| Rule id                     | Protects                 |
| --------------------------- | ------------------------ |
| `secret.home.ssh`           | `~/.ssh`                 |
| `secret.home.aws`           | `~/.aws`                 |
| `secret.home.gcp`           | `~/.gcp`                 |
| `secret.home.gcloud-config` | `~/.config/gcloud`       |
| `secret.home.kube-config`   | `~/.kube/config`         |
| `secret.home.docker-config` | `~/.docker/config.json`  |
| `secret.home.gh-hosts`      | `~/.config/gh/hosts.yml` |

The two single-file rules (`kube-config`, `docker-config`) each have eight companion rules covering renamed backups, with the id form `secret.home.<slug>.<suffix>`: the suffixes are `bak`, `backup`, `copy`, `disabled`, `old`, `orig`, `save`, and `tmp`. So `~/.kube/config.bak` blocks under `secret.home.kube-config.bak`, and `~/.docker/config.json.old` under `secret.home.docker-config.old`. That is 16 generated rules, 23 in the family overall.

## Key-variant rules

Rename-shielded copies of key and credential files are their own family, built from five protected prefixes: `id_rsa`, `id_dsa`, `id_ed25519`, `id_ecdsa`, and `credentials`. The slug in each id is the prefix with dashes (`id-rsa`, `credentials`, …).

* **Separator variants** — `secret.variant.<slug>.separator` (5 rules). Blocks the prefix followed by `-` or `_` and anything after it: `id_rsa-old`, `id_rsa_backup`, `credentials_prod`.
* **Dot-suffix variants** — `secret.variant.<slug>.<suffix>` (50 rules). Blocks the prefix followed by exactly one of ten suffixes: `.bak`, `.backup`, `.copy`, `.disabled`, `.key`, `.old`, `.orig`, `.pem`, `.save`, `.tmp`. So `id_rsa.bak` blocks under `secret.variant.id-rsa.bak`, and `credentials.pem` under `secret.variant.credentials.pem`.

The family is deliberately exact, so lookalikes pass: `id_rsafoo` matches no separator, and `credentials.json` uses a suffix outside the list.

One broad pattern closes the family: `secret.pattern.ssh-key-basename` blocks any **extensionless** basename ending in `_rsa`, `_dsa`, `_ed25519`, or `_ecdsa` — `deploy_key_rsa`, `github_ed25519`. A name containing a dot never matches it.

## Extension rules

Twenty-one rules with the id form `secret.ext.<extension>` block any file carrying that extension:

`.agilekeychain`, `.asc`, `.bek`, `.cscfg`, `.fve`, `.gnucash`, `.jks`, `.keychain`, `.kwallet`, `.mdf`, `.ovpn`, `.p12`, `.pcap`, `.pem`, `.pfx`, `.pkcs12`, `.psafe3`, `.rdp`, `.sdf`, `.tblk`, `.tpm`

Three **extension-pattern** rules cover extension families:

| Rule id                       | Extensions              |
| ----------------------------- | ----------------------- |
| `secret.ext-pattern.key`      | `.key`, `.keypair`      |
| `secret.ext-pattern.keystore` | `.keystore`, `.keyring` |
| `secret.ext-pattern.kdbx`     | `.kdb`, `.kdbx`         |

An override must use the family id — `secret.ext-pattern.key`, not `secret.ext.keypair`. An id that is not registered is rejected with `unknown secret protection rule id "<id>"`.

## Coding CLI credential tier (on by default)

Nine rules protect the credential stores of supported coding agents. Like every other rule so far, they are on whenever secret protection is enabled.

| Rule id                  | Protects                                                                                                                                |
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- |
| `secret.cli.claude-code` | `~/.claude/.credentials.json`                                                                                                           |
| `secret.cli.codex`       | `~/.codex/auth.json`, `~/.codex/.credentials.json`, `~/.codex/secrets`, `~/.codex/.sandbox-secrets`                                     |
| `secret.cli.gemini`      | `~/.gemini/oauth_creds.json`, `~/.gemini/mcp-oauth-tokens.json`, `~/.gemini/a2a-oauth-tokens.json`, `~/.gemini/gemini-credentials.json` |
| `secret.cli.copilot-cli` | `~/.copilot/config.json`, `~/.copilot/mcp-oauth-config`, `~/.copilot/mcp-secrets`                                                       |
| `secret.cli.kimi-code`   | `~/.kimi-code/server.token`, `~/.kimi-code/credentials`, `~/.kimi/credentials`, `~/.kimi/mcp-oauth`                                     |
| `secret.cli.opencode`    | `~/.local/share/opencode/auth.json`, `~/.local/share/opencode/mcp-auth.json`, `~/.local/share/opencode/opencode.db`                     |
| `secret.cli.pi`          | `~/.pi/agent/auth.json`                                                                                                                 |
| `secret.cli.amp`         | `~/.local/share/amp/secrets.json`, `~/.amp/oauth`                                                                                       |
| `secret.cli.cursor`      | `~/.cursor/auth.json`, `~/.config/cursor/auth.json`, `~/.cursor/projects/<name>/mcp-auth.json`                                          |

Antigravity has no credential rule — its only rule sits in the config tier below.

## Coding CLI config tier (off by default)

Ten rules cover the settings and MCP configuration files of the same agents. Those files can carry credentials inline, but agents also edit them as routine work, so this tier ships **off** and each rule needs an explicit `"on"` in [`secret_protection.overrides`](/docs/configuration/policy#rules-that-are-off-by-default) to activate. `<project>` paths match at any repository root once the rule is on.

| Rule id                         | Protects when enabled                                                                                                                                                                                                |
| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `secret.cli.claude-code.config` | `~/.claude/settings.json`, `~/.claude/settings.local.json`, `~/.claude.json`, `<project>/.claude/settings.local.json`, `<project>/.mcp.json`                                                                         |
| `secret.cli.codex.config`       | `~/.codex/config.toml`, `~/.codex/<name>.config.toml`                                                                                                                                                                |
| `secret.cli.gemini.config`      | `~/.gemini/settings.json`, `~/.gemini/google_accounts.json`, `<project>/.gemini/settings.json`, `/Library/Application Support/GeminiCli/settings.json`, `/etc/gemini-cli/settings.json`                              |
| `secret.cli.copilot-cli.config` | `~/.copilot/mcp-config.json`                                                                                                                                                                                         |
| `secret.cli.kimi-code.config`   | `~/.kimi-code/config.toml`, `~/.kimi-code/mcp.json`, `~/.kimi/config.toml`, `~/.kimi/config.json`, `~/.kimi/config.json.bak`, `~/.kimi/mcp.json`, `<project>/.kimi-code/mcp.json`                                    |
| `secret.cli.opencode.config`    | `~/.config/opencode/opencode.json`, `~/.config/opencode/opencode.jsonc`, `/Library/Application Support/opencode/opencode.json`, `/etc/opencode/opencode.json`, `<project>/opencode.json`, `<project>/opencode.jsonc` |
| `secret.cli.pi.config`          | `~/.pi/agent/models.json`                                                                                                                                                                                            |
| `secret.cli.amp.config`         | `~/.config/amp/settings.json`, `~/.config/amp/settings.jsonc`, `<project>/.amp/settings.json`, `<project>/.amp/settings.jsonc`                                                                                       |
| `secret.cli.cursor.config`      | `~/.cursor/mcp.json`, `<project>/.cursor/mcp.json`                                                                                                                                                                   |
| `secret.cli.antigravity`        | `~/.gemini/config/hooks.json`, `~/.gemini/config/mcp_config.json`                                                                                                                                                    |

## Deny paths

[`secret_protection.deny_paths`](/docs/configuration/policy#deny-paths) adds your own protected locations. A hit is a hard stop attributed to `secret.deny-path` — an id that is **not** registered, so no override can disable it, and none of the exemptions on this page apply to it. Deny paths stop applying only when `secret_protection.enabled` is `false`, which turns off the whole stage. The accepted entry forms are in [Policy](/docs/configuration/policy#deny-paths).

## Exemptions

Three exemptions bound the rules above. None of them relax a configured deny path.

* **Env templates.** The exact basenames `.env.example`, `.env.sample`, `.env.template`, and `.env.defaults` — plus any name starting with `.env.example.` or `.env.sample.` — are exempted before every built-in rule, even inside a protected home directory. The prefix form does not extend further: `.env.template.local` blocks under `secret.pattern.env-variant` like any other `.env.*` name.
* **Public keys.** `id_rsa.pub`, `id_ed25519.pub`, and `id_ecdsa.pub` are non-secret and exempt — but only outside the protected home directories, which are checked first. `./id_rsa.pub` is allowed; `~/.ssh/id_rsa.pub` blocks under `secret.home.ssh`.
* **Vendored directories.** When any path segment is `node_modules` or `__pycache__`, or the adjacent pair `vendor/bundle` or `vendor/cache` appears, exactly two families are suppressed: the extension rules (plain and pattern) and the broad `secret.pattern.ssh-key-basename` rule. Every other rule still applies there — `node_modules/x/.env` and `node_modules/x/id_rsa` block as usual. `.git` is not in the skip set.

## Configuration

All configuration lives in [`policy.json`](/docs/configuration/policy#secret-protection):

* `secret_protection.enabled: false` turns the whole stage off — built-in rules and deny paths alike.
* `secret_protection.overrides` sets per-rule state by registered id: `"off"` disables an on-by-default rule; `"on"` opts into a config-tier rule.
* `secret_protection.deny_paths` adds your own protected locations.

Neither [allow paths](/docs/guides/analysis-engine#recursive-delete-target-classification) nor any standard-mode allowance ever relaxes secret protection. In [strict mode](/docs/configuration/modes#strict-mode-cc_safety_net_strict=1), metadata-only discovery of these paths (`test -f ~/.ssh/id_rsa`, `find ~/.ssh -type f`) is blocked as well. The [Dashboard](/docs/guides/dashboard#secret-protection) edits the same settings through a UI.

<Note>
  Secret protection is a bounded pattern set, not a general read boundary. A credential in a file no rule recognizes is not protected — see [vs. sandboxing](/docs/guides/vs-sandboxing#where-cc-safety-net-cannot-help) for that boundary, and [Known limitations](/docs/guides/known-limitations) for the tier caveats. Secret **redaction** — scrubbing credential values from logs and block messages — is a separate mechanism, documented in the [Audit log reference](/docs/reference/audit-log#secret-redaction) and the [Security model](/docs/guides/security-model#secret-redaction).
</Note>
