Skip to content

Fix XSS escaping flagged by Snyk Code#45

Merged
jpr5 merged 5 commits into
masterfrom
fix/xss-escaping
Jun 10, 2026
Merged

Fix XSS escaping flagged by Snyk Code#45
jpr5 merged 5 commits into
masterfrom
fix/xss-escaping

Conversation

@jpr5

@jpr5 jpr5 commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes the three Snyk Code XSS (CWE-79) findings on the search results page:

  • erb :index locals (server.rb) — the units param is now strictly whitelisted to metric/imperial; tokens and placeholder escaping switched from ERB::Util.html_escape_once (bypassable via pre-encoded entities) to Rack::Utils.escape_html.
  • Host-derived calendar base URLs (views/index.erb, both _station_card renders)webcal_base/https_base derive from the request Host header and were interpolated into Alpine.js x-data as bare single-quoted JS strings. They are now JSON-encoded then HTML-escaped at construction and injected as proper literals, so a malicious Host header cannot break out of the JS string context.

Tests

Regression specs added with red-green verification (each assertion proven to fail when its protection is removed):

  • Script-tag payloads in searchtext and units
  • Malicious Host header breakout against both webcalBase and httpsBase independently
  • Assertions anchored on the results-summary markup so the search-form placeholder echo cannot mask a regression

Full suite: 512 examples, 0 failures.

jpr5 added 5 commits June 10, 2026 08:59
Whitelist the units param, switch token/placeholder escaping to
Rack::Utils.escape_html, and encode webcal/https base URLs as
HTML-escaped JSON literals before they reach Alpine.js x-data,
closing 3 Snyk Code XSS (CWE-79) findings. Adds regression tests.
- Replace placeholder regex that could never match (payload's leading
  quote made [^"]* match empty) with positive escaped-form and negative
  raw-form assertions
- Replace units not_to-include assertions that could not fail (server
  whitelists units via ternary, raw param is never echoed) with
  whitelist-behavior assertions and matching descriptions
- Replace vacuous include('imperial') (literal appears unconditionally
  in layout JS) with results-summary assertions
- Replace dead Host-header negative assertion (single-quoted form
  to_json can never emit) with one that fires when escaping is removed
- Key group_search_results stub on match_depth kwarg instead of call
  order
- Loosen token assertion to '<script>alert(1)<' to reduce
  Rack-version coupling without weakening the test
- Fix stale html_escape_once comment (server uses
  Rack::Utils.escape_html)
Pin httpsBase encoding alongside webcalBase in the Host-header test,
anchor the token-echo positive assertion to the results summary markup,
assert find_current_stations also receives the units param, and replace
the shape-blind group_search_results call-count with arg-pinned
per-call-site assertions.
@jpr5 jpr5 merged commit 40ad4f9 into master Jun 10, 2026
2 checks passed
@jpr5 jpr5 deleted the fix/xss-escaping branch June 10, 2026 16:57
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