feat: add sanitize-html for improved email content sanitization

This commit is contained in:
Dries Augustyns
2026-05-06 11:06:50 +02:00
parent 1193d6c7e6
commit 735acff454
3 changed files with 90 additions and 6 deletions
+2
View File
@@ -39,6 +39,7 @@
"mailparser": "^3.9.8",
"morgan": "^1.10.0",
"multer": "^2.1.1",
"sanitize-html": "^2.17.3",
"signale": "^1.4.0",
"stripe": "^20.0.0"
},
@@ -52,6 +53,7 @@
"@types/mailparser": "^3.4.6",
"@types/morgan": "^1.9.9",
"@types/multer": "^2.0.0",
"@types/sanitize-html": "^2.16.1",
"@types/signale": "^1.4.7",
"concurrently": "^9.2.1",
"tsx": "^4.20.6"
+17 -4
View File
@@ -3,6 +3,7 @@ import type {Prisma} from '@plunk/db';
import {EmailSourceType, EmailStatus} from '@plunk/db';
import type {Request, Response} from 'express';
import {simpleParser} from 'mailparser';
import sanitizeHtml from 'sanitize-html';
import signale from 'signale';
import type Stripe from 'stripe';
@@ -157,19 +158,31 @@ export class Webhooks {
// Parse email content if available
let htmlBody: string | undefined;
if (body.content) {
if (body.content && typeof body.content === 'string') {
try {
const isBase64 = body.receipt?.action?.encoding === 'BASE64';
const emailBuffer = isBase64
? Buffer.from(body.content as string, 'base64')
: Buffer.from(body.content as string);
? Buffer.from(body.content, 'base64')
: Buffer.from(body.content);
const parsed = await simpleParser(emailBuffer);
htmlBody =
const raw =
(parsed.html ? String(parsed.html) : undefined) ??
parsed.textAsHtml ??
parsed.text ??
undefined;
if (raw) {
htmlBody = sanitizeHtml(raw, {
allowedTags: sanitizeHtml.defaults.allowedTags.concat(['img']),
allowedAttributes: {
...sanitizeHtml.defaults.allowedAttributes,
img: ['src', 'alt', 'width', 'height'],
'*': ['style'],
},
allowedSchemes: ['http', 'https', 'mailto'],
});
}
} catch (parseError) {
signale.error('[WEBHOOK] Failed to parse email content:', parseError);
}