# Extensions & IDE plugins

Source: https://www.orthalon.com/de/docs/configure/extension-governance

Inventory browser extensions and IDE plugins, explain their risk, alert on permission drift and record approve, review or deny decisions.

> **Plan requirement:** Enterprise. Administrators make decisions; any member can view the inventory.

Orthalon records **which** browser extensions and IDE plugins are installed and **what they declare**: identifiers, versions, publishers, requested permissions, host access and declared capabilities. It never records page content, keystrokes, file contents or local paths, and this inventory is stored apart from AI activity events. It does not inspect what an extension does at run time.

Open **Discovery → Extensions & IDE plugins**.

---

## 1. Discovery sources

Each item shows the sources that report it. A source that has not reported for three days is marked stale.

| Source | Covers | What it reports | Setup |
| :--- | :--- | :--- | :--- |
| **Chrome Enterprise** (Chrome Browser Cloud Management) | Managed Chrome browsers and profiles | Installed extensions, manifest permissions, install type (normal, admin, sideload, development), install count, Chrome's third-party risk assessments; store listing details for a bounded set each sync | Chrome Enterprise connector |
| **Microsoft Defender** (Vulnerability Management) | Devices onboarded to Defender for Endpoint | Edge, Chrome and Firefox extensions, installed versions, device counts, Defender's permission descriptions and risk level | Microsoft Entra connector, opt-in |
| **Desktop agent** | Enrolled desktops, when the organization opts in | VS Code, VS Code Insiders, VSCodium, Cursor and Windsurf extensions; JetBrains plugins | Opt-in on this page |

Every connector syncs when an administrator clicks **Sync**. In the nightly maintenance window Orthalon also syncs Chrome Enterprise connectors that use a service account (a pasted access token has expired by then) and Microsoft Entra connectors with Defender browser extensions turned on. Desktop agents report once a day.

### Chrome Enterprise (service account, recommended)

A pasted access token expires within an hour, so drift detection needs a service account:

1. In Google Cloud, enable the **Chrome Management API** and create a service account with a JSON key.
2. In the Google Admin console, open **Security → Access and data control → API controls → Manage domain-wide delegation**, add the service account's client ID, and authorize:
   - `https://www.googleapis.com/auth/chrome.management.reports.readonly` (installed extensions)
   - `https://www.googleapis.com/auth/chrome.management.appdetails.readonly` (store listing details)
   - `https://www.googleapis.com/auth/chrome.management.securityinsights.readonly` (suspicious URL domains; optional — without it the connector reports the gap and still imports extensions)
   - `https://www.googleapis.com/auth/chrome.management.policy` — only if you enable **Allow blocking in a Google org unit**
3. The delegated admin needs **Services → Chrome Management → View Extensions List Report** for the inventory. Google does not document the privilege for App Details in the pages we could check; a super administrator works. Blocking also needs privileges to manage Chrome user settings.
4. In Orthalon, enter the customer ID (`my_customer` works), service-account email, private key and delegated admin.

Each sync reads up to 200 pages of 100 installed apps (20,000 extensions); a larger tenant is marked partial. `countInstalledApps` does not return installed versions. The version Orthalon shows for a Chrome extension comes from Defender or is the **latest store version**, labelled as such.

### Microsoft Defender browser extensions

1. On the Microsoft Entra connector's app registration, add the Microsoft Graph **application** permission `ThreatHunting.Read.All` and grant admin consent.
2. Set **Read Defender browser-extension inventory** to *Yes*.

This reads the `DeviceTvmBrowserExtensions` and `DeviceTvmBrowserExtensionsKB` advanced-hunting tables, which need Defender Vulnerability Management (the premium add-on or standalone). Microsoft Sentinel does not hold these tables. The query is summarised to one row per extension and capped at 5,000 extensions with up to 40 permission descriptions each; a capped result is marked partial and nothing is treated as removed.

### Desktop agents (IDE plugins)

Turn on **Collect IDE plugin metadata from enrolled desktop agents**. Agents ask once a day whether collection is on, and send nothing until it is. To exclude one machine, set `ORTHALON_IDE_PLUGIN_INVENTORY=off` in its managed configuration.

| Editor | Location read |
| :--- | :--- |
| VS Code | `~/.vscode/extensions` (or `VSCODE_EXTENSIONS`) |
| VS Code Insiders | `~/.vscode-insiders/extensions` |
| VSCodium | `~/.vscode-oss/extensions` |
| Cursor | `~/.cursor/extensions` |
| Windsurf | `~/.windsurf/extensions` |
| JetBrains IDEs | macOS `~/Library/Application Support/JetBrains/<Product><Version>/plugins`, Windows `%APPDATA%\JetBrains\<Product><Version>\plugins`, Linux `~/.local/share/JetBrains/<Product><Version>` |

The agent reads only `extensions.json`, each extension's `package.json` and each JetBrains plugin's `META-INF/plugin.xml`. It reports the id, name, publisher, version and declared capability kinds (activation such as start-up, contribution points such as terminal, chat participants, language-model tools and MCP servers, proposed APIs, untrusted-workspace support). It does not read settings, extension storage or workspace files, does not follow links out of the extensions folder, and does not report paths. Plugins bundled inside a JetBrains installation (for example JetBrains AI Assistant on some versions) and remote/WSL extension hosts are not seen.

---

## 2. AI extensions

An item is marked **AI** when its id is in Orthalon's catalogue of known AI assistants (Claude, ChatGPT/Codex, GitHub Copilot, Windsurf/Codeium, Continue, Cline, Roo Code, Kilo Code, Tabnine, Cody, Amazon Q, Gemini Code Assist, JetBrains AI Assistant, Monica, Merlin, Sider, MaxAI, HARPA, Perplexity, Grammarly, QuillBot, Wordtune), when its name matches a catalogued product, or when its name contains an AI keyword. The method is shown with the item. Only an id match carries the product's vendor; a name match keeps the extension's own publisher and, where the catalogue lists ids for that platform, adds the look-alike risk factor. AI items also appear in the AI asset inventory as **AI extension**.

---

## 3. Risk factors

The risk score is the sum of the factors below, capped at 100. Every factor shows the evidence that triggered it and its source. The score describes exposure, not intent: an extension is **confirmed malicious** only when an analyst records that verdict with a reason.

| Factor | Weight | Triggered by |
| :--- | :--- | :--- |
| Broad host access | 25 | `<all_urls>`, `*://*/*` and similar |
| Debugger access | 25 | `debugger` |
| AI site access | 15 | Host access covering ChatGPT, Claude, Gemini, Copilot, Perplexity and other AI sites |
| Reads clipboard / cookies, manages extensions, controls proxy | 15 each | `clipboardRead`, `cookies`, `management`, `proxy` |
| Recent permission expansion | 15 | Expanded in the last 30 days |
| Sideloaded | 20 | Chrome sideload or developer mode; VS Code VSIX install |
| Network observation / modification, script injection, native messaging, history | 10 each | `webRequest`, `webRequestBlocking`, `scripting`, `nativeMessaging`, `history` |
| Look-alike name | 20 | Named like a catalogued AI product but not one of its published ids |
| Not store-hosted, low install base | 10 each | Not in the Chrome Web Store; fewer than 1,000 store users |
| Unverified publisher | 10 | Only when a source states it; unknown is shown as unknown |
| Always active, proposed APIs, agent tooling | 10 each | IDE plugin activates at start-up; uses proposed APIs; contributes chat participants, language-model tools or MCP servers |
| AI assistant | 10 | Classified as AI (above) |

Store-listing permissions count toward risk. Chrome's third-party assessments (CRXcavator, Spin.AI, LayerX) and Defender's risk level are shown separately and are not part of the score.

---

## 4. Permission drift alerts

Orthalon keeps each item's permissions per source and compares every report with the last one from the same source:

- The first report is a baseline, not an alert. A new source for an existing item is its own baseline.
- **Added permissions, host access or capabilities**, a **publisher change**, or a move to a **sideloaded/developer** install raise **one** alert with the before/after versions and the added and removed entries.
- The same transition reported again — a retry, another source, or another device reaching the same version — attaches to the existing alert.
- Reductions and version updates are recorded in history without an alert.

Alerts go to the item's **policy owner** (set on the item). The owner or an administrator acknowledges and resolves them; every step is in the audit log.

---

## 5. Approval and enforcement

Administrators mark each item **Approve**, **Mark for review** or **Deny**. A decision is recorded, not enforced. What happens to a denied item depends on the platform:

| Platform | What Orthalon does | Shown as |
| :--- | :--- | :--- |
| Chrome | **Policy export** (registry, plist, ExtensionSettings entries). Optionally **Block in Google org unit**: sets `chrome.users.apps.InstallType` to `BLOCKED` for the configured org unit through the Chrome Policy API, then reads it back | *Flagged — deploy the policy snippet*, or *Org-unit policy set (verified)* only after the read-back returns `BLOCKED` |
| Edge | Policy export for `ExtensionInstallBlocklist` (registry and plist). Edge Add-ons ids differ from Chrome Web Store ids | *Flagged — deploy the policy snippet* |
| VS Code | Policy export for `AllowedExtensions` (VS Code 1.96+) | *Flagged — deploy the policy snippet* |
| Cursor, Windsurf, VSCodium, JetBrains | None | *Flagged — enforcement unsupported* |

A Chrome org-unit block applies only to managed browsers and managed profiles in that org unit. Approving an extension later does not lift a block in Google; remove it there. Merge exported `ExtensionSettings` entries into your existing policy rather than replacing it, and choose registry value numbers that are not already in use.
