From 523a5edfa10b650c6a45498404b95b30f0e2f89a Mon Sep 17 00:00:00 2001 From: nullrouten0 Date: Thu, 8 Oct 2026 06:56:30 -0700 Subject: [PATCH] fix(ui): escape the route string on the unknown-route page (#2124) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `app.js` wrote the URL fragment into `innerHTML` as the heading of the "Page not yet implemented" view for routes it does not know. Browsers percent-encode `<`, `>` and `"` in fragments, so this is unlikely to be exploitable today, but it is a plain `innerHTML` sink on a URL-controlled string and costs one `escapeHtml()` to close. **Tests:** one test added to `tests/unit/test-xss-escape-sinks.js` in the file's existing style. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Mythos 5.1 --- public/app.js | 2 +- tests/unit/test-xss-escape-sinks.js | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/public/app.js b/public/app.js index 6ca80cd0..e5677a3f 100644 --- a/public/app.js +++ b/public/app.js @@ -1281,7 +1281,7 @@ function navigate() { else { app.setAttribute('tabindex', '-1'); app.focus({ preventScroll: true }); } }); } else { - app.innerHTML = `

${route}

Page not yet implemented.

`; + app.innerHTML = `

${escapeHtml(route)}

Page not yet implemented.

`; } } diff --git a/tests/unit/test-xss-escape-sinks.js b/tests/unit/test-xss-escape-sinks.js index 350927cc..5867f9ee 100644 --- a/tests/unit/test-xss-escape-sinks.js +++ b/tests/unit/test-xss-escape-sinks.js @@ -588,6 +588,18 @@ test('loadDetail catch block does NOT interpolate e.message into innerHTML', () 'loadDetail missing textContent assignment for e.message: ' + body); }); +// ========================================================================= +// E. URL-derived strings +// ========================================================================= +console.log('\n=== E. URL-derived strings ==='); + +test('app.js unknown-route page escapes the route taken from location.hash', () => { + const html = evalTemplate('public/app.js', + /(

\$\{[^}]*route[^}]*\}<\/h2>

Page not yet implemented\.<\/p><\/div>)/, + { route: TAG_PAYLOAD + ATTR_PAYLOAD }); + assertNoXss(html, 'app.js unknown route'); +}); + // ========================================================================= // SUMMARY // =========================================================================