Skip to content

[P0] Security: Fix XSS in lore-detail-client and world-client markdown rendering #24

Description

@Pamacea

[P0] Security: Fix XSS in lore-detail-client and world-client markdown rendering

Severity

  • Priority: P0
  • Type: Security (XSS)
  • Estimation: 2 hours

Problem

The lore detail page and world client may render user-generated content (markdown, HTML) without proper sanitization, allowing XSS attacks.

Files Affected

  • src/app/world/[id]/lore/[slug]/page.tsx - lore-detail-client
  • src/app/world/[id]/page.tsx - world-client

Potential Attack Vectors

  1. Lore entries with malicious markdown/HTML
  2. Character descriptions with script injection
  3. Pin descriptions with on* event handlers
  4. User-generated rich text in any content field

Steps to Fix

  1. Audit all markdown rendering in these files:
// Search for dangerouslySetInnerHTML
grep -r "dangerouslySetInnerHTML" src/app/world/
  1. Ensure all HTML is sanitized:
import { sanitizeHtml } from '@/shared/lib/sanitize';

// BAD
<div dangerouslySetInnerHTML={{ __html: markdownContent }} />

// GOOD
<div dangerouslySetInnerHTML={{ __html: sanitizeHtml(markdownContent) }} />
  1. Use a proper markdown library with built-in sanitization:
import { marked } from 'marked';
import DOMPurify from 'dompurify';

export function renderMarkdown(content: string) {
  const rawHtml = marked(content);
  return DOMPurify.sanitize(rawHtml, {
    ALLOWED_TAGS: ['p', 'br', 'strong', 'em', 'a', 'h1', 'h2', 'h3', 'ul', 'ol', 'li', 'blockquote', 'code', 'pre'],
    ALLOWED_ATTR: ['href'],
    FORBID_ATTR: ['onclick', 'onload', 'onerror'],
  });
}
  1. Add Content Security Policy headers:
// next.config.js
const securityHeaders = [
  {
    key: 'Content-Security-Policy',
    value: "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self'"
  }
];

module.exports = {
  async headers() {
    return [{ source: '/:path*', headers: securityHeaders }];
  }
};

Acceptance Criteria

  • All dangerouslySetInnerHTML usage is audited
  • All user content is sanitized before rendering
  • CSP headers configured in next.config.js
  • XSS tests added for all content rendering paths
  • No script execution possible via user content

Notes

This complements the fix in property-description-textarea. All markdown rendering should use the same sanitization approach.

Co-Authored-By: Claude Opus 4.6 noreply@anthropic.com

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    criticalCritical issue requiring immediate attentionp0Priority: CriticalsecuritySecurity vulnerability or fix

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions