Possible URL spoofing on wildcard path in unjs/h3
Reported on
May 15th 2023
Description
H3 provides the getRequestURL
utility using the new URL(a, b)
constructor. When variable a
is attacker-controlled the origin of the resulting URL can be modified.
Proof of Concept
// index.js
import { listen } from "listhen";
import {
createApp,
createRouter,
eventHandler,
toNodeListener,
getRequestURL,
} from "../src";
const app = createApp()
const router = createRouter().get("/**", eventHandler((event) =>getRequestURL(event)))
app.use(router);
listen(toNodeListener(app));
Make request to http://localhost:3000//attacker.com/test
Output is "http://attacker.com/test"
Impact
The origin of the output URL cannot be trusted.
Highly context dependant, if used to make requests server-side then SSRF is possible.
Here's another report where I abuse a similar issue for CSRF.
Could be possible to chain into more severe bugs.
Nuxt3 imports this utility on the master branch, but no current usage.
Occurrences
request.ts L106
new URL(a, b)
can be vulnerable.
Thanks for the early report about this issue.
This is a valid case however as you mentioned, the possibility of SSRF when using this utility is context-dependent and users are expected to validate URLs. (for nuxt and nitro, it is also only being introduced as an opt-in feature not for internal routing)
I have made an alternative patch for fix without relative paths which could be used to exploit in conjunction with headers forgery on x-forwared-host
by always normalizing double slashes on URLs (https://github.com/unjs/h3/commit/b5d2972a8ee2ebda37815db5426d16cc35fd47ad)
The patch release h3@1.6.6
also contains more measurements to make x-forwarded-host
support opt-in.
Even though I could not find any more vulnerabilities, feel free to test and report if there is a possible bug with opt-in feature.
https://github.com/unjs/h3/releases/tag/v1.6.6