Description
The blog post page (apps/web/app/blog/[slug]/page.tsx) renders post.content using dangerouslySetInnerHTML without any HTML sanitization (line 96):
dangerouslySetInnerHTML={{ __html: post.content }}
If an attacker can inject malicious HTML into a blog post's content field (via the admin panel, database, or any content pipeline), the injected JavaScript will execute in every visitor's browser.
Impact
- Severity: High
- Session hijacking, credential theft, phishing
- Any compromise of the blog content pipeline immediately escalates to client-side code execution
Steps to Reproduce
- Insert a blog post with content containing
<img onerror="alert('XSS')" src=x> or <script>alert('XSS')</script>
- Visit the blog post page
- The injected script executes
Suggested Fix
Sanitize HTML before rendering using a library like sanitize-html or isomorphic-dompurify:
import sanitizeHtml from 'sanitize-html';
// In the component:
const cleanContent = sanitizeHtml(post.content, {
allowedTags: sanitizeHtml.defaults.allowedTags.concat(['img', 'h1', 'h2', 'h3']),
allowedAttributes: {
...sanitizeHtml.defaults.allowedAttributes,
img: ['src', 'alt', 'width', 'height'],
},
});
Description
The blog post page (
apps/web/app/blog/[slug]/page.tsx) renderspost.contentusingdangerouslySetInnerHTMLwithout any HTML sanitization (line 96):If an attacker can inject malicious HTML into a blog post's
contentfield (via the admin panel, database, or any content pipeline), the injected JavaScript will execute in every visitor's browser.Impact
Steps to Reproduce
<img onerror="alert('XSS')" src=x>or<script>alert('XSS')</script>Suggested Fix
Sanitize HTML before rendering using a library like
sanitize-htmlorisomorphic-dompurify: