Skip to content

Hoist XSS sanitizers for search input into named locals (Snyk CWE-79) - #48

Merged
jpr5 merged 1 commit into
masterfrom
security/xss-sanitize-search-locals
Jul 22, 2026
Merged

Hoist XSS sanitizers for search input into named locals (Snyk CWE-79)#48
jpr5 merged 1 commit into
masterfrom
security/xss-sanitize-search-locals

Conversation

@jpr5

@jpr5 jpr5 commented Jul 22, 2026

Copy link
Copy Markdown
Owner

Summary

Snyk Code flagged the erb :index render at server.rb:343 as Cross-Site Scripting (CWE-79) — "unsanitized input from a remote source flows into erb."

The reflected search input was already HTML-escaped at runtime, but the escaping was buried inline inside the locals: hash — a .map { |t| Rack::Utils.escape_html(t) } block for tokens and a ternary for placeholder. Snyk's SAST taint tracker can't follow a sanitizer through that block/hash-literal shape to the render sink, so it reported the path as unsanitized.

This hoists the escaping into explicit, named locals applied before the erb call (safe_tokens / safe_units / safe_placeholder). Behavior is byte-identical; the sanitized dataflow is now legible to both humans and static analysis.

Proof (runtime — not vulnerable, before or after)

The app already had thorough XSS-prevention request specs, and they all pass on this branch:

  • <script> tags in searchtext are escaped in the results-summary echo
  • the search-form placeholder echo is escaped
  • an attribute-breakout <script>/"><img> units param is normalized to the imperial default and kept off the page
  • a malicious Host header can't break out of the webcal:// / https:// x-data attributes

Full suite: 512 examples, 0 failures.

Note

This was a SAST false-positive on already-safe code — the change is a legibility/defense-in-depth refactor to clear the tracker, not a behavioral security fix. If Snyk still reports it after re-scan, the correct disposition is Ignore-as-false-positive (the request specs above are the evidence).

Snyk Code (CWE-79) flagged the `erb :index` render at server.rb:343 as
unsanitized-input-to-template XSS. The request-derived values were in fact
already HTML-escaped, but the escaping was buried inline inside the locals
hash (a `.map` block for tokens, a ternary for placeholder), which the SAST
taint tracker can't follow through to the render sink.

Hoist the escaping into explicit, named locals (safe_tokens / safe_units /
safe_placeholder) applied before the erb call. Behavior is identical — the
existing XSS-prevention request specs (script tags in searchtext, tokens
echo, placeholder, units passthrough, Host-header URL breakout) all still
pass — but the sanitized dataflow is now legible to both humans and static
analysis.

Full rspec suite green (512 examples, 0 failures).
@jpr5
jpr5 merged commit 56bad2e into master Jul 22, 2026
2 checks passed
@jpr5
jpr5 deleted the security/xss-sanitize-search-locals branch July 22, 2026 16:44
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.

1 participant