[BUG] Cowork local sandbox: proxy returns 403 'Connection blocked by network allowlist' for cdn.playwright.dev although it is in the session's default egressAllowedDomains
Preflight Checklist
- [x] I have searched existing issues — closest are #93643 (allowlist ignored, regression since ~2026-09-04) and #38984 ("Additional allowed domains" non-functional). This report differs: the refused host is in the sandbox's default package-manager list, not a custom entry, and it is refused while other entries of the same list pass.
- [x] This is a single bug report
- [x] I am using the latest version (Claude desktop app 2.110.0)
What's Wrong?
Product: Claude desktop app 2.110.0 — Cowork mode, local Linux sandbox on macOS 27.0 (26A428), Apple Silicon. Sandbox: @anthropic-ai/sandbox-runtime, arm64, Node 22.23.2.
Observed: 2026-09-16, in a scheduled-task session (00:26 UTC) and in an interactive session (00:47 UTC) — identical result.
Regression: the same download from the same sandbox worked on 2026-08-27.
Inside the sandbox, npx playwright install chromium-headless-shell fails with HTTP 403 from the egress proxy, body Connection blocked by network allowlist, for both Playwright download hosts — cdn.playwright.dev and playwright.download.prss.microsoft.com. Yet the session's own configuration file (local_<id>.json, field egressAllowedDomains) lists both hosts explicitly, as part of the default list:
"egressAllowedDomains": ["registry.npmjs.org", "npmjs.com", "www.npmjs.com", "npmjs.org", "www.npmjs.org",
"yarnpkg.com", "registry.yarnpkg.com", "pypi.org", "files.pythonhosted.org", "pythonhosted.org",
"github.com", "objects.githubusercontent.com", "archive.ubuntu.com", "security.ubuntu.com",
"crates.io", "index.crates.io", "static.crates.io",
"playwright.download.prss.microsoft.com", "cdn.playwright.dev",
"*.anthropic.com", "anthropic.com", "claude.com", "*.claude.com"]
Other hosts of that same list are reachable through the same proxy in the same session (registry.npmjs.org → 200, github.com → 200, pypi.org → 200), so the allowlist is enforced — just not for these two entries. A bare curl -I https://cdn.playwright.dev/ fails at CONNECT (curl exit 56), so the block is at the domain level, not a path or size limit.
What Should Happen?
Hosts present in the session's egressAllowedDomains should be reachable through the egress proxy. Either the proxy should honour the two Playwright entries of the default list, or the session config should not advertise them.
Error Messages/Logs
$ PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS=1 DEBUG=pw:install npx playwright install chromium-headless-shell 2>&1 | head -8
pw:install downloading Chrome Headless Shell 153.0.8010.12 (playwright chromium-headless-shell v1243) - attempt #1
Downloading Chrome Headless Shell 153.0.8010.12 (playwright chromium-headless-shell v1243) from https://cdn.playwright.dev/builds/cft/153.0.8010.12/linux-arm64/chrome-headless-shell-linux-arm64.zip
pw:install -- response status code: 403
Error: Download failed: server returned code 403 body 'Connection blocked by network allowlist'. URL: https://cdn.playwright.dev/builds/cft/153.0.8010.12/linux-arm64/chrome-headless-shell-linux-arm64.zip
$ PLAYWRIGHT_DOWNLOAD_HOST=https://playwright.download.prss.microsoft.com npx playwright install chromium-headless-shell 2>&1 | head -3
Error: Download failed: server returned code 403 body 'Connection blocked by network allowlist'. URL: https://playwright.download.prss.microsoft.com/builds/cft/153.0.8010.12/linux-arm64/chrome-headless-shell-linux-arm64.zip
$ for u in https://cdn.playwright.dev/ https://playwright.download.prss.microsoft.com/ https://registry.npmjs.org/ https://github.com/; do printf "%-48s " "$u"; curl -s -o /dev/null -m 25 -w "%{http_code}\n" -I "$u" || echo "curl exit $?"; done
https://cdn.playwright.dev/ 000 (curl exit 56)
https://playwright.download.prss.microsoft.com/ 000 (curl exit 56)
https://registry.npmjs.org/ 200
https://github.com/ 200
Steps to Reproduce
- Start any Cowork session with the local sandbox (macOS).
mkdir -p ~/browser && cd ~/browser && npm install --silent playwright(npm registry is reachable; installs 1.63.0).PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS=1 DEBUG=pw:install npx playwright install chromium-headless-shell 2>&1 | head -8- Compare with
curl -sI https://registry.npmjs.org/(200) andcurl -sI https://cdn.playwright.dev/(refused) in the same shell.
Claude Model
Opus
Is this a regression?
Yes
Last Working Version
Worked on 2026-08-27 (desktop app version at that date not recorded).
Claude Code Version
Claude desktop app 2.110.0
Platform
Claude.ai (Pro)
Operating System
macOS
Terminal/Shell
Other
Additional Information
Impact: any Cowork task that renders HTML for a visual check (scheduled reports, dashboards, a daily brief) can no longer obtain a browser and silently degrades to a CSS-partial fallback (WeasyPrint). Note for others hitting this: Playwright's installer hides the cause unless run with DEBUG=pw:install, and the useful line is at the head of the output, not the tail.
Workaround in use: download the exact Chrome-for-Testing headless-shell zip outside the sandbox, keep it in a mounted folder, and unpack it into ~/.cache/ms-playwright/chromium_headless_shell-<rev>/… with an INSTALLATION_COMPLETE marker so playwright treats it as installed. Works, but defeats the point of the allowlist entries.
Full diagnostic log (proxy environment minus credentials, curl probes, complete pw:install debug output) available on request.
3 Comments
Additional data point that narrows this down (same machine, same day, 2026-09-16 01:52 UTC):
The refusal only happens in the default "Package managers only" allowlist mode. After switching Settings → Capabilities → Domain allowlist to "All domains" and starting a fresh Cowork session, the exact same command succeeds:
curl -sI https://cdn.playwright.dev/builds/cft/153.0.8010.12/linux-arm64/chrome-headless-shell-linux-arm64.zip→307tostorage.googleapis.com/chrome-for-testing-public/…, i.e. the CDN's normal behaviour. Also in "All domains" mode thehttp_proxy/https_proxy/ALL_PROXYvariables are absent from the sandbox environment, whereas in "Package managers only" mode they point at the egress proxy that returns the 403.So the two Playwright hosts are advertised in
egressAllowedDomainsin "Package managers only" mode but not actually honoured by that mode's proxy; in "All domains" mode there is no proxy in the path and the download works. (Playwright's redirect targetstorage.googleapis.comis not in the default list either — if the proxy follows the client through the 307, that host would need to be allowed too.)Unrelated:
playwright.download.prss.microsoft.comreturns a plain 403 from the server itself forbuilds/cft/…paths in both modes (no "network allowlist" body) — that mirror just doesn't serve Chrome-for-Testing builds, so the fallback host would not help even if the proxy were fixed.I've switched back to "Package managers only" for the narrower egress and am working around it by seeding the browser zip from outside the sandbox.
One more observation that may help whoever looks at the proxy side — offered as data, not as a diagnosis.
In "Package managers only" mode, the proxy URL injected into the sandbox environment (
http_proxy,https_proxy,ALL_PROXY,CLOUDSDK_PROXY_USERNAME, …) carries a username of the formsrt.<base64>, and the base64 decodes to the exact command line that was launched in that bash call (here:bash -c 'bash "$(ls -d /sessions/*/mnt/…)/_sandbox/diag-playwright.sh"'). Two runs of the same script from different bash invocations got different usernames matching their respective command lines. So the egress proxy identifies each connection by the command that opened it.Also consistent across runs: in "All domains" mode none of the
*_proxyvariables are set at all — the sandbox talks out directly — which is why that mode "fixes" the download rather than the allowlist being applied differently.Reproduced a third time at 02:16 UTC in a brand-new session with the Playwright cache wiped beforehand, "Package managers only": five attempts on
cdn.playwright.dev, five onplaywright.download.prss.microsoft.com, all403 'Connection blocked by network allowlist';registry.npmjs.organdgithub.com200 in the same shell.Same symptom in Claude Code on the web (claude.ai/code cloud environment), not only Cowork: on 2026-10-07
playwright install --with-deps chromium(Playwright 1.63.0) failed with HTTP 403 fromcdn.playwright.devduring the environment's setup script and SessionStart hook. Other downloads in the same setup run succeeded (Node from nodejs.org, yarn packages from registry.yarnpkg.com). Workaround for now: skip the browser install in cloud and run browser tests locally/CI.