Skip to main content

vulkro extension-audit

Audit installed editor and browser extensions for supply-chain and permission risks. Editor extensions (VS Code, Cursor, Windsurf, VSCodium) and browser extensions (Chrome, Chromium, Brave, Edge, Firefox) run with broad authority on the user's machine: they read every editor buffer or every browser tab, persist data across sessions, and call out to remote endpoints with whatever credentials the host process can reach. A compromised extension is a session- token incident for every site the user is signed into.

By default only editor extensions are scanned. Pass --include-browser to also walk the Chromium-family per-profile Extensions/<id>/<version>/manifest.json tree and the Firefox per-profile extensions.json.

Usage

vulkro extension-audit [PATH] [FLAGS]

Arguments

ArgumentDescriptionDefault
PATHA specific extension manifest file (Chromium manifest.json, VS Code / Cursor / Windsurf / VSCodium extensions.json, or Firefox extensions.json), or a directory containing one. When omitted, the well-known editor locations are scanned (and with --include-browser, browser locations too).(omitted)

Flags

FlagDescriptionDefault
--format, -f <FMT>table, json, ndjson, sarif, gh-pr, junit, csv.table
--require-extensionTreat "no extensions found" as an error (exit 2) instead of a clean exit. Useful in CI jobs that expect an extension manifest to be present.false
--include-browserAlso walk Chromium-family + Firefox per-profile extension manifests. Editor-only by default to keep the audit scoped.false
--fail-on <SEVERITIES>Comma-separated severities that should produce a non-zero exit. Same shape as vulkro scan --fail-on.critical,high

Exit codes

CodeMeaning
0No findings, or --require-extension not set and no extensions found.
1Findings at or above the --fail-on threshold.
2Error: malformed JSON, IO failure, or --require-extension set with no extensions found.

Discovery paths

When <path> is omitted, the auditor walks the following:

Editors (always scanned)

  • ~/.vscode/extensions/extensions.json
  • ~/.vscode-server/extensions/extensions.json
  • ~/.cursor/extensions/extensions.json
  • ~/.windsurf/extensions/extensions.json
  • ~/.vscodium/extensions/extensions.json
  • ~/Library/Application Support/{Code,Code - Insiders,Cursor,Windsurf,VSCodium}/User/extensions/extensions.json (macOS)
  • ~/.config/{Code,Cursor,Windsurf,VSCodium}/User/extensions/extensions.json (Linux)

Browsers (only with --include-browser)

Chromium-family per-profile extension directories (<profile>/Extensions/<id>/<version>/manifest.json):

  • ~/Library/Application Support/Google/Chrome/Default/Extensions (macOS)
  • ~/Library/Application Support/Chromium/Default/Extensions
  • ~/Library/Application Support/BraveSoftware/Brave-Browser/Default/Extensions
  • ~/Library/Application Support/Microsoft Edge/Default/Extensions
  • ~/Library/Application Support/Arc/User Data/Default/Extensions
  • ~/.config/{google-chrome,chromium,BraveSoftware/Brave-Browser,microsoft-edge}/Default/Extensions (Linux)
  • Profile 1 sibling of each Default profile

Firefox profile directories (the auditor reads the extensions.json addons array under each profile dir):

  • ~/Library/Application Support/Firefox/Profiles/ (macOS)
  • ~/.mozilla/firefox/ (Linux)

Missing paths are skipped silently.

Rules

The auditor emits stable finding IDs in the EXT-NNN family.

IDRuleSeverity
EXT-001Installed (ecosystem, identifier, version) matches the Vulkro compromised-extension catalog.Critical / High (from catalog row)
EXT-002Manifest declares overbroad permissions: <all_urls> (or *://*/*), the debugger API, webRequestBlocking, or multiple broad API permissions declared together.High / Medium
EXT-003Manifest CSP allows unsafe-eval or unsafe-inline inside script-src or default-src. Lets the extension load arbitrary JavaScript at runtime.High

Inventory envelope

--format json emits both findings and a discovery inventory:

{
"findings": [ /* SecurityFinding records */ ],
"extension_inventory": {
"paths_checked": [
"/Users/me/.cursor/extensions/extensions.json",
"/Users/me/Library/Application Support/Google/Chrome/Default/Extensions/pajkjnmeojmbapicmbpliphjmcekeaac/24.10.4/manifest.json"
],
"paths_with_configs": [
"/Users/me/.cursor/extensions/extensions.json"
],
"extensions": [
{
"identifier": "ms-python.python",
"version": "2025.0.0",
"source": "/Users/me/.cursor/extensions/extensions.json",
"ecosystem": "vscode-marketplace"
}
]
}
}

ecosystem is one of vscode-marketplace, open-vsx, chrome-webstore, firefox-amo, or unknown. Aligns with the catalog's ecosystem column so the same identifier can be looked up across surfaces.

Examples

# Default: editor extensions only.
vulkro extension-audit

# Editor + browser surfaces.
vulkro extension-audit --include-browser

# Audit a single browser extension manifest explicitly.
vulkro extension-audit ~/Library/Application\ Support/Google/Chrome/Default/Extensions/pajkjnmeojmbapicmbpliphjmcekeaac/24.10.4/manifest.json

# CI gate: require at least one extension to exist and fail on
# critical or high findings.
vulkro extension-audit --require-extension --fail-on critical,high

# Stream NDJSON into jq.
vulkro extension-audit --include-browser --format ndjson | jq 'select(.severity == "critical")'
  • vulkro mcp-audit - same shape, but for MCP host configs.
  • vulkro scan - the broader pipeline; SUP-COMPROMISE-006 (compromised extension via the catalog) also surfaces here when an extension manifest appears in a scanned tree.
  • vulkro respond - "is THIS advisory or package in my project?" in under a second.
  • vulkro explain EXT-001 (and the rest) renders per-rule rationale even when no live finding hits.
  • Confidence model - how EXT findings are calibrated against the per-category rubric.