diff --git a/src/utils/repo-path.ts b/src/utils/repo-path.ts index 8f6da3605..e47bfc7a4 100644 --- a/src/utils/repo-path.ts +++ b/src/utils/repo-path.ts @@ -11,16 +11,16 @@ export function isValidRepoPath(path: string) { return false } - if ( - path.startsWith('/') || - path.endsWith('/') || - path.includes('//') || - path.includes('..') - ) { + if (path.startsWith('/') || path.endsWith('/') || path.includes('//')) { return false } return path.split('/').every((segment) => { + // Reject only actual relative path segments, not names like `[...404].tsx` + if (segment === '.' || segment === '..') { + return false + } + return REPO_PATH_SEGMENT_PATTERN.test(segment) }) } diff --git a/tests/repo-path.test.ts b/tests/repo-path.test.ts index 762a500ef..8bf26f8b1 100644 --- a/tests/repo-path.test.ts +++ b/tests/repo-path.test.ts @@ -36,6 +36,38 @@ assert.equal( 'traversal is rejected', ) +assert.equal( + isValidRepoPath( + 'examples/solid/solid-start-streaming/src/routes/[...404].tsx', + ), + true, + 'catch-all route files with spread notation are valid repo path segments', +) + +assert.equal( + isValidRepoPath('examples/svelte/basic/src/routes/[...slug]/+page.svelte'), + true, + 'catch-all route directories with spread notation are valid repo path segments', +) + +assert.equal( + isValidRepoPath('src/../routes/__root.tsx'), + false, + 'nested traversal is rejected', +) + +assert.equal( + isValidRepoPath('src/routes/..'), + false, + 'trailing traversal is rejected', +) + +assert.equal( + isValidRepoPath('src/./routes/__root.tsx'), + false, + 'current-directory segments are rejected', +) + assert.equal( isValidRepoPath('src/routes//__root.tsx'), false,