Skip to content

False positives: SVG xmlns, form variable names, and duplicate rule engines #357

Description

@ajianaz

Problem

The static security scanner and built-in rule engine both detect hardcoded-secret and hardcoded-url independently with different regex patterns and different sensitivity, causing recurring false positives that block PRs.

False Positive 1: sec-hardcoded-url on SVG xmlns

Rule: sec-hardcoded-url (builtin.rs)
Regex: http://[a-zA-Z0-9][\w.\-]+(:\d+)?(/\S*)?

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" ...>

The W3C XML namespace URI http://www.w3.org/2000/svg is an identifier, not a network connection. It should never be flagged.

Current post_match_filter only excludes localhost addresses — not xmlns=.

Fix: Extend post_match_filter in builtin.rs to also exclude lines containing xmlns= and xlink:href=.


False Positive 2: crypto/hardcoded-secret on form variable names

Rule: crypto/hardcoded-secret (security_scanner.rs line 47)
Regex: (?i)(?:password|passwd|pwd|secret|api_key|apikey|token)\s*[=:]\s*\S{8,}

let formAppSecret = $state('');       // line 21
...(formAppSecret && { app_secret: formAppSecret }),  // line 103

formAppSecret contains secret, and $state('') / formAppSecret matches \S{8,}. These are UI form state variables, not hardcoded credentials.

The sec-hardcoded-secret builtin rule (which requires "[^"]+" — non-empty quoted string) correctly does NOT fire here. But security_scanner.rs has its own looser regex that does.

Fix options:

  • A) Exclude empty string assignments via negative context
  • B) Require value to look like an actual credential (mix of alphanumeric + special chars)
  • C) Exclude lines with UI binding signals ($state, bind:, form)
  • D) Merge both scanners into one unified system (longer-term, eliminates divergence)

Structural Issue: Two duplicate rule engines

security_scanner.rs rules/builtin.rs
Hardcoded secret \S{8,} (very loose) "[^"]+" (requires quoted non-empty string)
Hardcoded URL not checked http://... regex
Post-match filter none localhost exclusions
Test file skip path-segment aware simple prefix

Both run independently on the same diff. Results are merged. The looser regex in security_scanner.rs produces findings the tighter builtin rule would not, and vice versa. This is the root cause of the divergence.


Evidence

PR: codecoradev/titen#16
CI job CodeCora failed with 3 false positive errors (all sec-hardcoded-url rule ID, but sourced from both scanners):

  • web/src/routes/admin/accounts/+page.svelte:21let formAppSecret = $state('')
  • web/src/routes/admin/accounts/+page.svelte:103app_secret: formAppSecret
  • web/src/routes/admin/accounts/+page.svelte:191 — SVG xmlns="http://www.w3.org/2000/svg"

Proposed Fix

  1. Quick: Extend post_match_filter for sec-hardcoded-url to exclude xmlns= and xlink:href=
  2. Quick: Tighten crypto/hardcoded-secret regex in security_scanner.rs — exclude empty string values and UI binding context
  3. Medium: Unify the two scanners into a single rule engine to eliminate regex divergence permanently

Priority

P2 — false positives block PRs and erode trust in the tool. The xmlns fix is trivial and high-impact.

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingsecurity

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions