Browser Extension Deployment
This guide is for admins rolling out the Control Zero browser extension to a team of developer or employee machines. The extension scans text typed or pasted into supported AI chat composers, records matches in the org audit feed, and denies a matched mask or block submission.
Enterprise MDM force-install (Chrome Enterprise policy, Jamf, Intune, Google Workspace, Kandji) is temporarily unavailable and will return. The public Chrome Web Store listing is pending Chrome Web Store review -- one-click self-serve install is COMING SOON. For now, distribute the extension manually: a Teams admin downloads
the pre-configured bundle below and shares it, or users load the unpacked build via
chrome://extensions -> Load unpacked.
If you are a developer just trying to install the extension to see it work, skip to the sign-up flow, then download the pre-configured bundle from the dashboard (Browser extension -> Download bundle) and load it via chrome://extensions -> Load unpacked. (The one-click Chrome Web Store install is COMING SOON, pending review.)
What the extension does, briefly
The Control Zero browser extension scans text typed or pasted into AI chat composers on supported sites (Claude.ai, ChatGPT, Gemini, Perplexity) against your org's data-loss-prevention rules. Matches are logged to your org's audit feed. When a rule is configured to mask or block, the extension denies the submission or cancels the paste.
What the extension captures:
- The matched text span (e.g., a specific SSN that tripped a rule)
- 40 characters of context before and after the match
- The host the user was on (e.g.,
claude.ai) - A device ID unique to this browser profile
- Hostname, user agent, extension version
- Optionally, the user's work email (opt-in)
What the extension does NOT capture:
- The full contents of the composer when no rule fires
- Keystrokes when the extension is paused (10-minute user override)
- Any content on non-AI-chat surfaces (search bars, password fields, etc.)
- Any content on sites outside the explicit allowlist
Network-level guard (v0.2.1)
Starting in extension version 0.2.1, the extension installs a second line of defense alongside the DOM-level overlay: a network-level guard that observes every outgoing AI request and can block it before it leaves the browser.
The guard requires three additional Chrome permissions in the manifest:
webRequest-- used in observer-only mode. Manifest V3 forbids blockingwebRequestlisteners, so the listener only reads the request body, scans it against the org's DLP rules, and emits an audit entry on a hit.declarativeNetRequest-- the only MV3-supported way to actually block a request. The extension synchronizes a dynamic ruleset against any DLP rule scoped tobrowser_ext_networkthat hasstatus==='live'ANDenabledANDaction==='block'. A rule withactionset todetectormaskdoes not install a network-level block; those actions are handled solely by the DOM overlay. The browser evaluates the installed rules in the network stack, which means a block still works even if the page disabled JavaScript or rewrote the textarea around the DOM overlay.declarativeNetRequestFeedback-- lets the extension log which dynamic rule fired, so the audit entry can name the policy that blocked the call.
Why both: the DOM-level overlay is the user-facing UX (Grammarly-style underlines and tooltips). The network guard is the safety net for when the overlay is bypassed. Together they cover composer typing and XHR-level egress.
The new DLP rule scope browser_ext_network is distinct from the existing browser_ext (DOM-only). Admins can scope a rule to either, both, or neither. The backend API accepts browser_ext_network as a valid scope, but the dashboard DLP rule editor does not currently expose it in its scope selector. To create a rule with browser_ext_network scope, use the API directly.
What declarativeNetRequest cannot do
- It does not inspect request bodies. The dynamic ruleset matches on URL only, so the network-level block is a hammer ("block all browser AI calls that match a DLP block rule"), not a scalpel. Body-aware decisions still come from the DOM overlay.
- The 30,000 dynamic rule cap (and 5,000 regex rule cap) is shared across all extensions in the profile. The extension only writes one rule per supported AI surface, so this is not a concern in practice.
- Rules are evaluated at the network stack, not in the page, so a successful block surfaces to the page as a network error, not a friendly message. The audit entry is the source of truth for what happened.
Cross-browser caveats
- Chrome / Edge / Brave / other Chromium: full support, this is the target.
- Firefox: Firefox still supports blocking
webRequestlisteners under MV2 semantics, and itsdeclarativeNetRequestimplementation is partial. A Firefox port of the extension would use blockingwebRequestdirectly and skip the DNR sync entirely. Themanifest.jsonshipped here is Chromium-MV3-only. - Safari: Safari Web Extensions support
declarativeNetRequestbut notdeclarativeNetRequestFeedback. A Safari port would drop that permission and lose the per-rule attribution in audit entries.
Enterprise bundle download (Teams tier)
Teams-tier admins can download a pre-configured extension bundle from the dashboard or via API. The bundle is a ZIP containing the full extension source with an embedded config.json that pre-populates the org ID, API key, and backend URL. This eliminates the need for users to manually configure the extension.
Dashboard
- Navigate to Integrations > Browser Extension in the dashboard.
- Select the target platform (Chrome or Firefox).
- Click Download Bundle. A ZIP file downloads with the extension source and embedded configuration.
- Share the ZIP with your team (internal download link, shared drive, or an unlisted store listing) so each user can install it.
API
# Download the Chrome bundle
curl -H "Cookie: cz_session=<your dashboard session cookie>" \
-o controlzero-extension-chrome.zip \
"https://api.controlzero.ai/api/orgs/<ORG_ID>/browser-extension/bundle?platform=chrome"
# Download the Firefox bundle
curl -H "Cookie: cz_session=<your dashboard session cookie>" \
-o controlzero-extension-firefox.zip \
"https://api.controlzero.ai/api/orgs/<ORG_ID>/browser-extension/bundle?platform=firefox"
The ZIP contains a config.json with the structure:
{
"api_url": "https://api.controlzero.ai",
"org_id": "<ORG_ID>",
"api_key": "cz_extension_ext_<generated>"
}
Each bundle download generates a fresh extension-scoped API key (scoped to browser_ext:report and browser_ext:config). Revoke unused bundle keys from the dashboard or API.
Bulk key generation (Teams tier)
For large fleet deployments where each device needs a unique key, use the bulk key generation API.
Generate keys
curl -X POST \
-H "Cookie: cz_session=<your dashboard session cookie>" \
-H "Content-Type: application/json" \
-d '{"count": 50, "prefix": "fleet", "expiry_days": 365}' \
"https://api.controlzero.ai/api/orgs/<ORG_ID>/browser-extension/keys"
Response:
{
"keys": [
{
"id": "uuid",
"key_prefix": "cz_extension_fleet_abcd1234",
"secret": "cz_extension_fleet_<full_secret>",
"scopes": ["browser_ext:report", "browser_ext:config"],
"expires_at": "2027-04-11T00:00:00Z",
"created_at": "2026-04-11T00:00:00Z"
}
],
"count": 50
}
Parameters:
count(required): number of keys to generate, 1-100prefix(optional): key name prefix, default "ext"expiry_days(optional): days until expiry, default 365
List keys
curl -H "Cookie: cz_session=<your dashboard session cookie>" \
"https://api.controlzero.ai/api/orgs/<ORG_ID>/browser-extension/keys"
Returns all extension keys for the org (prefix only, never the full secret).
Revoke a key
curl -X DELETE \
-H "Cookie: cz_session=<your dashboard session cookie>" \
"https://api.controlzero.ai/api/orgs/<ORG_ID>/browser-extension/keys/<KEY_ID>"