Skip to content

fix: correct path traversal check to allow '...' in URL path segments#461

Merged
mcollina merged 2 commits intofastify:mainfrom
q0rban:fix/buildurl-false-positive-dotdot
Mar 11, 2026
Merged

fix: correct path traversal check to allow '...' in URL path segments#461
mcollina merged 2 commits intofastify:mainfrom
q0rban:fix/buildurl-false-positive-dotdot

Conversation

@q0rban
Copy link
Copy Markdown
Contributor

@q0rban q0rban commented Mar 9, 2026

Summary

Fixes #460

The path traversal check in buildURL uses includes('..') which incorrectly rejects URLs containing ... (three dots) as part of a filename or route name, for example, Next.js catch-all routes like [...slug], which appear percent-encoded as %5B...slug%5D in static chunk URLs.

This PR replaces the check with a more precise one that only flags .. when it appears as a complete path segment (surrounded by / or at a string boundary).

// Before
if (decodeURIComponent(source).includes('..')) {

// After
const decoded = decodeURIComponent(source)
if (decoded === '..' || decoded.includes('/..') || decoded.includes('../')) {

The fix is intentionally structured for performance: === is checked first as the cheapest comparison, followed by two includes calls that short-circuit. We considered a regex approach (/(?:^|\/)\.\.(?:\/|$)/) but benchmarking showed includes runs 2–3x faster for typical URL lengths.

All existing path traversal test cases continue to pass.

Next.js catch-all routes like '[...slug]' appear percent-encoded as
'%5B...slug%5D' in static chunk URLs. These contain '...' as a substring
but are not path traversal and should not be rejected.

See: fastify#460
@q0rban
Copy link
Copy Markdown
Contributor Author

q0rban commented Mar 9, 2026

To start, I am only pushing up the test change. The unit test should fail. Once we've shown that, I will push up the fix. I just need a maintainer to approve the GHA workflow run.

@mcollina
Copy link
Copy Markdown
Member

go ahead and keep going with the implementation

The previous check used includes('..') which incorrectly rejects URLs
containing '...' as part of a filename or route name, such as Next.js
catch-all routes like '[...slug]' (%5B...slug%5D when percent-encoded).

Replace with a targeted check that only flags '..' when it appears as a
complete path segment (surrounded by '/' or at a string boundary).

Fixes: fastify#460
@q0rban
Copy link
Copy Markdown
Contributor Author

q0rban commented Mar 10, 2026

Pushed up the proposed fix.

Copy link
Copy Markdown
Member

@mcollina mcollina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@mcollina mcollina merged commit 456a7e3 into fastify:main Mar 11, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Regression: buildURL false positive rejects legitimate URLs containing '...' (e.g. Next.js catch-all routes)

2 participants