fix(route-rules): reject out-of-scope requests#4222
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughAdds path scope validation to prevent directory traversal attacks in route rules. A new Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
commit: |
Mirrors the scope check added for proxy rules. An encoded traversal like `..%2f` bypasses the `/**` scope at match time but can escape the base once the redirect target decodes `%2f` → `/`, letting a victim's browser reach a sibling scope on the redirect host.
A proxy route rule like
/api/orders/**: { proxy: { to: "http://upstream/orders/**" } }could be bypassed by requesting..%2fthe encoded slash stayed opaque at match time, so Nitro matched the/**scope and forwarded the raw path to the upstream, which decoded%2f → /and escaped the intended scope.Note
This depends on how the upstream interprets
%2F. Frameworks that honor RFC 3986 and treat%2Fas opaque within path segments are already safe (including Express, H3, and Hono).The fix also assumes the upstream does not double-decode percent-encoding:
%252Fstays opaque after canonicalization, so an upstream that decodes twice (%252F → %2F → /) could still be coaxed into escaping the scope. Single-decode is standard behavior.Fix
Before building the upstream URL in the proxy route rule, canonicalize the incoming pathname and verify it still falls under the rule's base path. If not, respond with
400 Bad Requestinstead of proxying. The bytes forwarded upstream are unchanged when the request is allowed — only rejection behavior is new.Canonicalization uses
new URL:%2Fand%5Care pre-decoded (WHATWG URL keeps them opaque in paths), then URL parsing resolves./../%2E%2Esegments and normalizes\.e2e reproduction:
backend.mjsnitro.config.ts