AUR-481: Rust idiomatic security coverage
Documento histórico do board. Pode descrever componentes removidos; para uso atual, consulte o guia do produto.
The measurement
The 2026-08-26 measurement planted the same four defects (hardcoded
secret, SQL injection, command injection, XSS) in eight languages and ran
the deterministic --seguranca pass. Rust was the worst cell in the
table: zero of three applicable rules fired, for a language the tool has
a native documentation extractor for (AUR-427) and no external toolchain
dependency. Three causes, each in security.yml's existing patterns:
- security/hardcoded-secret never matched
const ACCESS_KEY: &str = "AKIA...";-- the pattern expects a quote immediately after:=/:/=, and Rust's typed declarations put a TYPE (&str,String) between the identifier and=. - security/sql-injection never matched
conn.query(&("SELECT ... '".to_owned() + name));-- the pattern requires["']\s*\+and Rust's idiomatic concatenation puts a method call (.to_owned()/.to_string()) between the closing quote and the+. Rust's more common shape,format!("SELECT ...{}", name), has no+at all. - security/command-injection never matched
Command::new("sh").arg("-c").arg("ping ".to_owned() + h).spawn();-- none of the existing branches (exec[lv]p?e?,exec(Sync)?,spawn(...shell:true)) recognizeCommand::new.
What this card delivers
internal/review/rules/security.yml:
- security/hardcoded-secret gains two new alternatives: a typed
const/static/let declaration (
IDENT: &str|String = "value") assigned a quoted literal directly, and theString::from("value")wrapper (type annotation optional there). Both reuse the same case-insensitive keyword group and the same digit+letter VALUE class the existing quoted branch uses -- no weakening, same false-positive guard. - security/sql-injection gains two new alternatives: the
.to_owned()/.to_string()-then-+concatenation shape, and aformat!(...)call whose format string carries a SQL verb and a{}placeholder followed by a comma-separated identifier argument. - security/command-injection gains one new alternative:
Command::new("sh"|"bash")plus a.arg("-c")call, flagged on that combination alone (the same "dangerous regardless of what follows" reasoning the existingspawn(...shell:true)branch already uses), regardless of whether the later.arg(...)carries.to_owned() + hconcatenation or aformat!(...)call.
Both extensions were probed against every positive and negative shape
(see tests/unit/AUR-481.go) with a throwaway regex harness before
touching the catalog, then proven against the real loader
(internal/review.SecurityScan) and the real CLI
(aurumcode review --seguranca).
Rust command-injection: first reverted, now restored
A branch analogous to the existing spawn(...shell:true) one --
Command::new("sh"|"bash") plus a .arg("-c") call, flagged on that
combination alone regardless of what a later .arg(...) carries
(.to_owned() + h concatenation or a format!(...) call) -- was written
and proven correct (matches both vulnerable forms, excludes
Command::new("ping").arg(host)). It was first reverted: extending
security/command-injection's pattern broke tests/acceptance/AUR-462.sh's
own MUT-001, which hardcoded that pattern's exact bytes, verbatim, as a
literal grep-and-rewrite anchor (AUR-462.sh:266), and AUR-462.sh was
not in this card's paths at the time. Measured directly:
tests/acceptance/AUR-462.sh AC-001 produced
AUR-462/AC-001/MUT-001/anchor-not-found, exit 1.
tests/acceptance/AUR-462.sh was then added to this card's paths (the
coordinator's own call, after independently verifying the anchor-fragility
claim), with instructions to reanchor MUT-001 stably rather than weaken
its assertion. It now arms on the rule's - id: security/command-injection
line -- a structurally stable, content-independent marker -- and rewrites
the next pattern: line wholesale to an always-empty (pattern: ''),
always-non-matching value, rather than string-replacing inside the
pattern's own text. An awk END block makes the mutation impossible to
silently no-op: if the anchor is never armed-and-matched, awk exits 1,
mv never runs, and an explicit follow-up grep catches the untouched
file and fails loudly. This is immune to any future card widening the
pattern's text, which is exactly the failure this card hit (and the same
failure mode AUR-448's own MUT-001 hit the same day, when AUR-467
added a second print of the same shape it anchored on). With that fix in
place, the Rust command-injection branch is restored and shipped.
Go, C#, PowerShell, and bash command-injection coverage (also named
by this card's own outcome measurement) remain out for the ordinary
reason: this card's declared priority, set by the dispatcher, is Rust
delivered completely and proven, over partial coverage of every language.
Nothing in security.yml was touched for these four languages.
XSS was not in scope for any of the eight languages this card targeted (the outcome table shows XSS covered only for JavaScript, already fixed by AUR-462).
Fixture
tests/fixtures/review/vuln/rust-secret-sql-injection/ is a bare,
loose-object git repository built by
tests/fixtures/repos/git-demo/build-fixture.sh from that directory's
history.spec (the sealed acceptance profile carries no git binary, so
every fixture in this repository is committed pre-built rather than
generated at test time). Its second commit adds src/main.rs carrying
every AC-001 true-positive shape (typed const secret, String::from
secret, .to_owned() SQL concat, format! SQL, Command::new("sh") with
both a .to_owned() and a format! argument) beside every AC-002 safe
form this card names (a numeric constant, a digit-free string constant, a
$1-parametrized query, an argv-form Command with no shell).
Validation
- Unit:
tests/unit/AUR-481.go::TestAUR481-- package-boundary proof over synthetic diffs, including every AC-001 positive, every AC-002 negative, three AC-003 regression shapes, and a fixture-line-for-line end-to-end/determinism check. - Integration:
tests/integration/AUR-481.go::IntegrationAUR481-- CLI-boundary proof: builds the real binary, runs it against the committed Rust fixture and the pre-existing Python/secret/Node fixtures. - E2E:
tests/e2e/AUR-481.sh::E2EAUR481-- full-process proof, including the--fail-on highgate closing on the six real Rust findings. - Acceptance:
tests/acceptance/AUR-481.sh-- runs all three selectors plus two mutations: MUT-001 removes both new SQL alternatives and proves the two Rust SQL true positives vanish; MUT-002 widens theformat!branch past its SQL-verb requirement and proves the AC-002 safe form (format!("user {}", name)) is wrongly matched. - Regression:
tests/acceptance/AUR-462.sh AC-001andtests/acceptance/AUR-466.sh AC-001were run before and after every edit in this card and both stayed exit 0.