ktg-plugin-marketplace/plugins/llm-security/commands/ide-scan.md
Kjell Tore Guttormsen 03b8885b6e chore(llm-security): v7.7.2 — language consistency pass
~/.claude/CLAUDE.md specifies English for code and documentation,
Norwegian for dialog only. Norwegian had crept into surface text
across v7.5-v7.7. Translated to English in eight surfaces.

No scanner, hook, or behavior changes — purely surface text.

- 18 skill commands: the HTML Report-step now reads "HTML report:
  [Open in browser]" instead of "HTML-rapport: [Åpne i nettleser]"
- scripts/lib/report-renderers.mjs: key-stat labels, lede defaults,
  table headers, maturity-ladder descriptions, action-tier labels,
  clean buckets, dry-run/apply copy, and JS comments. Regex
  alternations /^high|^høy/ and /resolution|løsning/i preserved.
- playground/llm-security-playground.html: same renderer changes
  mirrored bit-identical, plus playground-only UI strings (catalog,
  breadcrumb aria-label, theme toggle, builder-modal hint,
  guide-panel "no projects yet", delete confirmation, alert/copy).
  Demo-state fixture content for dft-komplett-demo preserved
  (intentional Norwegian persona).
- agents/skill-scanner-agent.md + agents/mcp-scanner-agent.md:
  Generaliseringsgrense + Parallell Read-strategi sections translated
  to Generalization boundary + Parallel Read strategy.
- README.md: playground architecture prose + Recent versions table
  (v7.5.0 — v7.7.1).
- CLAUDE.md: v7.7.1 highlights translated, new v7.7.2 highlights
  added.
- ../../README.md: llm-security v7.5.0 — v7.7.1 bullets.
- ../../CLAUDE.md: llm-security catalog entry.
- docs/scanner-reference.md: six runnable-examples table cells.
- docs/version-history.md: new v7.7.2 entry. v7.5-v7.7 narrative
  sections left in original language (deferred per operator).
- Version bumped 7.7.1 → 7.7.2 in package.json,
  .claude-plugin/plugin.json, README badge + Recent versions,
  CLAUDE.md header + state, docs/version-history.md, playground
  renderHome hardcoded string, root README + CLAUDE.md llm-security
  entries.

Tests: 1820/1820 green. CLI smoke-test: 18/18 commandIds produce
>138 KB self-contained HTML. Browser-dogfood verified.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-19 06:47:44 +02:00

6.2 KiB

name description allowed-tools model
security:ide-scan Scan installed VS Code + JetBrains (IntelliJ IDEA, PyCharm, GoLand, WebStorm, Android Studio, …) extensions/plugins for supply-chain risk, typosquats, obfuscation, and malicious patterns. Accepts Marketplace / OpenVSX / direct VSIX URLs and JetBrains Marketplace URLs. Read, Glob, Grep, Bash sonnet

/security ide-scan

Scan installed IDE extensions. Both families covered:

  • VS Code + forks — Cursor, Windsurf, VSCodium, code-server, Insiders, Remote-SSH.
  • JetBrains plugins — discovery from installed plugin dirs, URL fetch from JetBrains Marketplace. IntelliJ IDEA, PyCharm, GoLand, WebStorm, RubyMine, PhpStorm, CLion, DataGrip, RustRover, Rider, Aqua, Writerside, Android Studio. Fleet and Toolbox are excluded (different plugin model).

Runs the IDE scanner plus reused scanners (UNI, ENT, NET, TNT, MEM, SCR) per extension. Offline by default.

Step 1: Run Scanner

Run the IDE extension scanner:

node <this plugin's scanners/ide-extension-scanner.mjs> [target]

Arguments (pass through as provided by the user):

  • [target] — one of:
    • omit, ., or all → discover all installed extensions
    • absolute path to an extracted extension directory → single-scan mode
    • https://marketplace.visualstudio.com/items?itemName=<publisher>.<name> → fetch from VS Code Marketplace
    • https://open-vsx.org/extension/<publisher>/<name>[/<version>] → fetch from OpenVSX
    • https://example.com/path/foo.vsix → direct VSIX download (HTTPS only)
    • https://plugins.jetbrains.com/plugin/7973-intellivue → JetBrains Marketplace (numericId resolved to xmlId via metadata, then downloaded)
    • https://plugins.jetbrains.com/plugin/download?pluginId=com.example.plugin[&version=1.2.3] → direct JetBrains plugin download
    • GitHub repo URLs are NOT supported (would require build step)
  • --vscode-only / --intellij-only — restrict discovery
  • --include-builtin — include Microsoft builtin extensions (default: excluded)
  • --online — enable Marketplace/OSV.dev lookups (opt-in; default: fully offline)
  • --format compact|json — output format
  • --fail-on <severity> — exit 1 if findings at/above severity

URL mode notes:

  • Hardened ZIP extractor with caps: 50MB compressed, 500MB uncompressed, 100x expansion ratio, 10 000 entries, depth 20. No fuzz-testing results published to date.
  • Rejects: zip-slip paths, symlink entries, absolute paths, drive letters, encrypted entries, ZIP64.
  • TLS verified, HTTPS only, 30s timeout. Cross-host redirects rejected.
  • Temp directory always cleaned up (success, error, abort).
  • meta.source in the envelope contains { type: "url", kind, url, finalUrl, sha256, size, publisher, name, version }.

Parse the JSON output. The result contains:

  • meta.scanner, meta.version, meta.target, meta.extensions_discovered (per type), meta.roots_scanned, meta.warnings
  • extensions[] — per-extension results with id, version, type, publisher, source, is_builtin, signed, scanner_results (IDE/UNI/ENT/NET/TNT/MEM/SCR), aggregate (counts, risk_score, risk_band, verdict), warnings
  • aggregate — top-level counts, risk_score, risk_band, verdict, extensions_total, extensions_blocked, extensions_warning

Step 2: Format Report

Present the results:

# IDE Extension Scan

| Field | Value |
|-------|-------|
| **Scanner** | ide-extension-scanner v[version] |
| **Target** | [target] |
| **Roots** | [comma-separated roots_scanned] |
| **Extensions** | [vscode] VS Code, [jetbrains] JetBrains |
| **Top Verdict** | [ALLOW/WARNING/BLOCK] |
| **Risk** | [risk_score]/100 ([risk_band]) |
| **Duration** | [duration_ms]ms |

## Counts

crit=[N] high=[N] medium=[N] low=[N] info=[N]

## Per-Extension Results

[One row per extension, sorted: BLOCK first, then WARNING, then ALLOW with findings]

| Extension | Version | Source | Verdict | Risk | Top Issue |
|-----------|---------|--------|---------|------|-----------|

Omit ALLOW rows with zero findings unless the user passed `--verbose`.

## Top Findings

[For each extension with verdict != ALLOW, list up to 3 findings as:
  - [SEV] [SCANNER]: title — file:line — recommendation]

## Warnings

[Any top-level or per-extension `warnings` entries, if present]

Step 3: Recommendations

  • aggregate.verdict === 'BLOCK': "One or more extensions are block-listed. Uninstall immediately — code --uninstall-extension <id>."
  • aggregate.verdict === 'WARNING': "High/medium findings detected. Review the Top Findings list. Audit suspicious extensions before continuing."
  • aggregate.verdict === 'ALLOW' and counts.info > 0: "Extensions look clean. Info-level findings are observational only."
  • aggregate.extensions_total === 0: "No extensions discovered. Run code --list-extensions to confirm, or pass a specific path."

If the user has many sideloaded (source=vsix) extensions: suggest re-installing from Marketplace where possible.

Notes

  • First run with no --online is fully offline.
  • Pass a single extracted extension directory to scan just one extension.
  • JetBrains plugins are additionally checked for Premain-Class javaagents, application-components lifecycle hooks, native binaries (.so/.dylib/.dll/.jnilib), long <depends> chains, typosquats vs top JetBrains plugins, and shaded-jar advisories (see knowledge/ide-extension-threat-patterns.md).

Step 4: HTML Report

After producing the markdown IDE-scan report above:

  1. Compute a temp markdown path:

    node -p "require('path').join(require('os').tmpdir(), 'sec-ide-scan-' + Date.now() + '.md')"
    
  2. Use the Write tool to save the entire markdown report you just produced (scanner header table + counts + Per-Extension Results table + Top Findings + Warnings + Recommendations + Notes) to that temp path. Verbatim.

  3. Run the renderer:

    node <plugin-root>/scripts/render-report.mjs ide-scan --in "<temp-md-path>"
    

    The CLI writes reports/ide-scan-<YYYYMMDD-HHmmss>.html relative to CWD and prints file:///abs/path.html on stdout.

  4. Append to your response (markdown link, no bare URL):

    HTML report: Open in browser

If the CLI exits non-zero, mention the error but do not block — the markdown report above is the primary deliverable.