Version: 4.0.0-alpha.10 (confirmed on HEAD)
File: skill/scripts/live-server.mjs:848-849
const absPath = path.resolve(process.cwd(), filePath);
if (!absPath.startsWith(process.cwd())) { res.writeHead(403); res.end('Forbidden'); return; }
Issue. startsWith on path strings, without requiring a separator, accepts any sibling directory whose name starts with the project directory's name. With the live server running in /home/u/projeto:
| Requested path |
startsWith('/home/u/projeto') |
Result |
/home/u/projeto-backup/.env |
true |
200 — served |
/home/u/projetoEVIL/secret.txt |
true |
200 — served |
Impact. Low on its own: it needs the live server running and a caller willing to pass a path outside the root. But it composes with #304 — anyone who lifts the token from /live.js reaches these neighbouring directories too, not just the project. Sibling directories like myapp-backup/, myapp-old/ or myapp.bak/ are exactly where people keep copies with credentials in them.
Fix. The correct pattern is already used elsewhere in the same file, at lines 1069-1070:
const rel = path.relative(process.cwd(), full);
if (!rel || rel.startsWith('..') || path.isAbsolute(rel)) return base;
Applying that same check to the /source handler fixes it with no new dependency and no behaviour change for legitimate paths.
(Downstream we also block dotfiles on that route, but that's a policy choice rather than a fix for this bug.)
Found while auditing the vendored skill in a project that keeps it under version control.
Version: 4.0.0-alpha.10 (confirmed on HEAD)
File:
skill/scripts/live-server.mjs:848-849Issue.
startsWithon path strings, without requiring a separator, accepts any sibling directory whose name starts with the project directory's name. With the live server running in/home/u/projeto:startsWith('/home/u/projeto')/home/u/projeto-backup/.envtrue/home/u/projetoEVIL/secret.txttrueImpact. Low on its own: it needs the live server running and a caller willing to pass a path outside the root. But it composes with #304 — anyone who lifts the token from
/live.jsreaches these neighbouring directories too, not just the project. Sibling directories likemyapp-backup/,myapp-old/ormyapp.bak/are exactly where people keep copies with credentials in them.Fix. The correct pattern is already used elsewhere in the same file, at lines 1069-1070:
Applying that same check to the
/sourcehandler fixes it with no new dependency and no behaviour change for legitimate paths.(Downstream we also block dotfiles on that route, but that's a policy choice rather than a fix for this bug.)
Found while auditing the vendored skill in a project that keeps it under version control.