Skip to content

fix(markdown,font): sanitize HTML attributes and CSS values to prevent XSS and injection#2959

Open
Dozie2001 wants to merge 1 commit intoresend:canaryfrom
Dozie2001:fix/security-xss-css-injection-escaping
Open

fix(markdown,font): sanitize HTML attributes and CSS values to prevent XSS and injection#2959
Dozie2001 wants to merge 1 commit intoresend:canaryfrom
Dozie2001:fix/security-xss-css-injection-escaping

Conversation

@Dozie2001
Copy link

@Dozie2001 Dozie2001 commented Feb 15, 2026

Summary

Fixes 5 security vulnerabilities found in the @react-email/markdown and @react-email/font packages:

  1. XSS via Markdown link hrefhref in the link renderer was interpolated into HTML without any escaping, allowing attribute injection.
  2. XSS via Markdown title attribute — Both image and link title attributes were inserted raw, enabling event handler injection (e.g. "onmouseover=alert(1)).
  3. XSS via Markdown code blocks — Content inside fenced code blocks was rendered as raw HTML, so <script> tags would execute.
  4. CSS injection via Font component — All Font props (fontFamily, fontStyle, fontWeight, fallbackFontFamily, webFont.url/format) were interpolated directly into <style dangerouslySetInnerHTML> without sanitization.
  5. Wrong HTML entity in CSS quote escapingescapeQuotes() in parse-css-in-js-to-inline-css.ts replaced " with &#x27; (single quote entity) instead of &quot; (double quote entity), producing incorrect CSS values.

Changes

packages/markdown/src/markdown.tsx

  • Added escapeHtml() utility that escapes &, <, >, ", '
  • Applied escapeHtml() to link href, link title, image src, image alt, image title, and code block text

packages/markdown/src/utils/parse-css-in-js-to-inline-css.ts

  • Fixed &#x27;&quot; in escapeQuotes()

packages/font/src/font.tsx

  • Added sanitizeCssValue() that strips ' ; { } \ < > characters
  • Applied to all values interpolated into the <style> tag: fontFamily, fontStyle, fontWeight, fallbackFontFamily, webFont.url, webFont.format

packages/markdown/src/markdown.spec.tsx

  • Updated inline snapshot to reflect corrected &quot; entity

Test plan

  • Existing @react-email/markdown tests pass with updated snapshots
  • Existing @react-email/font tests pass (no snapshot changes needed)
  • Verify markdown with special characters in links, titles, and code blocks renders safely
  • Verify Font component with normal font families renders correctly
  • Verify CSS custom styles with quoted values (e.g. font-family: "Roobert PRO") use &quot; not &#x27;

Summary by cubic

Sanitizes markdown attributes and Font CSS values to block XSS and CSS injection. Also fixes quote escaping to use " in inline CSS.

  • Bug Fixes
    • Escape HTML in markdown: link href/title, image src/alt/title, and fenced code text.
    • Sanitize Font props before injecting CSS by stripping unsafe characters from fontFamily, fontStyle, fontWeight, fallbackFontFamily, webFont.url/format.
    • Replace incorrect ' with " for double quotes in CSS; updated snapshot.

@changeset-bot
Copy link

changeset-bot bot commented Feb 15, 2026

⚠️ No Changeset found

Latest commit: a5293b0

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel
Copy link

vercel bot commented Feb 15, 2026

@Dozie2001 is attempting to deploy a commit to the resend Team on Vercel.

A member of the Team first needs to authorize it.

@Dozie2001 Dozie2001 closed this Feb 15, 2026
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 4 files

Confidence score: 2/5

  • User-impacting security risk in packages/markdown/src/markdown.tsx: hrefs allow javascript: and other executable schemes, enabling XSS despite HTML escaping.
  • Functional regression risk in packages/font/src/font.tsx: sanitizeCssValue strips semicolons, which can corrupt data URLs and break embedded fonts.
  • Pay close attention to packages/markdown/src/markdown.tsx and packages/font/src/font.tsx - unsafe URL handling and data URL corruption.
Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/markdown/src/markdown.tsx">

<violation number="1" location="packages/markdown/src/markdown.tsx:121">
P1: Link hrefs are only HTML-escaped; dangerous schemes like `javascript:` remain valid and allow XSS. Escaping does not prevent executable URL protocols.</violation>
</file>

<file name="packages/font/src/font.tsx">

<violation number="1" location="packages/font/src/font.tsx:62">
P2: sanitizeCssValue strips semicolons from webFont.url, which corrupts valid data URLs (e.g., data:font/woff;base64,...) and other URLs that rely on semicolons, breaking embedded fonts.</violation>
</file>

Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Add one-off context when rerunning by tagging @cubic-dev-ai with guidance or docs links (including llms.txt)
  • Ask questions if you need clarification on any suggestion

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.


return `<a href="${href}" target="_blank"${
title ? ` title="${title}"` : ''
return `<a href="${escapeHtml(href)}" target="_blank"${
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Link hrefs are only HTML-escaped; dangerous schemes like javascript: remain valid and allow XSS. Escaping does not prevent executable URL protocols.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/markdown/src/markdown.tsx, line 121:

<comment>Link hrefs are only HTML-escaped; dangerous schemes like `javascript:` remain valid and allow XSS. Escaping does not prevent executable URL protocols.</comment>

<file context>
@@ -109,8 +118,8 @@ export const Markdown = React.forwardRef<HTMLDivElement, MarkdownProps>(
 
-      return `<a href="${href}" target="_blank"${
-        title ? ` title="${title}"` : ''
+      return `<a href="${escapeHtml(href)}" target="_blank"${
+        title ? ` title="${escapeHtml(title)}"` : ''
       }${
</file context>


const src = webFont
? `src: url(${webFont.url}) format('${webFont.format}');`
? `src: url(${sanitizeCssValue(webFont.url)}) format('${sanitizeCssValue(webFont.format)}');`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: sanitizeCssValue strips semicolons from webFont.url, which corrupts valid data URLs (e.g., data:font/woff;base64,...) and other URLs that rely on semicolons, breaking embedded fonts.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/font/src/font.tsx, line 62:

<comment>sanitizeCssValue strips semicolons from webFont.url, which corrupts valid data URLs (e.g., data:font/woff;base64,...) and other URLs that rely on semicolons, breaking embedded fonts.</comment>

<file context>
@@ -47,29 +51,28 @@ export const Font: React.FC<Readonly<FontProps>> = ({
+
   const src = webFont
-    ? `src: url(${webFont.url}) format('${webFont.format}');`
+    ? `src: url(${sanitizeCssValue(webFont.url)}) format('${sanitizeCssValue(webFont.format)}');`
     : '';
 
</file context>

@Dozie2001 Dozie2001 reopened this Feb 15, 2026
@pkg-pr-new
Copy link

pkg-pr-new bot commented Feb 15, 2026

Open in StackBlitz

npm i https://pkg.pr.new/resend/react-email/@react-email/font@2959
npm i https://pkg.pr.new/resend/react-email/@react-email/markdown@2959

commit: a5293b0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant