[PR #505] [MERGED] fix: escape XML special characters in sitemap generation #627

Closed
opened 2026-05-06 13:09:10 +02:00 by BreizhHardware · 0 comments

📋 Pull Request Information

Original PR: https://github.com/cloudflare/vinext/pull/505
Author: @NathanDrake2406
Created: 3/12/2026
Status: Merged
Merged: 3/12/2026
Merged by: @james-elicx

Base: mainHead: fix/sitemap-xml-escaping


📝 Commits (1)

  • 15a6d5d fix: escape XML special characters in sitemap generation

📊 Changes

2 files changed (+78 additions, -20 deletions)

View changed files

📝 packages/vinext/src/server/metadata-routes.ts (+24 -12)
📝 tests/metadata-routes.test.ts (+54 -8)

📄 Description

Summary

  • sitemapToXml() interpolated user-supplied values directly into XML without escaping
  • URLs with & (extremely common with query params like ?q=a&b=2) produced invalid XML
  • Video titles/descriptions with <, >, ", or & also broke the XML structure
  • Search engines silently reject malformed sitemaps, causing invisible SEO loss

Fix

Add escapeXml() helper that handles all five XML special characters (& < > " ') and apply it to every user-supplied string value in the sitemap serializer: URLs, alternate hrefs, hreflang values, image locs, video titles/descriptions/tags/URLs, uploader names/info, restriction/platform attributes.

Numeric fields (duration, view_count, rating) and controlled enums (family_friendly, live) are left unescaped since they can't contain XML-special characters.

This intentionally diverges from Next.js's resolveSitemap() which also raw-interpolates. The existing parity test "matches Next's raw interpolation for XML-sensitive values" has been updated to assert correct XML escaping instead.

Test plan

  • New test: URLs with & produce &amp; in <loc>, <image:loc>, and href attributes
  • New test: video fields with &, <, >, " are properly escaped
  • Updated existing XML-sensitive values test to expect correct escaping
  • All 54 metadata-routes tests pass
  • Sitemap-related shim tests pass
  • CI: full Vitest + Playwright suite

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/cloudflare/vinext/pull/505 **Author:** [@NathanDrake2406](https://github.com/NathanDrake2406) **Created:** 3/12/2026 **Status:** ✅ Merged **Merged:** 3/12/2026 **Merged by:** [@james-elicx](https://github.com/james-elicx) **Base:** `main` ← **Head:** `fix/sitemap-xml-escaping` --- ### 📝 Commits (1) - [`15a6d5d`](https://github.com/cloudflare/vinext/commit/15a6d5d8f5fd6793bfbe6b94f5932bacfb3b1760) fix: escape XML special characters in sitemap generation ### 📊 Changes **2 files changed** (+78 additions, -20 deletions) <details> <summary>View changed files</summary> 📝 `packages/vinext/src/server/metadata-routes.ts` (+24 -12) 📝 `tests/metadata-routes.test.ts` (+54 -8) </details> ### 📄 Description ## Summary - `sitemapToXml()` interpolated user-supplied values directly into XML without escaping - URLs with `&` (extremely common with query params like `?q=a&b=2`) produced invalid XML - Video titles/descriptions with `<`, `>`, `"`, or `&` also broke the XML structure - Search engines silently reject malformed sitemaps, causing invisible SEO loss ## Fix Add `escapeXml()` helper that handles all five XML special characters (`&` `<` `>` `"` `'`) and apply it to every user-supplied string value in the sitemap serializer: URLs, alternate hrefs, hreflang values, image locs, video titles/descriptions/tags/URLs, uploader names/info, restriction/platform attributes. Numeric fields (duration, view_count, rating) and controlled enums (family_friendly, live) are left unescaped since they can't contain XML-special characters. This intentionally diverges from Next.js's `resolveSitemap()` which also raw-interpolates. The existing parity test "matches Next's raw interpolation for XML-sensitive values" has been updated to assert correct XML escaping instead. ## Test plan - [x] New test: URLs with `&` produce `&amp;` in `<loc>`, `<image:loc>`, and `href` attributes - [x] New test: video fields with `&`, `<`, `>`, `"` are properly escaped - [x] Updated existing XML-sensitive values test to expect correct escaping - [x] All 54 metadata-routes tests pass - [x] Sitemap-related shim tests pass - [ ] CI: full Vitest + Playwright suite --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
BreizhHardware 2026-05-06 13:09:10 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/vinext#627
No description provided.