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:
parent
a4a606d5ac
commit
e6ec050ec3
|
|
@ -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, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''')
|
||||
// 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>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue