CVE-2026-15074: @fastify/static Route Guard Bypass via Dot-Dot Path Traversal
A flaw in @fastify/static lets attackers sneak dot-dot path segments past route-level authentication guards to read protected static files, without ever leaving the configured static root.

The problem
@fastify/static versions up to and including 10.1.0 do not reject .. or %2E%2E segments before resolving a file path. The router (find-my-way) does not normalize these segments during route matching, so a request like /foo/../deep/secret.txt hits the plugin's catch-all instead of the protected /deep/* route.
This is a bypass of the earlier fix for GHSA-x428-ghpx-8j92 (CVE-2026-6414). That fix only blocked encoded slashes (%2F). Dot-dot segments survive the decodeURI + encodeURI round-trip intact and are collapsed silently by @fastify/send's internal path.normalize, defeating any route-scoped middleware or guard that ran before the file is served.
The impact is limited to route-guard bypass within the configured static root. An attacker cannot escape the root directory using this bug alone, but they can read files under a path prefix that should have been blocked by middleware.
Proof of concept
A working proof-of-concept for CVE-2026-15074 in @fastify/static, with the exact payload below.
GET /public/../deep/secret.txt HTTP/1.1
Host: target.example.com
# Percent-encoded variant also works:
GET /public/%2E%2E/deep/secret.txt HTTP/1.1
Host: target.example.comThe getPathnameForSend helper (introduced to fix the prior %2F bypass) ran decodeURI then encodeURI on the incoming pathname. Both .. and %2E%2E survive that round-trip unchanged because they contain no characters that encodeURI encodes, so neither form was stripped.
Downstream, @fastify/send calls path.normalize on the pathname before its own traversal guard, which collapses foo/../deep into deep. By then, route-level guards have already run against the original un-normalized URL and did not match /deep/*, so access control is silently skipped.
The patch adds an explicit check in getPathnameForSend to detect and reject any pathname containing .. or %2E%2E segments before the path ever reaches @fastify/send, closing the gap that the previous fix left open. CWE-22 (Improper Limitation of a Pathname to a Restricted Directory).
The fix
Upgrade @fastify/static to version 10.1.1. If you cannot upgrade immediately, do not rely on Fastify route-based middleware or guards to protect files served by @fastify/static; move that logic into the static plugin's own allowedPath callback or a server-level hook that runs after normalization.
Reported by imssm99.
Related research
- high · 7.5CVE-2026-82393CVE-2026-82393: pnpm Scoped-Name Path Traversal Arbitrary File Write
- high · 7.1CVE-2026-82392CVE-2026-82392: pnpm Virtual Store Linker Path Traversal via Crafted Lockfile
- high · 7.1CVE-2026-62680CVE-2026-62680: Orval Generation-Time SSRF and Local File Inclusion via Unvalidated $ref
- high · 7.1pnpm pacquet: Trust-Lockfile Dependency Alias Path Traversal