Skip to main content
CID222 Docs

Deploy the browser extension

Generate the managed policy that installs and connects the CID222 browser extension, then enrol devices, issue firewall EDL tokens and read the events they produce.

  • Version: 0.4
  • Feature: ext.browser
  • Role: admin_user
  • Type: task

The CID222 browser extension inspects what a person types into an AI website — ChatGPT, Claude, Gemini — from inside the browser, without intercepting TLS. Administration → Browser Extension generates the managed policy that installs it and points it at this appliance. Everything else the extension does — device attestation, the firewall block list, the event feed — is configured through the API or read on other pages.

What do I need?

Licence
Starter
Role
admin_user

Prerequisites

  • The appliance knows its own external name. Set `API_DOMAIN` before you use this page — see the warning below.
  • The signed extension package and its update manifest are published on a host your managed browsers can reach.
  • A gateway API key exists for the extension to authenticate with. Issue one on Access keys.
  • You can push a Chrome managed policy with GPO, Intune, Jamf or an equivalent.

Note

The extension is not a proxy. It reads the page in the browser and asks CID222 for a verdict, so there is no root CA to distribute and no TLS interception. It also cannot see traffic from a desktop app or an unmanaged browser — for those, see Deploy and integrate.

Before you start: set the hosts on the appliance

Danger

The CID host (cidHost) and CRX host fields on this page do not reach the policy you download. Selecting Generate policy posts your values, then immediately re-reads the policy from the appliance without them, so the JSON shown, copied and downloaded is always built from API_DOMAIN and EXTENSION_CRX_DOMAIN. The success toast still names the host you typed, which makes the failure look like a success.

Set both environment variables on the appliance and restart the gateway before you use this page:

  • API_DOMAIN — the external name browsers reach this appliance on. It becomes cidHost.
  • EXTENSION_CRX_DOMAIN — where the signed .crx and extension-update.xml are published.

A value with no scheme is treated as https://, and trailing slashes are stripped. If either is unset, the policy carries https://REPLACE-WITH-YOUR-CID-HOST or https://REPLACE-WITH-YOUR-CRX-HOST and the page shows Placeholders still present.

Generate the managed policy

Open the page

Select Administration → Browser Extension.

The Managed policy tile loads the policy this appliance would emit today. If both hosts are known, the JSON block below the buttons shows real addresses; otherwise the right column shows Placeholders still present.

Confirm the hosts

Read the JSON block, not the form fields.

The CID host (cidHost) field is prefilled from the appliance and is blank when the appliance reported a placeholder. The CRX host field is always blank on load and is never prefilled, even when EXTENSION_CRX_DOMAIN is set.

Take the policy

Select Copy, or Download to save it as cid222-policy.json.

Copy flips to Copied for two seconds. Both actions hand you exactly the JSON shown in the block.

Insert the tenant key

Replace cid_key_REPLACE_WITH_TENANT_KEY with a real gateway API key.

The generator never mints a key. Issue one on Access keys and paste it into the cidApiKey field of the JSON.

Push it with your device-management tool

Apply the policy to the managed browsers, pinning the extension ID shown in Before you push it.

The default ID is lllegnpcnmlafjcdkpecabdiogjafgei; a fork signed with a different key overrides it with BROWSER_EXTENSION_ID. Managed browsers install the extension from the update manifest on the next policy refresh.

Pilot before you widen

Apply the policy to one organisational unit first, and watch what arrives.

Events from the extension appear on All detections with the source set to the extension, and usage totals appear on AI usage.

Warning

Item 4 of the page's own Before you push it list tells you to check the Browser Inspection page for events. That page is the inline-proxy and ICAP surface and shows nothing the extension sends. Use All Detections and AI Usage instead.

What the policy contains

{
  "ExtensionInstallForcelist": [
    "lllegnpcnmlafjcdkpecabdiogjafgei;https://crx.example.com/extensions/stable/extension-update.xml"
  ],
  "3rdparty": {
    "extensions": {
      "lllegnpcnmlafjcdkpecabdiogjafgei": {
        "cidHost": "https://cid.example.com",
        "cidApiKey": "cid_key_REPLACE_WITH_TENANT_KEY",
        "failClosed": true
      }
    }
  }
}

Three managed keys reach the extension, and only three.

KeyValueWhat it does
cidHostFrom API_DOMAIN or the placeholderThe only address the extension talks to. A wrong value fails as Invalid credentials, which the user cannot fix
cidApiKeyPlaceholder you replaceThe gateway API key the extension authenticates with
failClosedAlways trueWhen the appliance is unreachable, the extension blocks AI sites rather than letting traffic past uninspected

Warning

failClosed is emitted as true unconditionally and there is no setting anywhere that changes it. The module README and the enterprise rollout guide both describe fail-open as a customer choice; the generator does not offer one. To ship fail-open you must hand-edit the downloaded JSON, and it is then no longer what this page produces.

Two documents also list a fourth key, extensionUpdateChannelUrl. The generator does not emit it. The update URL travels in ExtensionInstallForcelist instead.

Enrol and revoke devices

Device attestation proves a browser is the one it claims to be, so a firewall can allow AI destinations from protected machines only. It is entirely API-driven: there is no device list, no enrolment panel and no revoke button anywhere in the dashboard.

The extension performs the exchange itself, authenticating with the gateway API key from the managed policy — never a session token:

  1. POST /api/v1/extension/attestation/enroll registers the device with a P-256 public key. A key carrying its private scalar is refused. Re-enrolling replaces the key but never clears a revocation.
  2. GET /api/v1/extension/attestation/nonce issues a 32-byte challenge that lives for 60 seconds and can be claimed once.
  3. POST /api/v1/extension/attestation/heartbeat returns the nonce, a timestamp, the device posture and a signature over all three. The extension repeats this every five minutes.

All three are rate-limited to 30 calls a minute per device.

To see or change the fleet, call the admin API as an administrator:

# List enrolled devices, newest heartbeat first
curl -sS https://<appliance-fqdn>/admin/extension-devices \
  -H "Authorization: Bearer <session-jwt>"
 
# Revoke one device, and restore it again
curl -sS -X POST   https://<appliance-fqdn>/admin/extension-devices/<device-id>/revoke -H
curl -sS -X DELETE https://<appliance-fqdn>/admin/extension-devices/<device-id>/revoke -H

A revoked device is refused a nonce and drops out of the block list on the next poll.

Warning

A failed attestation produces one flat 401 Attestation rejected for six different causes — wrong device in the posture, unknown or revoked device, a timestamp more than two minutes off, a nonce that was already used, an oversized posture, or a bad signature. The gateway log line Heartbeat signature rejected for device <id> distinguishes only the last of them, and nothing is written to Event logs.

Publish the firewall block list

CID222 does not block network traffic. It publishes the addresses of healthy, attested devices, and your firewall allows AI destinations only from those addresses.

Mint an EDL token

Call the token API as an administrator with a name and a mandatory future expiry.

curl -sS -X POST https://<appliance-fqdn>/admin/edl-tokens \
  -H "Authorization: Bearer <session-jwt>" \
  -H "Content-Type: application/json" \
  -d '{"name":"perimeter-fw","expires_at":"2027-01-01T00:00:00Z"}'

The response carries the raw cid_edl_… token once. Only its SHA-256 hash and first 16 characters are stored, so a lost token is replaced, never recovered.

Point the firewall at the list

Configure an external dynamic list against https://<appliance-fqdn>/api/v1/edl/healthy-ips?token=cid_edl_….

The response is plain text, one address per line, with no header and no commentary. A firewall that cannot attach headers uses the query parameter; one that can sends Authorization: Bearer cid_edl_… instead. Add ?format=rpz for a DNS response-policy zone — that form is IPv4 only and silently skips anything else.

Rotate on a schedule

Mint the replacement, reconfigure the firewall, then revoke the old token with DELETE /admin/edl-tokens/:id.

Expiry is mandatory for these tokens precisely because the query-string form lands in access logs. There is no dashboard screen for any of this in 0.4.

A device appears in the list while it is not revoked, has heartbeated within the freshness window — 15 minutes by default, against a 5-minute heartbeat — and has a recorded source address. Addresses are the ones the gateway observed, not ones the device claimed.

Fields reference

Managed policy tile

FieldPrefilled fromEffect
CID host (cidHost)The appliance's own API_DOMAIN, blank if it is a placeholderPosted with Generate policy but absent from the policy you then copy
CRX hostNothing — always blank on loadSame: posted, then discarded by the refresh

Buttons

ButtonDoes
Generate policyPosts the two fields, then re-reads the appliance-derived policy. Silent on failure — a refusal produces no message at all
CopyCopies the JSON shown in the block. Fails with Could not copy to clipboard if the browser refuses clipboard access
DownloadSaves the same JSON as cid222-policy.json
SurfaceEndpointRole
Enrolled devicesGET /admin/extension-devicesadmin_user
Revoke / restore a devicePOST / DELETE /admin/extension-devices/:deviceId/revokeadmin_user
EDL tokensGET / POST /admin/edl-tokens, DELETE /admin/edl-tokens/:idadmin_user
Extension event feedGET /admin/extension-eventsadmin_user
Firewall listGET /api/v1/edl/healthy-ipsEDL token, not a session

Verify

  1. The JSON block on the page shows your real appliance host and CRX host, and the Placeholders still present banner is gone. If it is still there, the environment variables are not set — the form fields will not clear it.
  2. On a pilot machine, the extension appears in the browser's extension list, pinned by policy and not removable by the user.
  3. Call GET /admin/extension-devices. The pilot machine is listed with a last_seen_at within the last five minutes and a posture recording managedPolicyPresent.
  4. Fetch GET /api/v1/edl/healthy-ips with the EDL token. The pilot machine's address is in the output.
  5. Type something that trips a filter into an AI website on the pilot machine. The event appears on All Detections filtered to the extension source, and in the AI Usage totals.
  6. This module writes nothing to Event logs. Generating a policy, revoking a device and minting or revoking an EDL token leave no audit row — check the device list and token list themselves instead.

If it fails

  • Placeholders still present stays up after Generate policy — expected. Set API_DOMAIN and EXTENSION_CRX_DOMAIN on the appliance and restart the gateway; the form fields cannot fix it.
  • Selecting Generate policy does nothing visible at all — the request was refused and the page has no error handling for it. Confirm your role is admin_user or superadmin and that the licence includes the browser extension.
  • Access denied — Only administrators can manage the browser extension. — a viewer reaches this page through navigation and is then refused by the page itself. Only admin_user and superadmin can use it.
  • This feature (…) is not included in the installed license tier. Contact your CID representative to upgrade. with code FEATURE_NOT_LICENSED — the licence lacks the browser-extension capability. It is in every tier, so this usually means an expired or unread licence; see License.
  • The extension shows Invalid credentials to users — cidHost in the pushed policy is wrong, or cidApiKey is still the placeholder. Users cannot correct either; fix the policy and re-push.
  • Signed in, but this role does not use the browser extension: '…' has no extension view. Use the dashboard instead. — an auditor signed in to the extension. Auditors read evidence in the dashboard and do not generate traffic.
  • Attestation rejected (401) — one of six causes, deliberately indistinguishable. Check the device clock first: a skew over two minutes fails every heartbeat.
  • Device is enrolled to another tenant — the device identifier is already registered to a different account. Revoke it there before re-enrolling.
  • Too many attestation requests (400, not 429) — more than 30 attestation calls in a minute for one device. A device stuck in a retry loop produces this.
  • EDL token required / Invalid or expired EDL token (401) — the firewall sent no token, or one that is unknown, revoked or past its expiry. Mint a replacement.
  • expires_at must be in the future — EDL tokens must carry a future expiry. Unlike gateway API keys, a never-expiring EDL token cannot be created.
  • A large file upload is refused rather than cleaned — chunked and resumable uploads cannot be reassembled for inspection, and CID_RESUMABLE_UPLOAD_POLICY defaults to block. Documents are blocked rather than redacted; only images are redacted in place.

Next steps

  • AI usage — who used which AI application, from the events the extension and the proxy both feed.
  • All detections — the unified timeline where extension verdicts land beside chat and proxy detections.
  • Access keys — issue the cid_key_ the managed policy needs.
  • Endpoint agent — the OS-level alternative for traffic a browser extension cannot see.

Last updated on

On this page

Download PDF