diff --git a/components/templates/placeholder-fill-modal.tsx b/components/templates/placeholder-fill-modal.tsx
index b274b1de1..e66ad426c 100644
--- a/components/templates/placeholder-fill-modal.tsx
+++ b/components/templates/placeholder-fill-modal.tsx
@@ -7,6 +7,7 @@ import { cn } from '@/lib/utils';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { substitutePlaceholders, isBuiltInPlaceholder } from '@/lib/template-utils';
+import { sanitizeEmailHtml } from '@/lib/email-sanitization';
import { useFocusTrap } from '@/hooks/use-focus-trap';
import type { EmailTemplate } from '@/lib/template-types';
@@ -94,7 +95,8 @@ export function PlaceholderFillModal({
{t('preview')}
- {template.isHTML ?
: preview}
+ {/* The body may come from an imported file or a synced blob; it is markup in the app document here. */}
+ {template.isHTML ?
: preview}
)}
diff --git a/lib/__tests__/template-utils.test.ts b/lib/__tests__/template-utils.test.ts
index 16404ade4..f33d01288 100644
--- a/lib/__tests__/template-utils.test.ts
+++ b/lib/__tests__/template-utils.test.ts
@@ -221,6 +221,20 @@ describe('importTemplates', () => {
expect(result.templates[0].id).not.toBe('test-id');
});
+ it('strips script and event handlers from an imported HTML body', () => {
+ // The body reaches the composer's placeholder preview as markup in the
+ // app document; it used to be kept exactly as the file had it.
+ const json = JSON.stringify({
+ type: 'webmail-templates',
+ version: 1,
+ templates: [{ name: 'Evil', isHTML: true, body: 'Hi {{name}}
' }],
+ });
+ const body = importTemplates(json).templates[0].body;
+ expect(body).toContain('Hi {{name}}');
+ expect(body).not.toContain('onerror');
+ expect(body).not.toContain('