From 766156caab0ab2e6f8c0e5debb8112f652cff41c Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Tue, 21 Jul 2026 16:25:24 +0100 Subject: [PATCH] =?UTF-8?q?security:=20rust-secrets=20=E2=80=94=20require?= =?UTF-8?q?=20assignment=20to=20a=20literal,=20and=20cover=20`static`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up to #518, from triaging every remaining rust-secrets failure in the estate. THE FALSE POSITIVES. The patterns matched `= ... "` — a quote ANYWHERE after an equals. That flags code which hardcodes nothing at all: let api_key = request["api_key"].as_str().unwrap_or("") a lookup let api_key_file = temp_dir.path().join("config.js") a path Query::new("Here's my api_key=sk-12345") a demo string A hardcoded secret is an assignment DIRECTLY to a string literal, so each pattern now requires the quote to follow the `=`, with a minimum value length of 8 (a credential shorter than that is not a credential). THE MISSED DETECTION. `const.*KEY.*=` never matched `static AUTH_KEY: &str = "abcdef0123456789abcdef0123456789"` — a genuine hardcoded secret the job was silently passing. Found by canary, not by reading the regex: a 5-secret fixture detected only 4. `static` and `mut` are now accepted alongside `const`/`let`. Verified, not assumed: - 7/7 canary cases against the script extracted from THIS yaml (not a copy), including 5/5 real hardcoded secrets detected. - Replayed over all 64 Rust repos at both 2026-07-21 and post-cutoff 2026-09-01: 0 regressions, 3 verdicts fixed (aerie, and heterogenous-mobile-computing post-cutoff). Remaining after this: conative-gating, echidnabot and filesoup carry deliberately secret-shaped fixtures (a fuzz corpus, and two secret-scanners' own detection test data inside r#"…"# raw strings). Those are real matches on real secret-shaped literals, so they take the explicit `// scanner-allow: rust-secrets` pragma rather than a pattern loophole — separate one-line PRs. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/secret-scanner-reusable.yml | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/.github/workflows/secret-scanner-reusable.yml b/.github/workflows/secret-scanner-reusable.yml index c7170194..b01c5f50 100644 --- a/.github/workflows/secret-scanner-reusable.yml +++ b/.github/workflows/secret-scanner-reusable.yml @@ -175,13 +175,25 @@ jobs: fi echo "Scanning ${#FILES[@]} Rust file(s)." + # Each pattern requires an assignment DIRECTLY to a string literal of + # meaningful length. The previous forms matched `= ... "` — a quote + # anywhere after an equals — which flagged code that hardcodes + # nothing at all. Measured across the 64 Rust repos in the estate + # sweep, every one of these was a false positive: + # let api_key = request["api_key"].as_str().unwrap_or("") (lookup) + # let api_key_file = temp_dir.path().join("config.js") (path) + # Query::new("Here's my api_key=sk-12345") (a demo) + # A credential shorter than 8 characters is not a credential either. + # `static` is accepted alongside `const`: the old `const.*KEY` form + # missed `static AUTH_KEY: &str = "…"`, a genuine hardcoded secret + # (caught by canary, not by inspection). PATTERNS=( - 'const.*SECRET.*=.*"' - 'const.*KEY.*=.*"[a-zA-Z0-9]{16,}"' - 'const.*TOKEN.*=.*"' - 'let.*api_key.*=.*"' + '(const|static)[[:space:]]+(mut[[:space:]]+)?[A-Za-z0-9_]*SECRET[A-Za-z0-9_]*[[:space:]]*(:[^=]*)?=[[:space:]]*b?"[^"]{8,}"' + '(const|static)[[:space:]]+(mut[[:space:]]+)?[A-Za-z0-9_]*KEY[A-Za-z0-9_]*[[:space:]]*(:[^=]*)?=[[:space:]]*b?"[a-zA-Z0-9]{16,}"' + '(const|static)[[:space:]]+(mut[[:space:]]+)?[A-Za-z0-9_]*TOKEN[A-Za-z0-9_]*[[:space:]]*(:[^=]*)?=[[:space:]]*b?"[^"]{8,}"' + '(let|static)[[:space:]]+(mut[[:space:]]+)?[a-z0-9_]*api_key[a-z0-9_]*[[:space:]]*(:[^=]*)?=[[:space:]]*b?"[^"]{8,}"' 'HMAC.*"[a-fA-F0-9]{32,}"' - 'password.*=.*"[^"]+"' + '[a-z0-9_]*password[a-z0-9_]*[[:space:]]*(:[^=]*)?=[[:space:]]*b?"[^"]{8,}"' ) # Exemptions, mirroring the four layers already documented on