[PR #821] [MERGED] fix: use segment-based domain matching for CSRF origin wildcard patterns #871

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

📋 Pull Request Information

Original PR: https://github.com/cloudflare/vinext/pull/821
Author: @southpolesteve
Created: 4/11/2026
Status: Merged
Merged: 4/12/2026
Merged by: @james-elicx

Base: mainHead: fix/csrf-origin-wildcard-matching


📝 Commits (1)

  • a091e1f fix: use segment-based domain matching for CSRF origin wildcard patterns

📊 Changes

2 files changed (+123 additions, -6 deletions)

View changed files

📝 packages/vinext/src/server/request-pipeline.ts (+47 -6)
📝 tests/shims.test.ts (+76 -0)

📄 Description

Summary

Replace suffix-based wildcard origin matching with proper segment-by-segment DNS domain matching for server action CSRF origin validation.

Details

isOriginAllowed() used String.endsWith() for wildcard patterns, so *.example.com would match any hostname ending with .example.com, including evil.example.com.attacker.com.

The new matchWildcardDomain() implementation splits both domain and pattern by . and compares segment-by-segment from right to left:

  • * matches exactly one DNS label
  • ** matches one or more DNS labels
  • wildcards are blocked from matching entire domains (* or ** alone)
  • matching is case-insensitive per RFC 1035

Ported from Next.js:

Tests

12 unit tests ported from Next.js covering:

  • exact match
  • single-level wildcard (*)
  • multi-level wildcard (**)
  • non-matching TLD and unrelated domains
  • empty/undefined patterns
  • wildcards blocked at domain level
  • case-insensitive matching (RFC 1035)
  • localhost patterns
  • attacker-controlled suffix domains (the regression case)

🔄 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/821 **Author:** [@southpolesteve](https://github.com/southpolesteve) **Created:** 4/11/2026 **Status:** ✅ Merged **Merged:** 4/12/2026 **Merged by:** [@james-elicx](https://github.com/james-elicx) **Base:** `main` ← **Head:** `fix/csrf-origin-wildcard-matching` --- ### 📝 Commits (1) - [`a091e1f`](https://github.com/cloudflare/vinext/commit/a091e1f74de9180610eb5b25372267717ffc5d68) fix: use segment-based domain matching for CSRF origin wildcard patterns ### 📊 Changes **2 files changed** (+123 additions, -6 deletions) <details> <summary>View changed files</summary> 📝 `packages/vinext/src/server/request-pipeline.ts` (+47 -6) 📝 `tests/shims.test.ts` (+76 -0) </details> ### 📄 Description ## Summary Replace suffix-based wildcard origin matching with proper segment-by-segment DNS domain matching for server action CSRF origin validation. ## Details `isOriginAllowed()` used `String.endsWith()` for wildcard patterns, so `*.example.com` would match any hostname ending with `.example.com`, including `evil.example.com.attacker.com`. The new `matchWildcardDomain()` implementation splits both domain and pattern by `.` and compares segment-by-segment from right to left: - `*` matches exactly one DNS label - `**` matches one or more DNS labels - wildcards are blocked from matching entire domains (`*` or `**` alone) - matching is case-insensitive per RFC 1035 Ported from Next.js: - [`csrf-protection.ts`](https://github.com/vercel/next.js/blob/canary/packages/next/src/server/app-render/csrf-protection.ts) - [`csrf-protection.test.ts`](https://github.com/vercel/next.js/blob/canary/packages/next/src/server/app-render/csrf-protection.test.ts) ## Tests 12 unit tests ported from Next.js covering: - exact match - single-level wildcard (`*`) - multi-level wildcard (`**`) - non-matching TLD and unrelated domains - empty/undefined patterns - wildcards blocked at domain level - case-insensitive matching (RFC 1035) - localhost patterns - attacker-controlled suffix domains (the regression case) --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
BreizhHardware 2026-05-06 13:10:34 +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#871
No description provided.