Skip to content

fix(scanner): narrow CORS wildcard regex + skip doc files + negation filter - #484

Merged
ajianaz merged 1 commit into
developfrom
fix/cors-scanner-false-positive-483
Aug 4, 2026
Merged

fix(scanner): narrow CORS wildcard regex + skip doc files + negation filter#484
ajianaz merged 1 commit into
developfrom
fix/cors-scanner-false-positive-483

Conversation

@ajianaz

@ajianaz ajianaz commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

What

Fixes the CORS wildcard security scanner rule that produced false positives on documentation, env var names, and negation contexts (e.g., "do not use *").

Why

The original regex (?i)(?:Access-Control-Allow-Origin|cors).*\* matched any line containing the word "cors" followed by * anywhere after it. This triggered false positives on:

  • Env var names: TITEN_CORS_ORIGINS — contains "cors", then * from markdown bold ** or URL patterns
  • Documentation prose: Markdown config guides mentioning CORS setup
  • Negation contexts: Comments like "no wildcard" or "do not use *"

This caused stale/incorrect check-run failures on PRs in downstream repos using cora-review-action (e.g., titen#38, titen#39), requiring --admin merge override.

Closes #483

How

Three-layer defense-in-depth fix:

1. Narrow regex (security_scanner.rs)

Before: (?i)(?:Access-Control-Allow-Origin|cors).*\* — matches "cors" + any *

After: Requires actual code assignment/call syntax:

  • Access-Control-Allow-Origin: * — literal HTTP header
  • cors = "*", allow_origin("*"), allowed_origins = "*" — code patterns with [=:(] delimiter
  • origin: *, origin = "*" — config/key patterns

The standalone word "cors" no longer triggers — it must be part of a code pattern.

2. Skip non-code files (security_scanner.rs)

Added is_doc_file() check — security scanner now skips .md, .markdown, .mdx, .txt, .rst, .adoc, .asciidoc, .tex, .org files entirely. Security patterns are designed for source code, not prose.

3. Post-match negation filter (builtin.rs)

Added is_false_positive_cors() to post_match_filter() — suppresses matches when the line contains negation context:

  • "no wildcard", "no catch-all", "do not use *"
  • "without wildcard", "never wildcard", "disallow wildcard"
  • Env var/config key names: cors_origins, cors_allowed, cors_config

Testing

Test coverage added (25 new tests):

security_scanner.rs (14 tests):

  • detects_cors_wildcard_header — real HTTP header still detected
  • detects_cors_wildcard_assignmentcors_origin = "*" detected
  • detects_allowed_origins_wildcardallowed_origins = "*" detected
  • no_false_positive_cors_env_var_nameTITEN_CORS_ORIGINS does not trigger
  • no_false_positive_cors_in_prose — comment text does not trigger
  • no_false_positive_markdown_file.md files skipped entirely
  • no_false_positive_txt_file.txt files skipped
  • no_false_positive_rst_file.rst files skipped
  • real_cors_wildcard_in_rust_still_detected.allow_origin("*") still triggers
  • is_doc_file_recognizes_common_extensions — 9 doc extensions detected
  • is_doc_file_does_not_match_code_files — 8 code extensions/files pass through

builtin.rs (6 tests):

  • cors_negation_no_wildcard_is_false_positive
  • cors_negation_no_catch_all_is_false_positive
  • cors_negation_do_not_use_wildcard_is_false_positive
  • cors_env_var_name_is_false_positive
  • cors_actual_wildcard_is_not_false_positive — ensures real wildcards NOT suppressed
  • cors_unrelated_rule_not_affected — filter only applies to cors rule

Related Issues

Closes #483

Checklist

  • Branch name follows convention (fix/cors-scanner-false-positive-483)
  • Branch is from develop
  • Commit messages follow Conventional Commits
  • No secrets or credentials committed
  • One logical change per PR (no mixed concerns)

…filter (#483)

The static security scanner's CORS rule used an overly broad regex that
matched any occurrence of the word 'cors' followed by '*' anywhere on the
line. This triggered false positives on:
- Env var names like TITEN_CORS_ORIGINS (contains 'cors' + '*' from markdown bold)
- Documentation prose mentioning CORS configuration
- Comments instructing developers NOT to use wildcards

Three-layer fix:

1. Narrow regex to require actual code patterns:
   - Access-Control-Allow-Origin: *  (HTTP header)
   - cors = * / allow_origin(*) / origin: * / allowed_origins = *
   - Method calls like .allow_origin(*) now matched via [=:(] delimiter

2. Skip non-code files (.md, .txt, .rst, .adoc, .tex, .org, etc.)
   Security patterns are designed for source code, not prose.

3. Post-match negation context filter:
   Suppresses matches in negation contexts like 'no wildcard',
   'do not use *', 'without wildcard', and env var name patterns
   (cors_origins, cors_allowed, cors_config).

Tests: 25 new test cases covering true positives, false positives from
issue #483, doc file detection, and negation context suppression.
@ajianaz
ajianaz merged commit fac21b5 into develop Aug 4, 2026
13 checks passed
ajianaz added a commit that referenced this pull request Aug 4, 2026
…ation filter edge cases (#488, #489)

PR #484 narrowed the CORS regex to fix false positives (#483), but the
narrowing was too aggressive: 13 of 14 common framework-specific CORS
wildcard patterns were no longer detected.

Changes:

1. Rewrite CORS regex with 10 framework pattern alternatives using
   (?ix) extended mode: HTTP header, generic assignment, Django,
   Spring Boot, .NET, tower-http, Express, FastAPI, nginx, actix-web.
2. Remove unsupported lookahead (?!\w) — Rust regex crate limitation.
   Use explicit trailing delimiters instead.
3. Fix negation filter: skip suppression when comment body contains
   code indicators (=, fn, let, const) after negation phrase.
4. Fix cors_config suppression: only suppress env::var() read patterns,
   not bare CORS_CONFIG = "*" assignments (real finding).
5. Pre-compile negation regexes with LazyLock for performance.
6. Fix is_doc_file(): check for dot before extracting extension.
   Prevents extensionless files ('org', 'tex', 'md') being treated as docs.

Tests: 836 pass, 0 fail, 0 clippy warnings, fmt clean.
Closes #488, closes #489.
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.

Static security scanner reports stale/false-positive CORS finding after source text changed

1 participant