ktg-plugin-marketplace/plugins/llm-security/knowledge/ide-extension-threat-patterns.md
Kjell Tore Guttormsen 6252e55700 feat(llm-security): add /security ide-scan — VS Code / JetBrains extension prescan (v6.3.0)
New standalone scanner (prefix IDE) discovers installed VS Code extensions
across forks (Cursor, Windsurf, VSCodium, code-server, Insiders, Remote-SSH)
and runs 7 IDE-specific threat checks: blocklist match (CRITICAL),
theme-with-code, sideload (unsigned .vsix), dangerous uninstall hook (HIGH),
wildcard activation, extension-pack expansion, typosquat (MEDIUM).

Per-extension reuse of UNI/ENT/NET/TNT/MEM/SCR scanners with bounded
concurrency. Offline-first; --online opt-in. JetBrains discovery stubbed
for v1.1. 22 new tests (1296 total, was 1274).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-17 16:23:35 +02:00

6.3 KiB
Raw Blame History

IDE Extension Threat Patterns

Detection categories used by scanners/ide-extension-scanner.mjs (prefix IDE). Based on Koi Security / ExtensionTotal research 2024-2026 and VS Code / JetBrains official documentation.

Research brief: /Users/ktg/.claude/plans/research-ide-extension-prescan.md.

Scope

MVP (v6.3.0): VS Code + forks (Cursor, Windsurf, VSCodium, code-server, Insiders, Remote-SSH). IntelliJ plugins deferred to v1.1 — JetBrains manual-review + opt-in signing reduces public case-study volume.

1. Blocklist Match (CRITICAL)

Signal: Extension ID (lowercased publisher.name) matches entry in knowledge/top-vscode-extensions.json blocklist array.

Case: TigerJack (11 malicious extensions, 17K+ installs). WhiteCobra (24 extensions, ~$500K crypto theft). VS Code Cryptojacking Campaign ("Mark H" impersonator, 1M+ installs). Known-malicious IDs are CRITICAL.

Format: publisher.name@version or publisher.name@* for any version.

OWASP: LLM03 (Supply Chain), ASI04.

2. Theme-with-Code (HIGH)

Signal: package.json categories includes "Themes" AND (main is truthy OR activationEvents non-empty).

Case: "A Wolf in Dark Mode" — the Material Theme malware. Popular theme with hidden malware under color-scheme. Pure themes require zero runtime code; any main/activationEvents on a theme is a strong red flag.

OWASP: LLM06 (Excessive Agency), ASI02.

3. Sideload Signal (HIGH unsigned, MEDIUM signed)

Signal: extensions.json entry has metadata.source === "vsix" (i.e. installed from file, not Marketplace).

Rationale: Marketplace signature verification and malware-scan bypassed for .vsix-file installs. Legitimate use cases exist (private extensions, dev testing), but high malware-ratio in observed incidents.

Modifier: If .signature.p7s file present in extension root → downgrade to MEDIUM (possibly Marketplace-downloaded .vsix).

OWASP: LLM03.

4. Broad Activation Surface (MEDIUM / LOW)

Signal: package.json activationEvents includes "*" (MEDIUM) or "onStartupFinished" (LOW).

Rationale: "Wants to run always" is a strong capability signal — necessary for a few legitimate tools (shell integrators, system monitors) but unusual for most extensions. Exemption: exact-match against top-100 list.

Note: VS Code 1.74+ no longer requires activationEvents for declarative contributes — absence of events is NOT suspicious.

OWASP: LLM06.

5. Typosquat (HIGH / MEDIUM)

Signal: Extension ID has Levenshtein distance ≤ 2 from a top-100 extension ID, excluding exact match.

  • Distance 1 → HIGH
  • Distance 2 AND target is in top-50 → MEDIUM

Case: TigerJack aliases ab-498, 498, 498-00 targeting popular AI / utility extensions. Publisher impersonation (e.g. ms-pythom.pythom vs ms-python.python). AI-assistant typosquats (claude-code, codeium, cody).

OWASP: LLM03.

6. Extension Pack Expansion (MEDIUM)

Signal: package.json extensionPack array contains ≥ 3 bundled extension IDs.

Rationale: Extension packs amplify trust chain — installing one extension installs N others, each of which brings its own risk surface.

OWASP: LLM03.

7. Dangerous Uninstall Hook (HIGH / LOW)

Signal: package.json scripts["vscode:uninstall"] exists AND references one of: child_process, curl, wget, rm, powershell, iex, Invoke-Expression, Start-Process.

Rationale: Uninstall scripts are a persistence hook — attacker can delay destructive payload to trigger on uninstall attempt. VS Code runs these scripts with the user's privileges.

OWASP: LLM06, ASI02.

8. Data Exfiltration Patterns (delegated)

Detected by reused scanners on extension bundled source:

  • Hardcoded webhooks (Discord, Pipedream, webhook.site, Burp Collaborator, interactsh) → detected by NET scanner
  • Base64-encoded C2 domains → detected by ENT scanner
  • Unicode Tag steganography (GlassWorm pattern) → detected by UNI scanner
  • Env var exfiltration (process.env.HOME, SSH keys, .aws/credentials, .env) → detected by TNT scanner
  • Clipboard / screen capture misuse → detected by NET + TNT via API surface

Cases: GlassWorm (Unicode steganography + blockchain C2), MaliciousCorgi (AI-assistant data leaks), VS Code Cryptojacking (PowerShell download-and-execute), screen-capture malware ("Bitcoin Black", "Codo AI").

OWASP: LLM01 (Prompt Injection), LLM02 (Sensitive Disclosure), LLM03.

9. Nested npm Supply Chain (delegated)

Detected by SCR scanner on extension's bundled package-lock.json or flat package.json dependencies.

Rationale: A typical VS Code extension with main bundles 50500+ transitive npm deps. VS Code Marketplace malware-scan does NOT inspect nested deps. Compromised npm packages (event-stream, rc, nx, ua-parser-js, lottie-player) flow into extensions automatically at build time.

OWASP: LLM03, ASI04.

10. Memory Poisoning via README / CHANGELOG (delegated)

Detected by MEM scanner on extension README.md and CHANGELOG.md.

Rationale: Extension README is displayed in VS Code when user inspects extension details. Prompt-injection payloads in README can poison co-located LLM assistants (Copilot, Claude Code) if the user asks about the extension.

OWASP: LLM01.

Known Limitations

  • No bytecode analysis of IntelliJ JARs (v1.1+)
  • No VSIX extraction (pass extracted directory instead)
  • No Marketplace API lookups without --online flag (publisher age, download count, verified status unavailable offline)
  • Profile-specific extension filtering not implemented (all installed extensions are scanned)
  • .obsolete file parsing not implemented (extensions marked obsolete are still scanned — harmless but redundant)
  • Real-time IDE hooks are out of scope (separate repo, planned)

References