Skip to content

fix(security): tighten validateSelector allowlist — replace \s with [ \t] (#34) - #37

Merged
RapierCraft merged 1 commit into
mainfrom
fix/validate-selector-allowlist-34
Jun 22, 2026
Merged

fix(security): tighten validateSelector allowlist — replace \s with [ \t] (#34)#37
RapierCraft merged 1 commit into
mainfrom
fix/validate-selector-allowlist-34

Conversation

@RapierCraft

Copy link
Copy Markdown
Owner

Summary

Fixes the validateSelector() allowlist in src/upload-validator.ts where \s was used as whitespace shorthand. \s in a JS regex character class matches \n, \r, \f, \v, and all Unicode whitespace — only space and tab are valid in CSS selectors.

This means a selector like "div\nspan" previously passed validation and could then be echoed into error messages (e.g. No element found matching selector: div\nspan), splitting the message across lines.

Changes

  • src/upload-validator.ts:224: replace \s[ \t] in allowlist character class
  • src/upload-validator.ts:199-200: JSDoc updated from "whitespace" to "space and tab (the only whitespace valid in CSS selectors)"
  • src/upload-validator.ts:218-221: inline comment explaining the \s[ \t] rationale

Testing

  • validateSelector('div span') → passes (space still valid)
  • validateSelector('div\tnested') → passes (tab still valid)
  • validateSelector("div\nspan") → throws (newline now rejected)
  • validateSelector("div\rspan") → throws (CR now rejected)
  • validateSelector("div\fspan") → throws (form feed now rejected)
  • validateSelector("div\vspan") → throws (vertical tab now rejected)
  • Complex selectors (.class #id [attr="val"] > div + p) → pass
  • npm run build — TypeScript compiles cleanly

Closes #34
Implementation branch: fix/validate-selector-allowlist-34
Base: main

… \t] (#34)

\s in a JS character class matches \n, \r, \f, \v and all Unicode whitespace,
none of which are valid in CSS selectors. Use explicit space and tab instead.

This prevents selectors containing raw newlines or control characters from
passing validation and being echoed in error messages (cdp-client.ts:1858,
cdp-client.ts:1988), which could corrupt structured log output.

Also updates the JSDoc to accurately describe the whitespace characters
that are permitted (space and tab only).
@RapierCraft

Copy link
Copy Markdown
Owner Author

Security Review — PR #37

Agent: General Security (SEC)
PR: fix(security): tighten validateSelector allowlist — replace \s with [ \t] (#34)
Reviewed commit: fb18892


SHA Verification

CURRENT_SHA: fb18892abc6eab9b2e56a466effbf88abe732997
REVIEW_SHA:  fb18892abc6eab9b2e56a466effbf88abe732997
Status: CURRENT ✓

Review

This PR fixes a single regex in src/upload-validator.ts:220 — replacing \s with [ \t] in the validateSelector() allowlist. The change is minimal, targeted, and correct.

Files changed: src/upload-validator.ts (6 additions, 2 deletions)


Security Checks

1. Injection / Input Validation: ✅ PASS
The fix correctly narrows the allowlist. Old regex allowed \s which in JavaScript character classes matches:

  • space ( ) — valid in CSS ✓
  • tab (\t) — valid in CSS ✓
  • newline (\n) — NOT valid in CSS ✗
  • carriage return (\r) — NOT valid in CSS ✗
  • form feed (\f) — NOT valid in CSS ✗
  • vertical tab (\v) — NOT valid in CSS ✗
  • non-breaking space (\u00A0) — NOT valid in CSS ✗
  • other Unicode whitespace — NOT valid in CSS ✗

New regex [ \t] (space literal + \t escape) correctly accepts only space and tab.

Verified with Node.js execution:

space:     OLD=true  NEW=true  ✓ (expected: true)
tab:       OLD=true  NEW=true  ✓ (expected: true)
newline:   OLD=true  NEW=false ✓ (expected: false)
CR:        OLD=true  NEW=false ✓ (expected: false)
FF:        OLD=true  NEW=false ✓ (expected: false)
VT:        OLD=true  NEW=false ✓ (expected: false)
NBSP:      OLD=true  NEW=false ✓ (expected: false — bonus coverage)
.class:    OLD=true  NEW=true  ✓
#id:       OLD=true  NEW=true  ✓
[attr=val]: OLD=true NEW=true  ✓
div > p:   OLD=true  NEW=true  ✓
input:not: OLD=true  NEW=true  ✓

2. Caller coverage: ✅ PASS
All 4 call sites automatically benefit from the tightened allowlist:

3. Build verification: ✅ PASS
npm run build (TypeScript compilation) passes cleanly.

4. Secrets / env vars: ✅ PASS — none detected.

5. No regression: ✅ PASS
The fix preserves all valid CSS selector characters. A comprehensive test of the CSS selector grammar confirms space and tab (the only whitespace valid in CSS selectors) continue to pass. Complex selectors like input:not([disabled]), div > p, .class #id [attr="val"] all pass.

6. Error message safety: ✅ PASS
Two error messages in cdp-client.ts echo the selector back (No element found matching selector: ${selector}). With this fix, selectors containing \n/\r are now rejected before they can split these messages across lines.

7. JSDoc accuracy: ✅ PASS
The JSDoc update correctly narrows "whitespace" to "space and tab (the only whitespace valid in CSS selectors)". The inline comment explains the rationale for future maintainers.


Additional Observation (Informational — Not a Finding)

The \t escape in the character class [ \t] is a literal tab character in the compiled JavaScript. This is correct behavior and the TypeScript compiler handles it as expected. The space between [ and \t is a literal space character — both are explicitly in the allowlist, which is the intended behavior.


Verdict

APPROVED — No security findings. The fix is minimal, correct, complete, and well-documented. All callers automatically benefit from the tightened allowlist.


@RapierCraft RapierCraft left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APPROVED: commit fb18892 after context-aware security review (1 agent: General Security). 0 findings. Safe to merge.

Review summary: Single-file regex fix replacing \s with [ \t] in the validateSelector() allowlist. All 4 callers benefit automatically. TypeScript build passes. No regression on valid CSS selectors.

@RapierCraft
RapierCraft merged commit c3ce9c4 into main Jun 22, 2026
1 check passed
@RapierCraft

Copy link
Copy Markdown
Owner Author

PR Review Summary: #37 — fix(security): tighten validateSelector allowlist

Review Integrity

Reviewed commit: fb18892 | Current HEAD: fb18892 | Status: CURRENT

Verdict: APPROVED

Context-Aware Review

Domains: Security (input validation) | Agents: 1 (General Security)

Integration Checks (Phase 2.5)

Code registration: PASS — all 4 validateSelector() callers automatically benefit (cdp-client.ts:1839, cdp-client.ts:1968, index.ts:1134, http-bridge.ts:613)
SOPS deploy chain: N/A
Purpose Regression Gate (7A): N/A — non-milestone PR

Risk Matrix

Category Risk Blocking? Confidence
Regex regression (valid selectors broken) LOW No CONFIRMED safe
Newlines/control chars now rejected N/A No CONFIRMED desired

Findings

No findings. 0 issues created.

Automated Checks

Check Result
TypeScript build (npm run build) ✅ PASS
Secrets detection ✅ PASS — none
Env var audit ✅ PASS — none
Regex correctness (Node.js exec) ✅ PASS — all 12 test cases pass
Build: 0 errors ✅ PASS

Recommendation

MERGED — PR #37 merged to main at 2026-06-22T05:37:24Z.


Context-aware review complete. 1 agent (Security) + integration checks. 0 findings. PR merged.

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.

fix: validateSelector allowlist permits raw newlines via backslash-s (review finding — PR #32)

1 participant