From b2588ecdd8d553c73da5f33f1edd1d60de670753 Mon Sep 17 00:00:00 2001 From: Matt Date: Wed, 13 May 2026 00:08:51 +0200 Subject: [PATCH] fix(audit-wave-1): route all email-template URLs through safeUrl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes Wave 1.4 (CRITICAL). Three templates still inlined URLs directly into `href` without the existing safeUrl() helper: - inquiry-client-confirmation: `mailto:${contactEmail}` href — user-supplied email straight to an HTML attribute. - inquiry-sales-notification: `${crmUrl}` from inquiry form input. - residential-inquiry: same `mailto:${contactEmail}` pattern. Each call now passes through `safeUrl()` from `@/lib/email/shell`, which (a) scheme-allow-lists to http(s)/mailto/tel/root-relative and (b) HTML-attribute-escapes the result. A stray `"` in any URL would have escaped the attribute; a `javascript:` scheme would have triggered XSS in webmail clients that run scripts. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/lib/email/templates/inquiry-client-confirmation.tsx | 4 ++-- src/lib/email/templates/inquiry-sales-notification.tsx | 4 ++-- src/lib/email/templates/residential-inquiry.tsx | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib/email/templates/inquiry-client-confirmation.tsx b/src/lib/email/templates/inquiry-client-confirmation.tsx index 4de337c7..982f7682 100644 --- a/src/lib/email/templates/inquiry-client-confirmation.tsx +++ b/src/lib/email/templates/inquiry-client-confirmation.tsx @@ -1,7 +1,7 @@ import { Link, Text, render } from '@react-email/components'; import * as React from 'react'; -import { brandingPrimaryColor, renderShell, type BrandingShell } from '@/lib/email/shell'; +import { brandingPrimaryColor, renderShell, safeUrl, type BrandingShell } from '@/lib/email/shell'; export interface InquiryClientConfirmationData { firstName: string; @@ -38,7 +38,7 @@ function ClientConfirmationBody({ If you have any questions, please feel free to reach out to us at{' '} {contactEmail} diff --git a/src/lib/email/templates/inquiry-sales-notification.tsx b/src/lib/email/templates/inquiry-sales-notification.tsx index 8d95c28b..2e13f3cb 100644 --- a/src/lib/email/templates/inquiry-sales-notification.tsx +++ b/src/lib/email/templates/inquiry-sales-notification.tsx @@ -1,7 +1,7 @@ import { Link, Text, render } from '@react-email/components'; import * as React from 'react'; -import { brandingPrimaryColor, renderShell, type BrandingShell } from '@/lib/email/shell'; +import { brandingPrimaryColor, renderShell, safeUrl, type BrandingShell } from '@/lib/email/shell'; export interface InquirySalesNotificationData { fullName: string; @@ -55,7 +55,7 @@ function SalesNotificationBody({ Please visit the{' '} - + {portName} CRM {' '} to view more information. diff --git a/src/lib/email/templates/residential-inquiry.tsx b/src/lib/email/templates/residential-inquiry.tsx index a3393244..7458023f 100644 --- a/src/lib/email/templates/residential-inquiry.tsx +++ b/src/lib/email/templates/residential-inquiry.tsx @@ -39,7 +39,7 @@ function ClientConfirmationBody({ If you have any questions in the meantime, please reach us at{' '} {contactEmail}