Skip to content

fix(sandbox): deny host-path Playwright protocol params (#109)#113

Open
kimjune01 wants to merge 2 commits into
SawyerHood:mainfrom
kimjune01:fix/sandbox-path-deny
Open

fix(sandbox): deny host-path Playwright protocol params (#109)#113
kimjune01 wants to merge 2 commits into
SawyerHood:mainfrom
kimjune01:fix/sandbox-path-deny

Conversation

@kimjune01

@kimjune01 kimjune01 commented May 18, 2026

Copy link
Copy Markdown

Fixes #109.

Deny three Playwright wire-level params at HostBridge.receiveFromSandbox — the only host-fs holes that aren't already blocked by the QuickJS client platform's fs/path throws or by denyLaunch: true. Verified against playwright-core 1.58.2.

method param(s) direction
setInputFiles localPaths, localDirectory server reads
saveAs path server writes
harOpen file server reads

The screenshot/pdf/storageState/addScriptTag/addStyleTag/fulfill/tracing scenarios in #109 are already non-exploitable — those path params don't exist in the wire schema; the client writes/reads via its platform fs adapter, which throws in QuickJS. This PR blocks the remaining path: a script that reaches the underlying connection (e.g. page._connection) and crafts the raw message itself.

Attestation

Identical test file on both commits; only host-bridge.ts differs.

state commit result
before c58b79a (attest/before-fix) 2 failed, 9 passed
after 6c004d3 (this PR) 11 passed

Full suite on the fix commit (after pnpm bundle:sandbox-client): 15/15 files, 98/98 tests pass — including the live-browser integration tests, confirming legitimate Playwright flows are unaffected.

git remote add kimjune01 https://github.com/kimjune01/dev-browser.git && git fetch kimjune01
git checkout c58b79a && (cd daemon && pnpm install && pnpm vitest run src/sandbox/__tests__/sandbox-policy.test.ts)
git checkout 6c004d3 && (cd daemon && pnpm vitest run src/sandbox/__tests__/sandbox-policy.test.ts)

Before-fail output (the proof — message reaches the dispatcher):

AssertionError: expected 'TargetClosedError' to be 'Error'

Notes

  • Deny-list, not allow-list — small and reversible, but brittle against future protocol additions.
  • daemon/dist/* bundles not regenerated; left for release tooling.
  • The integration test hits the wire-level chokepoint directly, not via a guest script. Auditing every way a sandbox script can reach ChannelOwner._channel is a separate, larger attack-surface question and out of scope here.

Found by Codex (GPT-5.5) via /bug-hunt.

kimjune01 and others added 2 commits May 18, 2026 12:50
Add HostBridge-level deny-list for protocol messages that carry host
filesystem paths (screenshot path, pdf path, storageState path, add{Script,Style}Tag path,
setInputFilePaths localPaths, saveAs path, fulfill path, tracingStart tracesDir,
tracingStop path, tracingStopChunk filePath, harOpen file). These are
blocked before reaching the host-side Playwright dispatcher, with a
policy error returned to the sandbox.

Bug reported in SawyerHood#109. Found by Codex (GPT-5.5) via /bug-hunt.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…stBridge integration tests

Verified against playwright-core 1.58.2 protocol/validator.js. Of the 12
(method, param) pairs in the initial deny-list, only 3 are actually
reachable via the wire (the rest are client-side path params already
blocked by the QuickJS platform's fs/path throws):

- setInputFiles localPaths / localDirectory  (server-side read)
- saveAs path                                 (server-side write)
- harOpen file                                (server-side read)

Add HostBridge integration tests that prove the policy intercepts these
messages before they reach the Playwright dispatcher. Without the policy
the same messages reach the dispatcher and come back as TargetClosedError
(see PR description for failing-before output).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sandbox escape: Playwright path APIs let scripts read/write arbitrary host files

1 participant