fix: escape HTML in thinking blocks to prevent XSS
All checks were successful
Build AppImage / build (push) Has been skipped

Both bridge and frontend now properly escape &, <, > in thinking
content before injecting as innerHTML.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Eddy 2026-04-20 22:41:42 +02:00
parent 2b2e8fe932
commit 1b1800e32b
2 changed files with 3 additions and 3 deletions

View file

@ -545,7 +545,7 @@ async function sendMessage(message, requestId, model = null, contextOverride = n
} else if (block.type === 'thinking' && block.thinking) {
// Extended Thinking — als kollabierbaren Block im ChatGPT/Claude.ai-Style
const thinkLines = block.thinking.split('\n').length;
const escaped = block.thinking.replace(/</g, '&lt;').replace(/>/g, '&gt;');
const escaped = block.thinking.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
const collapsed = `<details class="thinking-block"><summary><svg class="thinking-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2a8 8 0 0 0-8 8c0 3.4 2.1 6.3 5 7.4V19a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1v-1.6c2.9-1.1 5-4 5-7.4a8 8 0 0 0-8-8z"/><line x1="9" y1="22" x2="15" y2="22"/></svg><span class="thinking-label">Überlegung</span><span class="thinking-meta">${thinkLines} Zeilen</span><svg class="thinking-chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"/></svg></summary><div class="thinking-content">${escaped}</div></details>\n\n`;
fullText += collapsed;
sendEvent('text', { text: collapsed });

View file

@ -68,9 +68,9 @@
for (const pattern of thinkingPatterns) {
const match = text.match(pattern);
if (match && match[1] && match[1].split('\n').length > 5) {
const thinkingPart = match[1].trim();
const thinkingPart = match[1].trim().replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
const answerPart = match[2].trim();
const lines = thinkingPart.split('\n').length;
const lines = match[1].trim().split('\n').length;
return `<details class="thinking-block"><summary><svg class="thinking-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2a8 8 0 0 0-8 8c0 3.4 2.1 6.3 5 7.4V19a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1v-1.6c2.9-1.1 5-4 5-7.4a8 8 0 0 0-8-8z"/><line x1="9" y1="22" x2="15" y2="22"/></svg><span class="thinking-label">Überlegung</span><span class="thinking-meta">${lines} Zeilen</span><svg class="thinking-chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"/></svg></summary><div class="thinking-content">${thinkingPart}</div></details>\n\n${answerPart}`;
}
}