06 Make it yours
Customer Policy Surface
In this chapter
- What policy controls
- Canonical policy fields
- Allowed values and defaults
- Sensitive actions BrowserBox can allow or deny
- Navigation, browser-internal and private-network policy
- Certificate-error policy
- Browser chrome policy modes
- Locking kiosk mode
- Per-destination feature controls
- Server policy versus embedder policy
- Customer policy CLI
- Operational visibility
6.1 What policy controls #
BrowserBox policy is the customer-facing runtime control surface that answers two distinct questions:
Which sensitive actions are allowed or denied?
Which browsing targets may the remote browser reach?
The canonical persisted policy file lives at:
~/.config/dosaygo/bbpro/policy/policy.jsonBrowserBox normalizes and validates that file before applying it. If a field is omitted, BrowserBox fills in safe defaults for the current schema.
The allowed values listed in this section are based on BrowserBox’s current runtime validation and normalization surface, not on a separate aspirational specification. In practice, customers should be able to trust this section because these values are the same ones BrowserBox validates at load time.
6.2 Canonical policy fields #
The customer-relevant policy bundle currently includes these high-level surfaces:
| Field | Meaning |
|---|---|
transport.certificateErrors |
Whether BrowserBox enforces certificate validation or explicitly allows self-signed / invalid certificates. |
navigation.mode |
Top-level navigation mode: open, allowlist, or blocklist. |
navigation.allowlist |
Allowed navigation targets when navigation.mode=allowlist. Supports exact host, exact origin, exact URL, and wildcard host patterns (§6.5.2). |
navigation.blocklist |
Denied navigation targets when navigation.mode=blocklist. |
navigation.internalAllowlist |
Exact browser-internal origins that may open. It defaults to empty. chrome://inspect and the other permanently reserved targets cannot be enabled. |
navigation.privateNetwork.mode |
Whether private/local targets are denied by default or controlled through an allowlist. |
navigation.privateNetwork.allowlist |
Explicit private/local destinations that may be reached, including exact hosts, IPs, and IPv4 CIDRs. |
featureControls.copy |
Controls copy actions, including modifier shortcuts and context-menu copy paths. |
featureControls.paste |
Controls paste actions, including text insertion into the remote browser. |
featureControls.downloads |
Controls download routes and archive-serving surfaces. When set to deny, the download is cancelled at the browser level before any data is written to disk, and the connected client receives a policy-denied notification. |
featureControls.uploads |
Controls upload routes and file input surfaces. |
featureControls.devtools |
Controls DevTools access. |
featureControls.audio |
Controls the audio sidecar service. |
featureControls.automation |
Controls the BrowserBox automation surface used by the webview API. |
featureControls.contextMenu |
Controls whether the remote-page context menu may open. |
featureControls.browserChrome |
Whether BrowserBox’s tab bar and address bar are shown, hidden or user-toggleable. always-hide keeps them hidden whatever the login link, the address bar or an embedder asks for (§6.7). |
6.3 Allowed values and defaults #
The most important values customers need to know are listed here directly.
6.3.1 Binary feature controls #
Unless stated otherwise, feature controls are binary decisions:
| Field | Allowed values | Default / note |
|---|---|---|
featureControls.copy |
allow, deny |
Required in the persisted policy bundle. |
featureControls.paste |
allow, deny |
Required in the persisted policy bundle. |
featureControls.downloads |
allow, deny |
Required in the persisted policy bundle. |
featureControls.uploads |
allow, deny |
Required in the persisted policy bundle. |
featureControls.devtools |
allow, deny |
Required in the persisted policy bundle. |
featureControls.audio |
allow, deny |
Required in the persisted policy bundle. |
featureControls.automation |
allow, deny |
Required in the persisted policy bundle. |
featureControls.contextMenu |
allow, deny |
If omitted, BrowserBox currently defaults this field to allow for backward compatibility. |
6.3.2 Enumerated policy fields #
| Field | Allowed values | Default / note |
|---|---|---|
transport.certificateErrors |
enforce, ignore-all |
Defaults to enforce. |
navigation.mode |
open, allowlist, blocklist |
Required in the persisted policy bundle. |
navigation.privateNetwork.mode |
deny, allowlist |
Defaults to deny. |
featureControls.browserChrome |
toggle, api, always-show, always-hide |
Defaults to toggle. Use always-hide for kiosks (§6.8). |
6.3.3 Identity and access configuration #
Three fields govern identity integration for authenticated BrowserBox deployments:
| Field | Allowed values | Note |
|---|---|---|
identity.authMode |
magic-link, sso-saml |
How users authenticate. magic-link uses email-based one-time links; sso-saml routes through an IdP. |
identity.ssoProvider |
none, okta, entra, custom |
The IdP in use when authMode=sso-saml. Use custom for non-enumerated providers. |
identity.peerCapabilityModel |
shared, scoped |
Whether multiple connected clients in the same session share capabilities (shared) or each client has its own scoped capability set (scoped). |
6.3.4 List-valued policy fields #
| Field | Allowed entry form |
|---|---|
navigation.allowlist |
Array of non-empty strings. Entries may be exact hosts, exact origins, exact URLs, or wildcard host patterns; see §6.5.2 for how each matches. |
navigation.blocklist |
Array of non-empty strings. Entries follow the same matching forms as the navigation allowlist. |
navigation.internalAllowlist |
Array of exact, origin-only chrome://page or chrome-extension://<32-character-id> strings. Wildcards, paths, queries and fragments are rejected. An allowed extension origin covers paths within that exact extension. |
navigation.privateNetwork.allowlist |
Array of non-empty strings. Entries may be exact hosts, exact IPs, or IPv4 CIDRs. |
6.3.5 Where customers can verify allowed values #
Customers do not have to guess. BrowserBox exposes the current policy surface through the customer-facing policy CLI:
bbx policy show --scope global|userprints one persisted policy source.bbx policy showprints the normalized effective policy that BrowserBox is actually using.bbx policy validate --file policy.jsonvalidates a candidate policy file against the current code and reports invalid enum values directly.
For example, if a customer uses an unsupported mode, BrowserBox validation reports the current accepted set, such as:
featureControls.browserChrome must be one of:
toggle, api, always-show, always-hide6.4 Sensitive actions BrowserBox can allow or deny #
These actions currently route through BrowserBox’s policy authorization layer:
| Action | Customer-visible effect |
|---|---|
| navigate | Page navigation, history navigation, new-tab target creation, and clean-slate navigation flows. |
| uploads | File upload routes and file chooser / file input flows. |
| downloads | Download and archive-serving routes. When denied, the download is cancelled before any data reaches the server’s download directory, and the user sees a policy-denied notification in the BrowserBox client UI. |
| devtools | BrowserBox DevTools service and its websocket bridge. |
| audio | BrowserBox audio service. |
| copy | Keyboard and context-menu copy paths. |
| paste | Keyboard and API-driven paste / insert-text paths. |
| automation | The automation methods exposed through the webview API, such as selector waits, clicks, typing, and evaluation. |
| contextmenu | The remote-page context menu UI. |
All of these controls are binary allow / deny decisions except featureControls.browserChrome, which uses explicit UI visibility modes described below.
6.5 Navigation, browser-internal and private-network policy #
BrowserBox separates ordinary browsing, browser-internal access and private/local reachability:
navigation.allowlistanswers “where may the RBI tab browse?”navigation.internalAllowlistanswers “which explicitly named browser-internal origins may open?”navigation.privateNetwork.allowlistanswers “which private or local destinations may any request reach?”ALLOWED_EMBEDDING_ORIGINSis separate and only controls which parent pages may embed BrowserBox
Browser-internal navigation is denied by default, independently of navigation.mode. To permit an internal page, add its exact origin, for example chrome://extensions. To permit an extension’s pages, add the exact extension origin, for example chrome-extension://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; BrowserBox then permits paths within that extension. chrome://inspect, chrome://newtab, chrome://omnibox-popup, and devtools:// remain forbidden even if listed. If global and user policies are both active, both must list the origin. about:blank is structurally accepted so BrowserBox can stage safe tab creation, but a user-requested blank tab still follows the configured navigation mode.
The BrowserBox Extensions button is shown only when the effective internal allowlist contains chrome://extensions or a valid exact extension origin. This visibility check uses the policy snapshot only; it does not scan the installed extensions directory.
6.5.1 Navigation modes #
| Mode | Behavior |
|---|---|
| open | Any ordinary browsing target is allowed, subject to the separate private-network and browser-internal boundaries. |
| allowlist | Only configured allowlist entries may be reached. |
| blocklist | All targets are allowed except those matching the configured blocklist. |
6.5.2 How allowlist entries match #
Allowlist and blocklist entries take four forms. The form of the entry decides how it matches:
| Entry | Form | Matches | Does not match |
|---|---|---|---|
*.example.com |
Wildcard host | example.com itself and every subdomain at any depth, such as www.example.com and a.b.example.com. Any scheme, port and path. |
notexample.com, example.org |
www.example.com |
Exact host | www.example.com on any scheme, port and path. |
example.com, a.www.example.com |
https://app.example.com |
Exact origin | Any path on that scheme, host and port. A trailing / makes no difference. |
The same host over http://, or on port 8443 |
https://example.com/a?b=1 |
Exact URL | That path and query only. A #fragment is ignored. |
/a, /a/c?b=1, /a?b=2 |
Avoid these mistakes:
A path without a scheme allows the whole site. An entry such as
example.com/mapsorexample.com/maps/*is read as the hostexample.com. To allow only certain pages, list each page as an exact URL, scheme included. There are no path-prefix entries.Only a leading
*.is a wildcard. An entry such as*example.comorwww.*.example.comis read as a literal host name and matches nothing.bbx policy validatedoes not flag either mistake. Before you rely on an entry, test the addresses you mean to allow and refuse:bbx policy check --action navigate --url https://www.example.com/Every page load is checked, including links, redirects and new windows opened from an allowed page. If a site sends users through another host, such as a sign-in or media host, that host needs its own entry.
The page a user reaches when a navigation is denied can be replaced with your own; see §5.8.
6.5.3 Private-network controls #
Private-network policy defaults to deny. Customer policy may widen that boundary explicitly:
| Field | Meaning |
|---|---|
| mode=deny | Denies private and local targets such as RFC1918 addresses, localhost, and the unspecified addresses 0.0.0.0 and :: by default. |
| mode=allowlist | Keeps the private/local boundary in place but permits explicit entries. |
| allowlist entries | Exact hosts, exact IPs, and IPv4 CIDRs, for example 10.0.0.5, 10.0.0.0/8, and localhost. |
IPv4-mapped IPv6 addresses such as ::ffff:10.0.0.5 are classified as the IPv4 address they carry, so they cannot be used to bypass an IPv4 rule. An allowlist entry containing / must be a valid IPv4 CIDR; an invalid or IPv6 CIDR is ignored rather than treated as a host. Run bbx policy validate after editing the allowlist and bbx policy check --action navigate --url <url> to confirm the result for a specific destination.
6.6 Certificate-error policy #
Certificate handling is now policy-driven rather than hidden behind a permanent launch flag.
| Mode | Behavior |
|---|---|
| enforce | Default. BrowserBox enforces certificate validation and will not silently accept certificate errors. |
| ignore-all | Explicit opt-in for environments that need to reach self-signed or otherwise invalid HTTPS targets. |
6.7 Browser chrome policy modes #
featureControls.browserChrome does not allow or deny a risky action. Instead, it governs whether BrowserBox’s own visible browser chrome, the tab bar and address bar, is shown, hidden, or user-toggleable.
| Mode | Visible UI | User toggle | Meaning |
|---|---|---|---|
| toggle | visible by default | yes | Legacy-compatible mode. The login link’s ui= sets the starting state. The user may show or hide BrowserBox chrome unless the embedder locks it. |
| api | visible by default | no | The embedder may drive UI visibility through the API, but the end user may not toggle it directly. |
| always-show | always visible | no | BrowserBox chrome must remain visible. |
| always-hide | always hidden | no | BrowserBox chrome stays hidden for kiosk-style or tightly embedded experiences. A ui=true login link, an edited address bar, the context menu and the embedder API cannot show it. For a kiosk, combine it with a navigation allowlist (§6.8). |
If the embedder sets ui-visible or allow-user-toggle-ui, those values may further restrict the experience. They cannot widen what the server policy allows.
Navigation in always-hide mode: when chrome is hidden, BrowserBox’s built-in back/forward buttons are not visible to the user. However, tab history is preserved internally. Embedders can navigate the remote browser’s history programmatically through the webview API:
await webview.callApi('goBack');
await webview.callApi('goForward');The remote-page context menu has no back option. Embedders that need end-user back navigation in always-hide mode should add their own back button wired to the goBack API call above.
6.8 Locking kiosk mode #
A kiosk that users must not leave needs two settings in the server policy. The user’s browser cannot override either of them.
featureControls.browserChromeset toalways-hide. The chrome stays hidden: aui=truelogin link, an edited address bar, the context menu and the webview API cannot show it.A
navigationallowlist naming the kiosk’s sites (§6.5). The server refuses every page load outside it: typed addresses, new tabs, and links, redirects and new windows opened from inside an allowed site.
The allowlist is the boundary; always-hide removes the controls. Hiding the chrome alone is not a boundary, because a user who modifies the browser client could show it again. The allowlist still limits that user to the listed sites, so always set both.
Set them in the global policy, /etc/browserbox/policy.json. The global browserChrome setting takes precedence over a per-user policy, and the global policy applies to every BrowserBox Fleet seat on the host.
# If there is no global policy yet:
sudo bbx policy init --scope global --baseline regulated
sudo cp /etc/browserbox/policy.json kiosk.json
# In kiosk.json set:
# "featureControls": { ..., "browserChrome": "always-hide" }
# "navigation": { "mode": "allowlist", "allowlist": ["www.example.org"], ... }
sudo bbx policy set --scope global --file kiosk.jsonNew sessions start with the policy. In always-hide mode a user who follows a link off the allowlist has no back button, so install a blocked-policy.html page (§5.8.2) with a link back to the kiosk’s start page.
6.9 Per-destination feature controls #
featureControls settings such as downloads and paste are currently global — the same setting applies to all browsing destinations regardless of which site the user is on. Different featureControls per allowlist entry are not supported. If your use case requires different download or clipboard behavior on different sites, the recommended approach is to run separate BrowserBox instances each with a distinct policy configuration.
6.10 Server policy versus embedder policy #
BrowserBox has three relevant policy layers:
Global server policy, stored in
/etc/browserbox/policy.json, which applies to every Unix user and Fleet seat.User server policy, stored in the user’s existing BrowserBox policy directory, which may tighten but never loosen the global policy.
Embedder policy hints, supplied through the canonical webview surface, which may only restrict and never widen the effective server policy.
An action is allowed only when every active server-policy scope allows it.
With no global policy, the user policy behaves exactly as before.
User and embedder restrictions may narrow capabilities further.
An embedder cannot override a server-side deny into an allow.
6.11 Customer policy CLI #
BrowserBox ships a policy CLI so customers can inspect, initialize, validate, and test the effective policy surface.
bbx policy help
bbx policy where [--scope global|user] [--json]
bbx policy baselines
bbx policy controls [--json]
bbx policy show [--scope global|user]
bbx policy get [--scope global|user]
bbx policy resolve
bbx policy check --action <name> [--url <https://...>] [--source <tag>]
bbx policy trace [--last <n>]
bbx policy init [--scope global|user] [--baseline regulated|compat]
bbx policy reset [--scope global|user] [--baseline regulated|compat]
bbx policy set [--scope global|user] --file <path/to/policy.json>
bbx policy validate [--scope global|user] [--file <path/to/policy.json>]6.11.1 Useful commands #
| Command | Meaning |
|---|---|
| bbx policy where | Prints the resolved Unix principal plus global and user policy paths and status. |
| bbx policy baselines | Lists supported baseline names. |
| bbx policy controls –json | Prints the documented NIST 800-53 and FIPS 140 control surfaces. |
| bbx policy show | Prints the effective policy actually enforced, with source and principal diagnostics. |
| bbx policy show –scope global | Prints the raw stored global policy; use --scope user for the user’s raw policy. |
| bbx policy resolve | Compatibility alias for the compiled / normalized effective policy snapshot. |
| bbx policy check –action ... | Evaluates a single action decision. Exit code 0 means allow; exit code 2 means deny. |
| bbx policy trace –last 20 | Shows recent policy decisions from the decision trace log. |
| bbx policy init –scope user –baseline compat | Creates the selected scope from a named baseline. |
| bbx policy reset –scope global –baseline regulated | Replaces the selected scope with a named baseline. |
| bbx policy set –scope user –file policy.json | Loads, validates, and atomically persists a policy at the selected scope. |
| bbx policy validate | Validates the current persisted policy or an explicitly supplied file. |
6.11.2 Recipe: global policy with a per-user tightening #
Set the administrator-owned policy that applies to every BrowserBox Unix user and Fleet seat:
bbx policy set --scope global --file global-policy.jsonOptionally set a stricter policy for one Unix user. The operator reads the source file and BrowserBox writes it in the target user’s policy store, so the target account does not need access to the operator’s file:
bbx policy set --scope user --file policy.json --for user-bbx-0901Inspect the effective policy actually enforced for that user, then inspect the raw user layer if needed:
bbx policy show --for user-bbx-0901
bbx policy show --scope user --for user-bbx-0901
bbx policy where --for user-bbx-0901The user layer may tighten the global policy but cannot weaken it. Reset only that user’s layer to a named baseline with:
bbx policy reset --scope user --baseline compat --for user-bbx-09016.12 Operational visibility #
When policy blocks an action, BrowserBox emits both customer-visible and operator-visible signals:
a policy-denied notification in the client UI when a connected client is present at the time of the block
server log entries prefixed with
[policy-decision]a persistent trace file at
/̃.config/dosaygo/bbpro/policy/decisions.ndjson
Actions that currently produce client-visible notifications include:
| Action | Notification trigger |
|---|---|
| navigate | A navigation to a blocked destination. |
| downloads | A browser download that was cancelled before any bytes reached disk. |
| copy, paste, devtools, uploads, automation, contextmenu | The corresponding action was attempted while denied by policy. |
| tab-limit | A new tab or popup was blocked because the session is at the configured tab cap (BBX_MAX_TABS). |
Tab-limit blocks that occur during service startup are silent—they close excess tabs without showing a client notification, since no client is connected yet.