Description
The overlay leaderboard (overlay/static/index.html) injects entry.word directly into the DOM via innerHTML without escaping. Words come from Twitch chat messages — a viewer could submit a guess containing HTML/JS to inject arbitrary content into the overlay.
Location
overlay/static/index.html — leaderboard render loop
// Vulnerable:
row.innerHTML = `<span class="top-word">${entry.word}</span>`;
Fix
Replace innerHTML assignment with DOM node creation using textContent:
const wordSpan = document.createElement('span');
wordSpan.className = 'top-word';
wordSpan.textContent = entry.word; // escapes HTML automatically
Apply the same pattern to all dynamic values (entry.user, scores, target word).
Severity
🔴 Critical — Identified by [Tech] UX Designer
Description
The overlay leaderboard (
overlay/static/index.html) injectsentry.worddirectly into the DOM viainnerHTMLwithout escaping. Words come from Twitch chat messages — a viewer could submit a guess containing HTML/JS to inject arbitrary content into the overlay.Location
overlay/static/index.html— leaderboard render loopFix
Replace
innerHTMLassignment with DOM node creation usingtextContent:Apply the same pattern to all dynamic values (
entry.user, scores, target word).Severity
🔴 Critical — Identified by
[Tech] UX Designer