mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-19 17:46:36 +03:00
Fix /source guard escaping the project root via sibling directories
The /source route confined paths with `absPath.startsWith(process.cwd())`, a string-prefix check with no separator. An absolute request path to a sibling directory whose name extends the project dir name (projeto -> projeto-backup) shared the prefix and was served. Switch to the relative-path check already used by sessionFileMetadataFromPollReply: reject when the relative path is empty (the root dir itself, never a file this route serves), starts with `..`, or is absolute. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
762ffd08b2
commit
da2982ab95
@@ -846,7 +846,13 @@ function createRequestHandler({ detectScript, liveScriptParts }) {
|
||||
const filePath = url.searchParams.get('path');
|
||||
if (!filePath || filePath.includes('..')) { res.writeHead(400); res.end('Bad path'); return; }
|
||||
const absPath = path.resolve(process.cwd(), filePath);
|
||||
if (!absPath.startsWith(process.cwd())) { res.writeHead(403); res.end('Forbidden'); return; }
|
||||
// Confine to the project root. A bare `startsWith(cwd)` string check lets a
|
||||
// sibling dir whose name extends the root name (projeto -> projeto-backup)
|
||||
// slip through; compare on the relative path instead (same pattern as
|
||||
// sessionFileMetadataFromPollReply below). An empty rel means the request
|
||||
// resolved to the root directory itself, which this file route never serves.
|
||||
const rel = path.relative(process.cwd(), absPath);
|
||||
if (!rel || rel.startsWith('..') || path.isAbsolute(rel)) { res.writeHead(403); res.end('Forbidden'); return; }
|
||||
let content;
|
||||
try { content = fs.readFileSync(absPath, 'utf-8'); }
|
||||
catch { res.writeHead(404); res.end('File not found'); return; }
|
||||
|
||||
Reference in New Issue
Block a user