Fix XSS in memory-browser-panel

Replace dangerouslySetInnerHTML with React elements for inline
formatting (bold/italic). New renderInlineFormatting() helper returns
React nodes instead of raw HTML strings, eliminating XSS risk from
user-controlled memory content.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Pete Christianson 2026-03-04 00:42:08 -08:00
parent a4a606d5ac
commit e6ec050ec3
1 changed files with 27 additions and 13 deletions

View File

@ -271,6 +271,30 @@ export function MemoryBrowserPanel() {
))
}
const renderInlineFormatting = (text: string): React.ReactNode[] => {
const parts: React.ReactNode[] = []
const regex = /(\*\*.*?\*\*|\*.*?\*)/g
let lastIndex = 0
let match: RegExpExecArray | null
let key = 0
while ((match = regex.exec(text)) !== null) {
if (match.index > lastIndex) {
parts.push(text.slice(lastIndex, match.index))
}
const m = match[0]
if (m.startsWith('**') && m.endsWith('**')) {
parts.push(<strong key={key++}>{m.slice(2, -2)}</strong>)
} else if (m.startsWith('*') && m.endsWith('*')) {
parts.push(<em key={key++}>{m.slice(1, -1)}</em>)
}
lastIndex = regex.lastIndex
}
if (lastIndex < text.length) {
parts.push(text.slice(lastIndex))
}
return parts
}
const renderMarkdown = (content: string) => {
// Improved markdown rendering with proper line handling
const lines = content.split('\n')
@ -323,20 +347,10 @@ export function MemoryBrowserPanel() {
elements.push(<div key={`${i}-space`} className="mb-2"></div>)
} else if (trimmedLine.length > 0) {
if (inList) inList = false
// Handle inline formatting — escape HTML entities first to prevent XSS
let content = trimmedLine
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#039;')
// Simple bold formatting
content = content.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
// Simple italic formatting
content = content.replace(/\*(.*?)\*/g, '<em>$1</em>')
elements.push(
<p key={`${i}-p`} className="mb-2" dangerouslySetInnerHTML={{ __html: content }}></p>
<p key={`${i}-p`} className="mb-2">
{renderInlineFormatting(trimmedLine)}
</p>
)
}
}