Back to Blog
high SEVERITY4 min read

How Route Guard Bypass via Path Traversal happens in Fastify and how to fix it

A high-severity path traversal vulnerability (CVE-2026-15074) in @fastify/static version 9.0.0 allowed attackers to bypass route guards and access restricted files. The agentchatbus-ts service was upgraded from @fastify/static 9.0.0 to 10.1.2, which includes proper path normalization to prevent directory traversal attacks.

O
By Orbis AppSec
•Technically reviewed by Anupam Mediratta•Published August 23, 2026•Reviewed August 23, 2026

Answer Summary

CVE-2026-15074 is a path traversal vulnerability in @fastify/static (Node.js/Fastify) that allows attackers to bypass route guards by crafting malicious file paths with sequences like `../`. This is classified under CWE-22 (Improper Limitation of a Pathname to a Restricted Directory). The fix involves upgrading @fastify/static from version 9.0.0 to 10.1.2, which implements proper path canonicalization before serving static files.

Vulnerability at a Glance

cweCWE-22
fixUpgrade @fastify/static to version 10.1.2
riskUnauthorized access to sensitive files outside the intended directory
languageTypeScript/Node.js
root causeInsufficient path normalization in @fastify/static 9.0.0
vulnerabilityPath Traversal / Route Guard Bypass

Introduction

In the agentchatbus-ts service, a high-severity vulnerability was discovered in the static file serving layer. The package-lock.json file pinned @fastify/static to version 9.0.0, which contained CVE-2026-15074—a route guard bypass vulnerability that could allow attackers to traverse directories and access files they shouldn't reach.

This matters because agentchatbus-ts likely serves static assets to users through Fastify's static file middleware. When that middleware fails to properly normalize paths, an attacker can craft requests like GET /static/../../../etc/passwd to escape the designated static directory and read arbitrary files from the server's filesystem.

The Vulnerability Explained

What Is Path Traversal?

Path traversal (also called directory traversal) occurs when an application uses user-supplied input to construct file paths without properly validating or sanitizing that input. Attackers exploit this by inserting special sequences like ../ (dot-dot-slash) to navigate up the directory tree.

How @fastify/static 9.0.0 Was Vulnerable

In version 9.0.0, @fastify/static had insufficient path normalization logic. When a request came in for a static file, the library didn't properly canonicalize the path before checking route guards or serving the file. This meant:

// Conceptual vulnerable flow in @fastify/static 9.0.0
// Request: GET /static/../../../sensitive/config.json
// The path "../../../sensitive/config.json" wasn't properly resolved
// Route guards checking "/static/*" patterns were bypassed

The vulnerable dependency in agentchatbus-ts/package.json:

"@fastify/static": "^9.0.0"

Attack Scenario Against agentchatbus-ts

Consider this realistic attack against the agentchatbus-ts service:

  1. Reconnaissance: An attacker discovers the application serves static files at /assets/
  2. Crafting the payload: They send a request like:
    GET /assets/..%2f..%2f..%2f..%2fetc/passwd HTTP/1.1
  3. Bypassing route guards: Because the path isn't normalized before guard checks, middleware protecting routes outside /assets/ doesn't trigger
  4. File exfiltration: The server returns the contents of /etc/passwd or potentially more sensitive files like environment variables, configuration files, or source code

For an agent chat bus service handling AI/ML workloads, exposed files could include:
- API keys for model providers
- Database connection strings
- Internal service credentials
- User conversation logs

The Fix

The fix upgrades @fastify/static from version 9.0.0 to 10.1.2, which includes proper path traversal protections.

Before (Vulnerable)

// agentchatbus-ts/package.json
"@fastify/static": "^9.0.0"

// agentchatbus-ts/package-lock.json
"node_modules/@fastify/static": {
  "version": "9.0.0",
  "resolved": "https://registry.npmjs.org/@fastify/static/-/static-9.0.0.tgz",
  "dependencies": {
    "@fastify/accept-negotiator": "^2.0.0",
    "@fastify/send": "^4.0.0",
    "content-disposition": "^1.0.1",
    "fastify-plugin": "^5.0.0",
    "fastq": "^1.17.1",
    "glob": "^13.0.0"
  }
}

After (Fixed)

// agentchatbus-ts/package.json
"@fastify/static": "^10.1.2"

// agentchatbus-ts/package-lock.json
"node_modules/@fastify/static": {
  "version": "10.1.2",
  "resolved": "https://registry.npmjs.org/@fastify/static/-/static-10.1.2.tgz",
  "dependencies": {
    "@fastify/accept-negotiator": "^2.0.0",
    "@fastify/error": "^4.0.0",
    "@fastify/send": "^4.0.0",
    "content-disposition": "^2.0.1",
    "fastify-plugin": "^6.0.0",
    "fastq": "^1.17.1",
    "glob": "^13.0.0"
  }
}

Key Changes in the Upgrade

  1. New dependency added: @fastify/error (^4.0.0) — provides standardized error handling for security violations
  2. Updated content-disposition: From ^1.0.1 to ^2.0.1 — includes additional header injection protections
  3. Updated fastify-plugin: From ^5.0.0 to ^6.0.0 — better integration with Fastify's security model

The new version implements proper path canonicalization:
- Resolves symbolic links
- Normalizes ../ sequences before any security checks
- Validates the final resolved path stays within the configured root directory
- Returns 403 Forbidden for any traversal attempts

Key Takeaways

  • @fastify/static 9.0.0 allowed path traversal because it didn't normalize paths before checking route guards
  • The agentchatbus-ts service was exposed to potential file exfiltration attacks through its static file serving endpoint
  • Upgrading to @fastify/static 10.1.2 adds proper path canonicalization and the @fastify/error dependency for better security error handling
  • Dependency scanning tools like Trivy can automatically detect vulnerable package versions in package-lock.json
  • Always lock and audit your transitive dependencies — the vulnerability was in a nested dependency that many developers might overlook

How Orbis AppSec Detected This

  • Source: HTTP request path parameter used for static file resolution
  • Sink: @fastify/static file serving handler in agentchatbus-ts
  • Missing control: Path normalization and boundary validation before serving files
  • CWE: CWE-22 (Improper Limitation of a Pathname to a Restricted Directory)
  • Fix: Upgraded @fastify/static from 9.0.0 to 10.1.2, which implements proper path canonicalization

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.

Conclusion

CVE-2026-15074 in @fastify/static demonstrates why dependency management is critical for application security. A single unpatched package can expose your entire filesystem to attackers. The fix was straightforward—a version bump—but the consequences of leaving it unpatched could have been severe for the agentchatbus-ts service.

Regularly audit your dependencies, implement automated vulnerability scanning, and don't rely solely on library security—add defense in depth with application-level path validation.

Prevention and further reading

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #82

Related Articles

high

clean_path() Path Traversal: rel_path Escapes USERDATA Dir

A path traversal flaw in the `clean_path()` helper let a user-controlled `rel_path` value escape the intended USERDATA directory and reach arbitrary files on disk. The function joined path segments without checking the final result, so `../` sequences in route parameters or query strings could be used to read or write files outside the sandboxed storage area. The fix normalizes the path and verifies it still resolves inside the USERDATA root before returning it, raising an error otherwise.

critical

path.resolve() Path Traversal in Node CLI's Dynamic import()

A Node.js CLI script for validating expression definitions took a file path from `process.argv[2]`, resolved it with `path.resolve()`, and passed the result straight into a dynamic `import()` — with no check that the resolved path stayed inside the working directory. An attacker (or a malicious skill/plugin invocation) could supply traversal sequences to load and execute arbitrary `.js` files from anywhere on disk. The fix adds a boundary check with `path.relative()` and an extension allowlist b

high

bookDir() Path Traversal via Unsanitized bookId Parameter

The `bookDir()` function accepted unsanitized `bookId` values derived from user-created book titles, enabling path traversal attacks through `../` sequences. A fix was applied that validates the identifier using `path.basename()` and throws on mismatch, ensuring all resolved paths remain within `LIBRARY_DIR`.

high

Express `app.get('*')` Wildcard Handler Path Traversal in watch.js

A first-party Express server's wildcard route handler used `req.url.indexOf('font.woff2')` to gate access to a font file, allowing attackers to bypass the substring check with crafted paths. The fix replaces the catch-all handler with explicit route registration.

high

updateCardBg() Follows Unvalidated 302 Location Headers

A background-image updater fetched a configured image URL with manual redirect handling and then re-issued the request to whatever `Location` header came back, with no scheme or host checks. A redirect to `http://169.254.169.254/` or `http://127.0.0.1:<port>/` would have been followed with the original fetch options attached, and the response body written to disk as an image asset. The fix resolves the redirect target against `imgDownloadUrl` and rejects anything that is not HTTPS on the same ho

high

markitdown_bridge.py Path Traversal: Arbitrary File Read via sys.argv

The markitdown_bridge.py script, used by MDView for DOCX-to-Markdown conversion, accepted file paths directly from command-line arguments without validating they stayed within intended directories. An attacker could exploit this to read arbitrary files from the filesystem by passing path traversal sequences in the source_path parameter.