Escape HTML entities before rendering AI insight content

The renderContent() function used dangerouslySetInnerHTML without
first sanitizing the AI-generated text, allowing any HTML in the
model response to execute in the browser. Added escHtml() helper
and applied it before the bold-substitution regex.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
jtricerolph 2026-07-13 09:25:02 +00:00
parent fce9048902
commit dde41bc5d1

View file

@ -23,9 +23,17 @@ function formatAge(iso: string): string {
return `${Math.floor(hours / 24)}d ago` return `${Math.floor(hours / 24)}d ago`
} }
function escHtml(s: string): string {
return s
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
}
function renderContent(text: string) { function renderContent(text: string) {
return text.split('\n').map((line, i) => { return text.split('\n').map((line, i) => {
const processed = line.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>') const safe = escHtml(line)
const processed = safe.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
if (line.startsWith('- ') || line.startsWith('* ')) { if (line.startsWith('- ') || line.startsWith('* ')) {
return ( return (
<div key={i} style={{ display: 'flex', gap: 8, marginBottom: 4 }}> <div key={i} style={{ display: 'flex', gap: 8, marginBottom: 4 }}>