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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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