Summary
The QuickJS sandbox exposes raw Playwright client objects to guest scripts, and HostBridge.receiveFromSandbox() dispatches any protocol message to the host-side Playwright dispatcher with no method/parameter allowlist. Because several normal Playwright APIs accept host filesystem paths, a guest script can read or write arbitrary host files — directly contradicting the README's "no fs / no direct filesystem access" promise.
⚠️ This is a sandbox-escape security issue. You may prefer to convert this into a private GitHub security advisory rather than leave it public.
Where
daemon/src/sandbox/quickjs-sandbox.ts:422 — waitForConnectionObject() returns unrestricted Playwright Page objects.
daemon/src/sandbox/host-bridge.ts:54 — receiveFromSandbox() dispatches any JSON protocol message to DispatcherConnection.
README.md:181 — advertises these as "full Playwright Page objects".
Reproducer (read arbitrary host file)
const page = await browser.newPage();
await page.setContent('<input type="file" id="f">');
await page.setInputFiles('#f', '/etc/passwd');
const text = await page.evaluate(async () => {
return await document.querySelector('#f').files[0].text();
});
console.log(text);
Other affected APIs (write paths)
page.screenshot({ path: '...' })
locator.screenshot({ path: '...' })
page.context().storageState({ path: '...' })
- any Playwright option that takes a host path
Suggested fix
Don't expose raw Playwright client objects directly. Wrap or filter the API surface so only vetted methods are reachable, and explicitly reject any Playwright call that takes a host-side path or resource handle. If you keep the protocol bridge, add a method/parameter allowlist on the host side before dispatching.
Found via /bug-hunt (codex / gpt-5.4) round 1.
Summary
The QuickJS sandbox exposes raw Playwright client objects to guest scripts, and
HostBridge.receiveFromSandbox()dispatches any protocol message to the host-side Playwright dispatcher with no method/parameter allowlist. Because several normal Playwright APIs accept host filesystem paths, a guest script can read or write arbitrary host files — directly contradicting the README's "no fs / no direct filesystem access" promise.Where
daemon/src/sandbox/quickjs-sandbox.ts:422—waitForConnectionObject()returns unrestricted PlaywrightPageobjects.daemon/src/sandbox/host-bridge.ts:54—receiveFromSandbox()dispatches any JSON protocol message toDispatcherConnection.README.md:181— advertises these as "full Playwright Page objects".Reproducer (read arbitrary host file)
Other affected APIs (write paths)
page.screenshot({ path: '...' })locator.screenshot({ path: '...' })page.context().storageState({ path: '...' })Suggested fix
Don't expose raw Playwright client objects directly. Wrap or filter the API surface so only vetted methods are reachable, and explicitly reject any Playwright call that takes a host-side path or resource handle. If you keep the protocol bridge, add a method/parameter allowlist on the host side before dispatching.
Found via
/bug-hunt(codex / gpt-5.4) round 1.