chore(sync): HTML-escape callback page inputs

This commit is contained in:
iamtoruk 2026-07-26 07:05:44 -07:00
parent 2c29352d80
commit d4f85ced71
2 changed files with 26 additions and 1 deletions

View file

@ -149,7 +149,14 @@ export interface CallbackResult {
* is served once from a throwaway localhost server, so it must not depend
* on network fonts, external CSS, or dashboard assets.
*/
export function renderCallbackPage(ok: boolean, title: string, message: string): string {
export function renderCallbackPage(ok: boolean, rawTitle: string, rawMessage: string): string {
// Current call sites pass literals, but escape anyway so a future caller
// interpolating IdP-influenced text (e.g. the callback `error` param) cannot
// turn this localhost page into an XSS sink.
const escapeHtml = (s: string) => s.replace(/[&<>"']/g, c =>
({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' })[c]!)
const title = escapeHtml(rawTitle)
const message = escapeHtml(rawMessage)
const accent = ok ? '#1f8a5b' : '#c8541f' // --primary / --chart-5 (terracotta)
const mark = ok ? '&#10003;' : '&#10005;' // ✓ / ✕
return `<!doctype html>