Incident ID: 2026-05-01-gitleaks-cf-account-id-false-positive Date: 2026-05-01 Severity: SEV-4 (infrastructure drift / toil accumulating; no secrets exposed) Duration: ~24h between first filing (2026-04-30 nightly scan) and resolution (2026-05-01) Blast radius: nightly security scan noise; #682 filed; would continue filing duplicate issues on every subsequent nightly run without remediation Author: sre-agent
The nightly gitleaks scan filed #682 (CRITICAL: generic-api-key in terraform/freescout/terraform.tfvars:31) daily. The flagged value is the Cloudflare Account ID — a public identifier, not a secret. An allowlist entry for this pattern already existed in .gitleaks.toml (added in PR #633), but the allowlist was silently not working because regexTarget = "match" was not set, causing gitleaks to test the regex against the bare hex Secret value rather than the full variable-assignment Match string. PR #839 adds regexTarget = "match" and two additional SOP path suppressions; full-history scan drops from 19 findings to 0.
cf_access_account_id in terraform/freescout/terraform.tfvars:31 and terraform/cf-access/terraform.tfvars:13. #682 filed by security_file_issues.py.cf_access_account_id (Cloudflare Account ID). Confirmed it is a public, non-secret identifier..gitleaks.toml: allowlist regex for cf_access_account_id already present from PR #633. Ran gitleaks --no-git=false locally; findings still appeared.config/allowlist.go): without regexTarget, regexes test against the extracted Secret field, not the Match field. Regex cf_access_account_id\s*=\s*"[0-9a-f]{32}" matches Match but not Secret. Root cause confirmed.regexTarget = "match" and SOP path suppressions to .gitleaks.toml.cf_access_account_id is the Cloudflare Account ID, a public identifier not a credential. No rotation required.regexTarget field.regexTarget gap immediately.generic-api-key rule fires on entropy alone; the severity label amplified toil.Contributing factor 1: regexTarget not set in allowlist — gitleaks [allowlist] regexes default to matching against the extracted Secret (the pattern group capture), not the full Match string. The allowlist entry was written as a full-assignment regex (cf_access_account_id\s*=\s*"[0-9a-f]{32}"). Without regexTarget = "match", gitleaks tested this regex against the raw hex value 22b5c35090724fbf05db6d4f501ac821, which did not match. The allowlist silently did nothing.
Contributing factor 2: Allowlist entry not validated against full-history scan — the entry was added in PR #633 targeting the shallow file scan. The nightly CI scan uses --no-git=false (full git history). No test was run in full-history mode to confirm suppression.
Contributing factor 3: No gitleaks runbook — when the finding recurred in #682, there was no documented procedure for diagnosing why an allowlist entry wasn't working. The investigation had to start from scratch.
security_file_issues.py from the nightly scan (2026-04-30 08:07 UTC)regexTarget field since PR #633 merged 2026-04-30; #682 was filed the same night)gitleaks detect --no-git=false --config=.gitleaks.toml on the PR branch and fails if new findings appear beyond the baseline (see action items)regexTarget = "match" to [allowlist] in .gitleaks.toml. Added path suppressions ^console/app/sops/rotation/ and ^app/sops/rotation/ for curl-auth-user false positives on SOP documentation copies.gitleaks detect --source=. --config=.gitleaks.toml --no-git=false — 914 commits, 0 findings (was 19).cf_access_account_id is a public Cloudflare Account ID visible in the dashboard URL.| # | Action | Owner | Due | Issue |
|---|---|---|---|---|
| 1 | Merge PR #839 — gitleaks allowlist fix | Kristerpher | 2026-05-02 | #839 |
| 2 | Add CI job that runs gitleaks full-history scan on PRs touching .gitleaks.toml and fails on new findings |
sre-agent | 2026-05-08 | (new) |
| 3 | Add note to .gitleaks.toml header: "when adding a regexes entry, test with gitleaks detect --no-git=false" |
sre-agent | 2026-05-08 | (in PR #839 comment) |
docs/ops/runbooks/gitleaks.md (new, created with this RCA)https://github.com/gitleaks/gitleaks/blob/v8.18.4/config/allowlist.go