diff --git a/.jules/sentinel.md b/.jules/sentinel.md index ae7a88f..9bdaa4e 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -27,3 +27,7 @@ **Vulnerability:** The CLI file scanner `vibesec scan` lacked detection rules for fundamental security vulnerabilities in JavaScript/TypeScript ecosystems, specifically arbitrary code execution via `eval()` and Cross-Site Scripting (XSS) via React's `dangerouslySetInnerHTML`. **Learning:** Even specialized "vibe-coding" static analysis tools must include detection for standard, catastrophic security anti-patterns (like eval and XSS injection vectors) to provide complete coverage. **Prevention:** Two new rules, `dangerous-eval` and `react-dangerously-set-inner-html`, were added to `SCAN_RULES` to flag these patterns. +## 2025-02-12 - Prevent ReDoS by avoiding capturing groups in scanner rules +**Vulnerability:** Regular Expression Denial of Service (ReDoS) vulnerability caused by tracking capturing group matches `(...)` during line-by-line file scanning in `SCAN_RULES`. +**Learning:** In a highly repetitive inner loop (line-by-line file scanning), tracking backreferences and capturing group matches incurs unnecessary regex engine overhead. While unbounded quantifiers are the primary ReDoS cause, capturing groups exacerbate the tracking state, increasing scan time significantly on long lines or adversarial payloads. +**Prevention:** Always use non-capturing groups `(?:...)` instead of capturing groups `(...)` when adding or modifying regular expressions in `SCAN_RULES` to prevent unnecessary performance overhead and ReDoS vulnerabilities. diff --git a/scanner/cli/vibesec.py b/scanner/cli/vibesec.py index d97f38d..f1a9137 100644 --- a/scanner/cli/vibesec.py +++ b/scanner/cli/vibesec.py @@ -116,7 +116,7 @@ SCAN_RULES = [ { "id": "hardcoded-stripe-secret", - "pattern": re.compile(r'sk_(live|test)_[A-Za-z0-9]{24,}'), + "pattern": re.compile(r'sk_(?:live|test)_[A-Za-z0-9]{24,}'), "severity": "CRITICAL", "message": "Hardcoded Stripe secret key detected. Rotate this key immediately.", "extensions": None, @@ -150,7 +150,7 @@ }, { "id": "firebase-allow-all", - "pattern": re.compile(r'allow\s+(read|write|read,\s*write)\s*:\s*if\s+true'), + "pattern": re.compile(r'allow\s+(?:read|write|read,\s*write)\s*:\s*if\s+true'), "severity": "CRITICAL", "message": ( "Firebase/Firestore rule allows unrestricted read/write access. " @@ -161,7 +161,7 @@ { "id": "todo-skip-auth", "pattern": re.compile( - r'(?i)(todo|fixme|hack|temp)[^\n]{0,50}(auth|security|permission|check|protect)', + r'(?i)(?:todo|fixme|hack|temp)[^\n]{0,50}(?:auth|security|permission|check|protect)', ), "severity": "HIGH", "message": ( @@ -180,7 +180,7 @@ { "id": "hardcoded-database-url", "pattern": re.compile( - r'(?i)(DATABASE_URL|POSTGRES_URL)\s*[=:]\s*["\x27](postgres|postgresql|mysql)://\S+', + r'(?i)(?:DATABASE_URL|POSTGRES_URL)\s*[=:]\s*["\x27](?:postgres|postgresql|mysql)://\S+', ), "severity": "CRITICAL", "message": "Hardcoded database connection string detected.", @@ -189,7 +189,7 @@ { "id": "hardcoded-jwt-secret", "pattern": re.compile( - r'(?i)(JWT_SECRET|NEXTAUTH_SECRET)\s*[=:]\s*["\x27][^"\x27\s]{8,}["\x27]', + r'(?i)(?:JWT_SECRET|NEXTAUTH_SECRET)\s*[=:]\s*["\x27][^"\x27\s]{8,}["\x27]', ), "severity": "CRITICAL", "message": "Hardcoded JWT/NextAuth secret detected.",