Browser Extension
Supported modes: Hosted Available in: Teams -- View pricing
The Control Zero browser extension enforces DLP rules on browser-based AI chat applications. It works as a content overlay on Claude.ai, ChatGPT, Gemini, and Perplexity, scanning input fields and clipboard operations against your organization's DLP rules before content reaches the AI provider.
What It Does
The extension runs as a Chrome/Edge MV3 extension that:
- Scans text input and clipboard pastes in AI chat interfaces against your DLP rules.
- Overlays a warning when sensitive content is detected, giving the user a chance to review or cancel the submission.
- Blocks paste operations that match high-severity rules (configurable per rule).
- Audits every scan result (detection, block, user override) to the Control Zero backend.
- Syncs DLP rules from the dashboard automatically, with no manual configuration per device.
Supported AI Chat Applications
| Application | Domain | Adapter |
|---|---|---|
| Claude | claude.ai | Claude adapter |
| ChatGPT | chatgpt.com | ChatGPT adapter |
| Google Gemini | gemini.google.com | Gemini adapter |
| Perplexity | perplexity.ai | Perplexity adapter |
Each adapter understands the specific DOM structure of its target application. When the AI provider changes their UI, only the adapter needs updating.
How Rules Sync
- An admin creates or updates DLP rules in the Control Zero dashboard.
- The backend stores the rules and makes them available via the device config endpoint.
- The extension's background service worker polls for rule updates on a configurable interval.
- Updated rules are cached locally in extension storage for offline operation.
- The content script applies the latest rules on every input field interaction and paste event.
Rules are scoped. Only rules with the browser_ext scope apply in the extension. Rules scoped to sdk or gateway only are ignored.
Threat Model: The Overseer
The extension operates under the Overseer threat model:
-
Trust boundary: The extension trusts the backend as the source of truth for DLP rules. It does not trust the page content or the user's clipboard.
-
Secret hashing: Detected sensitive content is hashed with HMAC at the content script boundary before being sent to the background service worker. A second defense-in-depth HMAC is applied at the background script before transmission to the backend. Raw sensitive content never leaves the device.
-
Cold boot is recorded, not blocked: Until the extension has completed its first successful rule sync it is in the
never_syncedstate, and it is not enforcing. It cannot match rules it does not have, so pastes and sends into monitored AI chat applications proceed unscanned. There is therefore a window between installation and first sync in which the extension provides no DLP protection. Allowing is deliberate -- hard-blocking every paste on an unknown ruleset would break every fresh install -- but the gap is made visible rather than silent. The first paste in a session raises a toast reading "Control Zero: DLP rules not yet loaded — not enforcing", and an audit event carryingtool_name: ruleset_not_readyandrule_state: never_syncedis recorded once per egress path (paste, send, background scan) per session, so an administrator can see which devices are not enforcing instead of mistaking silence for a clean scan. The extension retries the rule fetch every 60 seconds for 5 minutes; enforcement starts automatically as soon as a sync succeeds. Until a sync error is recorded the popup and options page read "Syncing rules…"; once one is, they show the failure instead -- a rejected key reads "Rule sync rejected (403)".The same applies to the other non-enforcing states -- an org with no
browser_extrules, org DLP switched off, a failing refresh, or a rule payload that could not be read. Each proceeds and is recorded under its owntool_name, so "did not run" stays distinguishable from "ran and found nothing" in the audit log.
Circuit Breaker
The extension includes two circuit breakers to prevent performance degradation. Both narrow as-you-type detection; neither disables blocking.
- Per-rule circuit breaker: if a single rule matches more than 20 times in a
rolling 60-second window, that rule is dropped from the as-you-type scan loop
for the remainder of the page session. This prevents a pathological regex from
locking up the UI. One audit row is written per rule when it trips, carrying
tool_name: rule_circuit_broken, so a silenced rule is visible rather than silent. The rule is not re-enabled automatically; reload the page to clear it. - Global performance circuit breaker: if three consecutive as-you-type scans each exceed 50ms, the extension stops as-you-type scanning for the life of that page's content script. There is no automatic recovery; reload the page.
What keeps working when either breaker trips. The paste handler and the send gate run their own scans and do not consult either breaker, so paste blocking, paste masking, and the send gate continue to enforce -- including for a rule whose as-you-type circuit has tripped. What you lose is highlight-as-you-type detection, not enforcement at the egress points.
Compliance Checklist Gate (admin-facing, organization-level)
Control Zero gates the creation of browser-scoped DLP rules on an
organization-level compliance checklist. Before an admin can create a DLP rule
scoped to browser_ext, an admin must tick all six items for the organization:
- Data Protection Impact Assessment (DPIA) complete
- Legal review complete
- Privacy notice updated
- User notification sent
- MDM policy published
- Incident response plan updated
The state is read and written through
GET / POST /api/orgs/{orgID}/compliance/browser-ext-ack and is surfaced in
the dashboard. All six must be true at once; unticking any one clears the
acknowledgment stamp and closes the gate to new browser-scoped rules again.
This is an administrative control on your organization's rule authoring. It is not an end-user consent mechanism: the extension presents no acknowledgment prompt, no user response gates scanning, and ticking the six boxes does not by itself discharge any legal obligation. Deciding what notice, consultation, or consent your deployment requires -- and obtaining it -- is your organization's responsibility. Work through the pre-rollout checklist in the Browser Extension Deployment guide with your legal and privacy teams.
The extension does surface a monitoring notice to the user: its options page carries a static disclosure banner naming what is scanned and where matches are logged, and on a fresh install the extension opens that options page with a first-run tutorial. Both are informational; neither is interactive and neither gates scanning.
Pattern Specificity Floor
Overly broad patterns are rejected by the backend when the rule is created, before they can reach any device. A pattern must already be valid RE2, and is then rejected if any of these hold:
| Check | Rule | Error code |
|---|---|---|
| Length floor | Fewer than 6 characters after trimming | PATTERN_TOO_SHORT |
| Broad match | Contains an unbounded quantifier (.*, .+, \w*, \S+, and similar) that is not anchored by a literal token of at least 4 characters. password=.+ passes; .+ alone does not | PATTERN_TOO_BROAD |
| Low entropy | For a pattern containing no regex metacharacters, the literal content carries less than 2.5 bits of Shannon entropy -- this catches aaaaaa and 111111 | PATTERN_LOW_ENTROPY |
These are structural checks on the pattern itself. Control Zero does not measure a rule's false-positive rate, and there is no false-positive-rate threshold to configure. Review broad rules against a sample of your own content before publishing them.
Enterprise Deployment
Enterprise MDM force-install (Chrome Enterprise, Jamf, Intune) is on the roadmap and temporarily unavailable, and 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 shares the pre-configured bundle
(dashboard -> Browser extension -> Download bundle), or load the unpacked build
via chrome://extensions -> Load unpacked. See the Browser Extension Deployment guide
for the manual distribution steps.
How Audit Flows
Content script (tab) -> HMAC hash sensitive content
|
v
Background service worker -> HMAC (defense-in-depth)
|
v
POST /api/v1/browser/audit -> Backend ingest -> Analytical store
|
v
Dashboard: Audit log page (filterable by source=browser_ext)
Every audit entry includes: timestamp, device ID, matched rule, action taken (detect / block / user override), the target application, and the HMAC hash of the matched content. Raw content is never transmitted.
Session State
The extension maintains per-tab session state:
- Scan statistics: Total scans, detections, and blocks for the current session.
- Pause state: user pause is off unless an admin turns it on. The managed-storage key
allow_user_pausedefaults tofalse, and while it is false the pause control in the extension popup is disabled. Where an admin has enabled it, a pause lasts a fixed 10 minutes -- the duration is not configurable, and there is no admin-set maximum. A user may pause again as soon as a pause expires, so treat this as "an admin decides whether users can pause at all", not as a bounded total. - Activity buffer: Recent scan events buffered for batch upload to the backend. Buffer flushes every 30 seconds or when it reaches 50 events, whichever comes first.
DLP Rule Scoping
Only rules with the browser_ext scope are enforced by the extension. When creating rules in the dashboard, include browser_ext in the scopes array:
name: block-credit-cards
pattern: '\b4[0-9]{12}(?:[0-9]{3})?\b'
category: financial
action: block
scopes:
- browser_ext
- gateway
Rules scoped only to sdk or gateway are ignored by the extension. This lets you maintain different enforcement levels per surface. For example, you might block credit card numbers in the browser extension but only detect them in the gateway.
The extension fetches the live, browser_ext-scoped rule set for your org -- your custom rules plus your enabled built-in detectors, merged server-side (see below) -- and runs them against composer input and paste events.
Each rule uses detect, mask, or block, and on a paste each does something different:
| Action | What happens on paste |
|---|---|
block | The paste is cancelled before the text lands in the composer, and a toast names the rule that stopped it. |
mask | The paste is cancelled and the redacted text is inserted instead -- each match replaced with [REDACTED:<category>:<length>] -- and a toast reads "Paste masked by DLP rule". |
detect | The paste is allowed and recorded; a toast reads "Allowed but logged". |
mask is not promoted to block on this surface: a masked paste proceeds with the sensitive spans redacted. The one place an action escalates is the send gate, and it escalates on category, not on action: a match whose category is secret is treated as blocking whatever its action, so a secret-category mask or detect rule stops the send and opens the review interstitial rather than letting the secret reach the provider. A non-secret mask or detect match is a soft warning on send and the message goes.
Two settings bound that escalation, and both are worth knowing before you rely on it. Neither has a shipped admin override today, so treat the send gate as a strong default that an individual user can still step around.
blockOnSendis a user toggle. It is on by default, and it is exposed as a switch in the extension popup ("Block on send"). A user who turns it off disables the whole send gate, including thesecretescalation, before any scan runs. There is no managed-storage or server-side setting that forces it back on.allowOverridedefaults to on and nothing currently turns it off. When on, the interstitial offers a "send anyway" path that requires a typed justification of at least 8 characters and writes an audit row. The extension reads this setting and would hide the override button if it were false, but no shipped surface -- popup, options page, or managed-storage policy -- writes it, so in practice the override is always available.
So on the send path a secret match is a stop plus an accountable, logged
exception -- not an absolute block. If a secret must not be able to leave under
any circumstances, put an enforcing surface that the user does not control
(the SDK or the gateway) in the path.
The extension ships no patterns of its own; it is served them. The rule-pull
response merges your organization's enabled built-in detectors in with your
custom browser_ext rules, so SSNs, AWS keys, credit cards and similar shapes
are caught in the browser without writing a custom rule for each. See the
Locale-Aware DLP guide.
Three conditions bound that merge:
- Org DLP must be switched on. With the master switch off the endpoint returns an empty rule set, and the extension does not scan.
- A project or organization DLP profile must be configured. With no profile,
the extension receives your custom
browser_extrules only. - Context-gated detectors are deliberately withheld. The extension's scanner is regex-only and cannot evaluate a detector's required nearby-context window, so shipping those as bare regexes would flood you with false positives. They remain enforced by the SDK and gateway, which can evaluate that context.
Merged built-ins all carry the single action set on the DLP profile, rather than a per-detector action.
Verify Installation
- Open any supported AI chat application (e.g., claude.ai).
- Paste content that matches a known DLP rule (e.g., a test credit card number
4111-1111-1111-1111). - The extension overlay should show the matched rule and prevent submission.
- Check the Control Zero dashboard audit log for an entry with
source: browser_ext.
Troubleshooting
Extension not scanning. Open the extension popup and check, in order: the
status reads "Active"; scanning is not paused; the extension is enabled for this
site; and "Last sync" is not "Never". A rule set that has never synced, an org
whose DLP master switch is off, and an org with no browser_ext rules all leave
the extension non-enforcing -- each is recorded in the audit trail under its own
reason, so check there to tell them apart. If as-you-type highlighting stopped
but pastes are still blocked, a performance circuit breaker has tripped; reload
the page.
Rules not updating. Open the extension popup and check the "Last sync" timestamp. If it shows "Never," the extension cannot reach the backend. Verify network connectivity and the backend URL configuration.
Performance issues. If the extension causes input lag, broad regex patterns
are the most common cause; review your DLP rules for specificity. The popup does
not report circuit-breaker state -- when the global breaker trips it logs
scan circuit tripped to the page's developer console, and a tripped per-rule
breaker writes an audit row with tool_name: rule_circuit_broken.