Skip to content

security: rust-secrets — require assignment to a literal, and cover static#523

Merged
hyperpolymath merged 2 commits into
mainfrom
security/rust-secrets-literal-assignment
Jul 21, 2026
Merged

security: rust-secrets — require assignment to a literal, and cover static#523
hyperpolymath merged 2 commits into
mainfrom
security/rust-secrets-literal-assignment

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

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. 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 (the more important half)

const.*KEY.*= never matched:

static AUTH_KEY: &str = "abcdef0123456789abcdef0123456789";

That is a genuine hardcoded secret the job was silently passing. I found it because a 5-secret canary fixture detected only 4 — not by reading the regex. static and mut are now accepted alongside const/let.

Verified, not assumed

Canary run against the script extracted from this YAML (yaml.safe_load → execute), not a hand-copy:

PASS  5 real hardcoded secrets           -> BLOCKS   (detected 5/5)
PASS  clean (env::var, comment, pragma, OAuth URL)
PASS  secret in ./src                    -> BLOCKS
PASS  crates/                            -> ADVISORY today
PASS  crates/                            -> BLOCKS after cutoff
PASS  literal + env mention after ;      -> BLOCKS
PASS  malformed cutoff                   -> refuses to run
7 passed, 0 failed

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).

What deliberately still fails

conative-gating, echidnabot, filesoup carry genuinely 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 get the explicit // scanner-allow: rust-secrets pragma rather than a pattern loophole that would weaken the gate for everyone. Separate one-line PRs.

🤖 Generated with Claude Code

…static`

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 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@hyperpolymath
hyperpolymath merged commit d13ff9f into main Jul 21, 2026
18 of 21 checks passed
@hyperpolymath
hyperpolymath deleted the security/rust-secrets-literal-assignment branch July 21, 2026 15:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant