From e12da3c72f1fa4bd17a7345467d735c5aae1fbcf Mon Sep 17 00:00:00 2001 From: Patience Mpofu Date: Tue, 18 Aug 2026 11:54:26 -0700 Subject: [PATCH] docs: add generic config-secret custom detector example (#5195) * docs: add generic config-secret custom detector example Custom Detectors already support omitting the `verify` webhook, in which case matches are simply reported as unverified. This makes them usable for flagging generic hardcoded secrets (e.g. *.password=, *.secret=) in config files like .properties, .env, and .yaml, which the built-in verified detectors intentionally don't cover. Adds examples/generic_config_secrets.yml, tuned for that use case (looser than generic_with_filters.yml, which requires a digit and a special char), with entropy filtering and exclude rules for common placeholders (changeme, ${VAR}, {{ .template }}, etc.) to keep false positives down. Also links to it from README.md and CUSTOM_DETECTORS.md next to the existing `verify`-optional docs. Addresses #4957. * fix: scope placeholder excludes to captured value, not full match exclude_regexes_match runs against the entire key=value match, so the env/vault/kms exclude rules were dropping real hardcoded secrets whenever the key path happened to contain a word like "env" (e.g. env.password=..., app.env.secret=...) -- common in config files this example targets. Switch to exclude_regexes_capture so these rules only look at the value being reported. Flagged by Cursor Bugbot on PR #5195. --- README.md | 2 + examples/generic_config_secrets.yml | 47 ++++++++++++++++++++++++ pkg/custom_detectors/CUSTOM_DETECTORS.md | 2 + 3 files changed, 51 insertions(+) create mode 100644 examples/generic_config_secrets.yml diff --git a/README.md b/README.md index aa681b49a..5d7b000a2 100644 --- a/README.md +++ b/README.md @@ -798,6 +798,8 @@ Custom Detectors support a few different filtering mechanisms: entropy, regex ta and excluded word lists checked against the secret (captured group if present, entire match if capture group is not present). Note that if your custom detector has multiple `regex` set (in this example `hogID`, and `hogToken`), then the filters get applied to each regex. [Here](examples/generic_with_filters.yml) is an example of a custom detector using these filters. +The `verify` section is optional — if you omit it, matches are still reported as unverified, no webhook required. This makes Custom Detectors useful for flagging generic hardcoded secrets (e.g. `*.password=`, `*.secret=`) in config files like `.properties`, `.env`, or `.yaml` that TruffleHog's built-in, verified detectors won't otherwise catch. [Here](examples/generic_config_secrets.yml) is an example tuned for that use case. + **NB:** This feature is alpha and subject to change. ### Regex Detector Example diff --git a/examples/generic_config_secrets.yml b/examples/generic_config_secrets.yml new file mode 100644 index 000000000..06a814c4c --- /dev/null +++ b/examples/generic_config_secrets.yml @@ -0,0 +1,47 @@ +detectors: +- name: generic-config-secret + keywords: + - secret + - password + - passwd + - pwd + - apikey + - api_key + - api-key + - token + - credential + - cred + - auth + regex: + secret: |- + (?i)[\w.-]{0,50}?(?:secret|passw(?:or)?d|pwd|api[_-]?key|token|credentials?|creds?|auth)[\w.-]{0,20}\s*[=:]\s*["'`]?([^\s"'`,;]{6,150})["'`]?\s*(?:$|[\r\n#;]) + entropy: 2.5 + # Applied to the captured value only (not the key), so a key path like + # `env.password` or `app.env.secret` doesn't cause a real hardcoded + # secret to be excluded just because "env" appears in the key. + exclude_regexes_capture: + - '(?i)^\$\{[^}]*\}$' + - '(?i)^\{\{[^}]*\}\}$' + - '(?i)^%[A-Z_]+%$' + - '(?i)^\$[A-Z_][A-Z0-9_]*$' + - '(?i)^(?:process\.env\.|os\.environ|getenv\(|System\.getenv\()' + - '(?i)^(?:vault|kms|secretsmanager|parameterstore)://' + exclude_words: + - "changeme" + - "change_me" + - "change-me" + - "changethis" + - "xxxxxx" + - "example" + - "placeholder" + - "dummy" + - "redacted" + - "your_api_key" + - "your-api-key" + - "yourapikey" + - "insert_secret_here" + - "todo" + - "fixme" + - "null" + - "none" + - "false" diff --git a/pkg/custom_detectors/CUSTOM_DETECTORS.md b/pkg/custom_detectors/CUSTOM_DETECTORS.md index d7887109e..f149f81f0 100644 --- a/pkg/custom_detectors/CUSTOM_DETECTORS.md +++ b/pkg/custom_detectors/CUSTOM_DETECTORS.md @@ -41,6 +41,8 @@ This guide will walk you through setting up a custom detector in TruffleHog to i When only one of the two fields is configured, non-matching responses are treated as the opposite state (e.g., if only `successRanges` is set, any response that doesn't match is treated as rotated; if only `rotatedRanges` is set, any non-matching response is treated as live). When both fields are configured and the response matches neither, the result is treated as unknown/inconclusive. + Since `verify` is optional, Custom Detectors can also be used without a webhook to flag generic hardcoded secrets (e.g. `*.password=`, `*.secret=`) in config files such as `.properties`, `.env`, or `.yaml`. [Here](/examples/generic_config_secrets.yml) is an example config tuned for that use case. + Here's an example with configurable verification ranges: ```yaml