Trust and isolation
What the box enforces
Section titled “What the box enforces”Tested against real Chromium (test/scope.browser.test.ts in the repository):
- Slots cannot reach each other. Each slot is its own BrowserContext behind a virtual DevTools endpoint that cannot see or reach another slot’s pages, targets, contexts or sessions, including by guessing ids.
- A client is held to the web. It cannot point a page at
file:,chrome:,devtools:,view-source:orabout:pages other than blank. Onlyhttp(s),data:andblob:open. It cannot have the browser read a file path into a page (DOM.setFileInputFiles, dragging files in), and it cannot choose where a download goes. Downloads are denied from the start. - The browser does not inherit the node’s secrets. Chromium is started with an allowlisted environment, not the node’s:
PATH,HOME, the locale (LANG,LC_*),TZ, the display (DISPLAY,XAUTHORITY,WAYLAND_DISPLAY,XDG_*), library and font paths, and proxy and CA settings (HTTP(S)_PROXY,NO_PROXY,SSL_CERT_*). A headful node that needs more (LIBGL_*,MESA_*,GTK_*,DBUS_SESSION_BUS_ADDRESS) names it inBROWSERBAY_CHROMIUM_ENV_PASSTHROUGH. The box’s ownBROWSERBAY_*settings can never be passed.
What it does not do
Section titled “What it does not do”The box limits what a client can ask of the machine. It does not make a client harmless.
- A slot can browse anything the node’s network can reach. That means localhost services, the LAN, and a cloud metadata address (
169.254.169.254). This is SSRF, and it is inherent in giving someone a browser. - The node process’s own environment holds a secret. A node’s enrollment secret sits there, and in the all-in-one it is the API key. The browser’s OS user can read it through the process table. The restrictions above keep a client from asking for it, but they are a filter on a very capable protocol, not a sandbox. Nothing here is proof against a flaw in that filter or in Chromium.
- Slots on one node share a browser process (unless the node runs with
BROWSERBAY_ISOLATION=process: see Isolation). A hostile page that crashes or exhausts it takes every slot on that node with it, and a renderer exploit is not contained by a VM. Chromium’s own sandbox is the control for that. It is off by default (--no-sandbox) because containers rarely allow the user namespaces it needs. SetBROWSERBAY_CHROMIUM_SANDBOX=truewhere yours does. A Chromium per slot stops one slot’s page crashing the others, but it is not a boundary against an exploit: that still needs the sandbox, or a machine per party.
- Give slot tokens to services you trust, not to end users or to code you did not write. A person watching and steering a slot through a viewer you build is fine, because that viewer sends only mouse and key events, not DevTools commands. See Live view.
- Run nodes on machines with nothing to steal. If the pages are untrusted, add egress rules that block private ranges and metadata addresses.
- Prefer the split deployment for anything sensitive. The machines with browsers then hold only a node’s enrollment secret, and the API key stays on the relay’s machine.
- To serve parties that do not trust each other, run a box per party. A namespace is a naming convention, not a boundary.