Summary
The frontend chatbot renders assistant output through innerHTML after passing it through
formatMarkdown() in docs_scripts/chatbot.js.
Fenced code blocks are escaped via escapeHtml(), but inline code and bold text
substitutions insert captured groups directly into HTML without escaping. Raw HTML outside
any markdown marker also survives into the DOM.
Evidence
Unsafe substitutions:
- Inline code (line 767):
formatted = formatted.replace(/([^\n]+)/g, '$1');`
- Bold text (line 773):
formatted = formatted.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
innerHTML sinks:
- Streaming path:
docs_scripts/chatbot.js:609
- Non-streaming path:
docs_scripts/chatbot.js:830
Existing escaping (used for fenced code blocks only):
escapeHtml() at docs_scripts/chatbot.js:975
Impact
If the model returns text containing HTML like <img src=x onerror=alert(1)>, it is
inserted into the DOM unsanitized via innerHTML.
Expected Fix
At minimum, apply escapeHtml() to captured groups in the inline code and bold regex
replacements. A more comprehensive fix would escape all raw text before selectively
re-introducing safe markdown formatting.