diff --git a/public/game.js b/public/game.js
index 998283b..b44da74 100644
--- a/public/game.js
+++ b/public/game.js
@@ -2,6 +2,11 @@ const socket = window.location.protocol === 'file:'
? io('http://localhost:3001')
: io();
+// ๐ Safety helpers โ never let player-controlled text/colour reach innerHTML raw.
+// (mirrors escapeHtml in chat.js:431; used by the chat feed, killcam + scoreboard)
+function escapeHtml(s){ return String(s == null ? '' : s).replace(/[&<>"']/g, c => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); }
+function safeColor(c){ const s = String(c == null ? '' : c); return (/^#[0-9a-fA-F]{3,8}$/.test(s) || /^[a-zA-Z]{1,20}$/.test(s)) ? s : '#ffffff'; }
+
// โโ Weapon definitions โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
const WEAPONS = [
{
@@ -1774,7 +1779,8 @@ function renderChatFeed() {
feed.innerHTML = chatLog.map(line => {
const age = (Date.now() - line.t) / 1000;
const op = age > 6 ? Math.max(0, 1 - (age - 6) / 2) : 1;
- return `
${line.text}
`;
+ const _col = safeColor(line.color), _txt = escapeHtml(line.text);
+ return `${_txt}
`;
}).join('');
}
function updateChatFeed() {
@@ -8952,7 +8958,7 @@ function openKillTheater(index) {
ov.style.display = 'block';
ov.innerHTML = `
- ๐น KILL LOG ยท ${replay.victim} ยท ${replay.weapon}
+ ๐น KILL LOG ยท ${escapeHtml(replay.victim)} ยท ${escapeHtml(replay.weapon)}
@@ -12500,7 +12506,7 @@ function showScoreboard(v) {
Object.values(players).sort((a,b)=>b.kills-a.kills).forEach(p => {
const tr = document.createElement('tr');
if (p.id===myId) tr.className='me';
- tr.innerHTML=`${p.name} | ${p.kills} | ${p.deaths} | ${p.hp} | `;
+ tr.innerHTML=`${escapeHtml(p.name)} | ${p.kills} | ${p.deaths} | ${p.hp} | `;
tbody.appendChild(tr);
});
}
diff --git a/server.js b/server.js
index 665ca8a..1d081e2 100644
--- a/server.js
+++ b/server.js
@@ -1016,7 +1016,7 @@ io.on('connection', (socket) => {
const now = Date.now();
if (p._lastChatAt && now - p._lastChatAt < 800) return; // throttle to ~1/0.8s
p._lastChatAt = now;
- socket.broadcast.emit('chatLine', {
+ emitToMatch(p.matchId, 'chatLine', {
id: socket.id,
text: String(data.text || '').slice(0, 60),
color: String(data.color || '#fff').slice(0, 12),