- jetbrains-research-brief.md: 29 sources, confidence 0.88 — input for v6.6.0 JetBrains/IntelliJ extension scanning. Covers plugin format, install paths per OS+product, Marketplace API, threat landscape (zero confirmed-malicious cases), check-mapping table, sandbox reuse verdict, risk register. - ide-scan-url-support.md: retroactive plan doc for v6.4.0 URL-fetch feature.
32 KiB
| type | created | question | confidence | dimensions | mcp_servers_used | local_agents_used | external_agents_used | |||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ultraresearch-brief | 2026-04-17 | Extend /security ide-scan (llm-security v6.6.0) to cover JetBrains / IntelliJ plugins, mirroring the VS Code v6.3-v6.5 work (discovery + URL fetch + OS sandbox). | 0.88 | 7 |
|
|
JetBrains/IntelliJ Extension Security Scanning — v6.6.0 Research Brief
Generated by ultraresearch-local v1.0 on 2026-04-17
Research Question
Can we replicate the v6.3–v6.5 VS Code/VSIX work for JetBrains/IntelliJ plugins in /security ide-scan, and what is the authoritative technical + threat context needed to plan it?
Specifically: (1) plugin format, (2) install locations per OS and product, (3) JetBrains Marketplace API, (4) 2024–2026 threat landscape, (5) check-mapping from 7 VS Code checks to JetBrains equivalents, (6) reusability of existing sandbox/zip/fetch primitives, (7) risks and JetBrains-only concerns.
Executive Summary
Feasible and well-scoped. The existing VS Code pipeline (lib/zip-extract.mjs, lib/vsix-sandbox.mjs, lib/vsix-fetch.mjs, lib/ide-extension-discovery.mjs, lib/ide-extension-parser.mjs) is ~80% reusable — all routing, CLI flags, envelope counters, data loader, and sandbox primitives already accept a 'jetbrains' type. The 4 real implementation gaps are: (1) directory walk in discoverJetBrainsExtensions, (2) META-INF/plugin.xml XML parser in parseIntelliJPlugin (nested-jar extraction required), (3) populated knowledge/top-jetbrains-plugins.json, (4) type === 'jetbrains' branch in scanOneExtension. Key caveat: zero publicly-confirmed malicious plugins on JetBrains Marketplace — the blocklist must be a typosquat-seed corpus, not a confirmed-bad list. Secondary caveat: signing is advisory (warning-not-block, YouTrack IJPL-212393 confirms warning sometimes absent); the highest-value IDE-specific check is sideload detection, per OX Security 2025 research demonstrating verified-badge bypass on IntelliJ.
Dimensions
Plugin Format — Confidence: high
Local findings:
lib/ide-extension-parser.mjs:101-112—parseVsixFileandparseIntelliJPluginare both stubs; onlyparseVSCodeExtensionis implemented. JetBrains path returnsnull.lib/zip-extract.mjs(entire file) — format-agnostic ZIP parser with zip-slip/symlink/absolute/ratio defences. ZIP-inside-ZIP extraction is supported (caller concatenates calls).
External findings:
- Distribution: either
.jar(no bundled deps, legacy) or.zip(with deps, modern Gradle default). Source: plugin-content.html. - ZIP layout:
<artifact>/lib/<main>.jar + lib/<dep>.jar.META-INF/plugin.xmllives INSIDE the main jar, not at ZIP root. Scanner must open outer ZIP → find main jar inlib/→ open main jar → readMETA-INF/plugin.xml. - Installed plugins on disk are already extracted by the IDE (directory form, not zip). Sideloaded URL downloads are zip form.
plugin.xmlschema elements relevant for scanning:<id>,<name>,<version>,<vendor url email>,<description>,<depends optional config-file>,<idea-version since-build until-build>,<actions>,<extensions defaultExtensionNs="com.intellij">with children likeapplicationService,projectService,postStartupActivity,backgroundPostStartupActivity,applicationListener,projectListener,themeProvider. Legacy<application-components>/<project-components>still supported and appear in older plugins.require-restartattribute on<idea-plugin>controls dynamic loading.Premain-ClassinMETA-INF/MANIFEST.MF= Java agent (bytecode instrumentation) — extremely high-risk signal.
Install Locations per OS — Confidence: high
External findings (per-product confirmed):
| Product | Directory string | macOS root | Linux plugins | Windows root |
|---|---|---|---|---|
| IntelliJ IDEA Ultimate | IntelliJIdea{YYYY.N} |
~/Library/Application Support/JetBrains/ |
~/.local/share/JetBrains/ |
%APPDATA%\JetBrains\ |
| IntelliJ IDEA Community | IdeaIC{YYYY.N} |
same | same | same |
| PyCharm Professional | PyCharm{YYYY.N} |
same | same | same |
| PyCharm Community | PyCharmCE{YYYY.N} |
same | same | same |
| WebStorm | WebStorm{YYYY.N} |
same | same | same |
| GoLand | GoLand{YYYY.N} |
same | same | same |
| PhpStorm | PhpStorm{YYYY.N} |
same | same | same |
| RubyMine | RubyMine{YYYY.N} |
same | same | same |
| CLion | CLion{YYYY.N} |
same | same | same |
| DataGrip | DataGrip{YYYY.N} |
same | same | same |
| Rider | Rider{YYYY.N} |
same | same | same |
| RustRover | RustRover{YYYY.N} |
same | same | same |
| DataSpell | DataSpell{YYYY.N} |
same | same | same |
| Android Studio | AndroidStudio{version} |
~/Library/Application Support/Google/ (NOT JetBrains) |
~/.config/Google/ |
%APPDATA%\Google\ |
| Aqua | Aqua{YYYY.N} |
same (discontinued April 2025, legacy installs remain) | same | same |
| Fleet | separate ecosystem — exclude from scanner | n/a | n/a | n/a |
Critical Linux quirk: config lives under ~/.config/JetBrains/<Product>/ but plugins live under ~/.local/share/JetBrains/<Product>/plugins/. This is different from macOS/Windows where both are co-located.
Local findings:
lib/ide-extension-discovery.mjs:38-53—getJetBrainsBaseDir()already returns macOS/Windows/Linux base dirs correctly, but Linux points to~/.local/share/JetBrains(correct for plugins).- Currently does NOT handle Android Studio (Google/ prefix) — needs second base-dir function.
Contradictions:
- The existing
getJetBrainsBaseDir()returns a single base dir, but Android Studio uses a separate vendor prefix (Google/notJetBrains/). Resolution: add a second discovery root for Android Studio, or generalize to accept a list of{vendor, productRegex}tuples.
JetBrains Marketplace API — Confidence: high (live calls confirmed)
External findings:
- Base:
https://plugins.jetbrains.com/ - Lookup by numeric ID:
GET /api/plugins/{numericId}→ returns{id, name, xmlId, vendor:{name, isVerified}, downloads, pricingModel, family, tags, link}. Confirmed live with id=1347 (Scala). - Lookup by xmlId:
GET /plugins/list?pluginId={xmlId}(documented).GET /api/plugins?xmlId=...returns HTTP 400 — do NOT use. - Version listing:
GET /api/plugins/{numericId}/updates?size=N→ array of{id, version, file, cdate, since, until, size, downloads, pluginId, author:{isJetBrains, name}}. Confirmed live. - Download latest compatible:
GET /pluginManager?action=download&id={xmlId}&build={productCode}-{buildNumber}→ redirect to file. - Download specific version:
GET /plugin/download?pluginId={xmlId}&version={v}→ redirect. - Direct file download:
GET /files/{file-path-from-update-object}(e.g./files/1347/991561/scala-intellij-bin-2025.3.39.zip). - URL-to-ID resolution:
https://plugins.jetbrains.com/plugin/7973-intellivue→ numeric ID is7973(first path segment before dash). - Auth: none for reads. Rate limits not publicly documented.
- OpenVSX equivalent: none confirmed. JetBrains Marketplace is effectively the only public registry. Custom repositories supported via
updatePlugins.xmlon arbitrary HTTPS servers (enterprise).
Threat Landscape 2024–2026 — Confidence: high (for documented incidents); medium (for absence-of-evidence)
External findings (security + community):
- CVE-2024-37051 (CVSS 9.3, June 2024) — first-party JetBrains GitHub plugin. Malicious PR content exfiltrates OAuth/PAT tokens. 15 IDEs affected 2023.1+. Patched.
- CVE-2025-64671 (2025) — GitHub Copilot for JetBrains. Same attack-surface pattern.
- CVE-2025-57729 (CVSS 6.5, Aug 2025) — unexpected LSP plugin startup.
- CVE-2025-68269 (CVSS 5.4, Dec 2025) — remote project trust bypass.
- CVE-2025-64456 (CVSS 8.4, 2025) — ReSharper DPA Collector missing sig verification → local privilege escalation.
- Log4Shell propagation (Dec 2021): JetBrains used "API Watcher" to identify plugins bundling log4j; temporarily hid affected versions, no public list of affected plugin names.
- OX Security (July 2025, Nir Zadok & Moshe Siman-Tov Bustan): demonstrated verified-badge bypass on IntelliJ IDEA via sideloaded
.zipwith spoofed verification values. JetBrains response: "not from Marketplace, user responsibility." Sideload is therefore the primary remaining attack vector that JetBrains does not treat as a vendor bug. - Third-party Marketplace malicious plugins: zero publicly confirmed cases as of April 2026. This is material: the blocklist file CANNOT be seeded with confirmed-malicious entries because none exist publicly. Seed as typosquat-comparison corpus only.
- Plugin signing reality: Warning-not-block. YouTrack IJPL-212393 confirms warning sometimes absent. Custom-repository plugins do not get JetBrains CA re-signing — enterprise can self-sign with arbitrary chain.
- No sandbox: JetBrains' own docs explicitly acknowledge: "Plugins run as part of the IDE and have the same access rights as the IDE itself… Uninstalling does not guarantee all effects are undone." This is structurally identical to VS Code — no sandboxing, full user-privilege execution on project open.
Trust-model observations:
vendor.isVerifiedfrom Marketplace API is the strongest trust signal but confirms identity, not code safety.vendor.emailandvendor.urlare optional, unvalidated, template-friendly — weak signals.- Plugin ID
Lombook Pluginis a legitimate pre-existing typo in the real Lombok plugin (Marketplace ID 6317). Scanner must whitelist this exact string; a plugin namedLombokorLombokPluginwould be the suspicious one.
Check Mapping (7 VS Code checks → JetBrains) — Confidence: high
| VS Code Check | JetBrains Equivalent | Signal source | Status |
|---|---|---|---|
| Blocklist match | Same concept, different ID namespace (xmlId) |
plugin.xml <id> vs knowledge/top-jetbrains-plugins.json[blocklist] |
Reusable — needs populated blocklist (seed-only, no confirmed-bad) |
| Theme-with-code | Plugin declares <themeProvider> as only extension, OR declares it alongside services/actions/listeners |
plugin.xml extension count + element types |
Needs-new logic (JetBrains has no categories: ["Themes"] manifest field — infer from <themeProvider> presence) |
| Sideload detection | Sideloaded plugin = installed via "Install Plugin from Disk" or directly dropped into plugins dir | On-disk scan: no reliable filesystem marker. Confidence: low — JetBrains does not mark sideloaded vs Marketplace-installed on disk. Only URL-target mode reliably knows provenance. | Partial — URL mode = always-sideload; on-disk mode = cannot distinguish reliably. Emit LOW advisory for on-disk plugins with vendor.isVerified=false (queried from Marketplace by xmlId). |
Broad activation (* / onStartupFinished) |
<application-components> OR AppLifecycleListener with appStarted (highest risk); <postStartupActivity> / <backgroundPostStartupActivity> (medium); applicationService with preload="true" (medium) |
plugin.xml extension/listener declarations |
Needs-new logic with JetBrains-specific ranking |
| Typosquat (Levenshtein vs top list) | Same algorithm, different corpus (xmlIds) | plugin.xml <id> vs knowledge/top-jetbrains-plugins.json[jetbrains] |
Reusable — needs populated corpus (50+ xmlIds identified, see Q5 in community findings) |
| Extension-pack expansion | <depends> chain — required vs optional="true" |
plugin.xml <depends> elements |
Needs-adaptation |
| Dangerous uninstall hooks | No direct equivalent. JetBrains has DynamicPluginListener.beforePluginUnload but plugin's own code runs, not a manifest-declared script like vscode:uninstall |
— | Skip (no parallel); document in knowledge as "Known Limitations" |
JetBrains-only checks (new categories):
- Java agent declaration (
Premain-Classin MANIFEST.MF): HIGH severity — bytecode instrumentation capability. - Native binary bundling:
.dll/.so/.dylib/.exeinside jar resource directories. Legitimate for some plugins (jssc serial port) but also a confirmed implant delivery vector. Log SHA-256 + size. - Legacy
<application-components>: blocks dynamic loading, fires at IDE launch. MEDIUM advisory. - Shaded jar detection: bundled jar where
META-INF/MANIFEST.MFlacks Maven coordinates. Cannot audit via OSV.dev. MEDIUM advisory.
Sandbox / Primitive Reusability — Confidence: high
Local findings (validated against memory note on sandbox reuse):
lib/zip-extract.mjs— fully reusable, format-agnostic (ZIP is ZIP). Existing zip-slip/symlink/absolute/ratio/depth/entries caps apply unchanged to JetBrains.zip.lib/vsix-sandbox.mjs:buildSandboxProfile, buildBwrapArgs— fully reusable, no VS-Code-specific strings.lib/vsix-sandbox.mjs:buildSandboxedWorker, runVsixWorker— needs-adaptation:WORKER_PATHis hardcoded tovsix-fetch-worker.mjs. Generalize to acceptworkerPathparameter (or create wrapperrunPluginWorker(url, tmpDir, workerPath, opts)).lib/vsix-fetch.mjs— transport primitives (httpsFetch,readBodyCapped,httpsFetchSameHost) fully reusable. Routing (detectUrlType,fetchMarketplaceVsix,fetchOpenVsxVsix) VS-Code-specific: addfetchJetBrainsPlugin()arm and extenddetectUrlTypeto recognizeplugins.jetbrains.com/plugin/...URLs.- Redirect whitelist: add
plugins.jetbrains.com,downloads.marketplace.jetbrains.com,cache-redirector.jetbrains.com(verify during implementation via redirect observation). lib/vsix-fetch-worker.mjs— create siblinglib/jetbrains-fetch-worker.mjswith same IPC protocol (--url,--tmpdirargv → single stdout JSON line with{ok, sha256, size, finalUrl, source, extRoot}).extRootdetection differs: look for top-level dir containinglib/rather thanextension/.- Reused scanners (UNI/ENT/NET/TNT/MEM/SCR):
- UNI, ENT: fully reusable (text scanning, format-agnostic).
- NET: minor adaptation — add JetBrains CDN hosts to trusted-domains set.
- TNT: minor adaptation — add
.kt,.groovy,.scalatoCODE_EXTENSIONS(currently has.javabut not Kotlin etc.). - MEM: reusable but low-recall for JetBrains —
MEMORY_FILE_PATTERNSwon't match JetBrains filenames. Workaround: inscanOneExtensionJetBrains branch, includeplugin.xmland README files inmemFiles. - SCR: fully reusable — gracefully no-ops on JetBrains plugins (no npm/pip lockfiles).
Risks / Unknowns — Confidence: medium
What makes this harder than VS Code:
- Nested ZIP extraction for installed plugins on disk. When scanning installed plugins, JetBrains plugins on disk are already extracted — directory form, main jar still a ZIP. Scanner must ZIP-extract the main jar to read
plugin.xml. This is one more layer than VS Code (wherepackage.jsonis plain on disk). - Bundled JAR dependency staleness. Every plugin ships its own
lib/*.jarcopies. No lockfile. Log4Shell propagated this way in 2021. Tier-1 mitigation: parseMETA-INF/MANIFEST.MFforImplementation-Title/Implementation-Version, batch-query OSV.dev Maven ecosystem. Shaded jars (coordinates stripped) flag as "cannot audit." - Android Studio vendor prefix divergence. Single
getJetBrainsBaseDir()insufficient — Android Studio usesGoogle/AndroidStudio<version>/under the normal OS base. Generalize discovery. - No OSV ecosystem for JetBrains plugin IDs. Only the bundled Maven deps are OSV-queryable. Third-party plugin IDs have no canonical vulnerability database.
- Signing is advisory.
hasSignaturefield inParsedManifestis unreliable — IDE warns but does not block; warning sometimes absent (YouTrack IJPL-212393). Use only as a weak INFO signal. - Zero-public-malicious-plugin dataset. Blocklist must be structurally seed-only. Typosquat corpus is high-value; "confirmed bad" section starts empty.
- Kotlin (
.kt) not in TNT's CODE_EXTENSIONS. Will silently skip Kotlin-authored plugins for taint analysis. Add.kt,.groovy,.scala. - Fleet plugins are a different ecosystem (separate SDK, Kotlin Multiplatform) — explicitly exclude; do not attempt to parse.
Premain-Class= high-severity signal (Java agent / bytecode instrumentation). Community finding — not present in existing check taxonomy.- Native binaries in jars = medium-high signal. Confirmed implant delivery vector (Nextron Systems on trojanized Material Icon Theme). Log SHA-256 + size.
Not found / gaps:
- Marketplace API rate limits (not publicly documented).
- Whether IDE re-verifies plugin signatures on every load vs install-time only.
- Whether sideloaded plugins get any runtime re-validation.
- No academic paper specifically on JetBrains plugin malware analysis (2023–2026).
Local Context
Architecture
From architecture-mapper: the orchestrator scanners/ide-extension-scanner.mjs already routes on type === 'vscode' | 'jetbrains', already counts meta.extensions_discovered.jetbrains, already parses --intellij-only CLI flag. The call graph is already built — scanOneExtension is the only place that unconditionally dispatches to parseVSCodeExtension; needs branch.
Dependencies
From architecture-mapper: lib/zip-extract.mjs is the reusable foundation. lib/vsix-sandbox.mjs generalizes with one parameter (WORKER_PATH). The main new dependency is an XML parser for plugin.xml — zero-dep constraint mandates either hand-rolled DOM-lite (regex-based for simple fields + minimal recursive-descent for nested elements) or use of Node.js built-in primitives. No third-party XML deps permitted per CLAUDE.md "Null npm dependencies in hooks/scanners."
Conventions
From project CLAUDE.md and code inspection: test harness is node:test, fixtures under tests/fixtures/<feature>/, scanner prefixes per scanner (IDE for top-level, UNI/ENT/NET/TNT/MEM/SCR for reused). JetBrains additions must preserve scanner prefix IDE; may introduce new finding type codes (e.g. IDE-JB-01 theme-with-code, IDE-JB-02 broad-activation, etc.).
History
Task-finder located the exact canonical backlog entry: TODO.md:14 — v6.6.0-kandidater: JetBrains-discovery (v1.1-stub i dag). This is the user-sanctioned scope.
External Knowledge
Best Practice
- Parse
META-INF/plugin.xmlfrom inside main jar (inside outer zip). Official pattern. - Use Marketplace REST API for xmlId→verified/downloads/vendor enrichment. Batch via
/api/plugins/{id}. - OSV.dev batch API (
POST /v1/querybatch) with Maven ecosystem queries for bundled jars. - For sideload detection on URL target: always-sideload (by definition of URL install). For on-disk target: query Marketplace API by xmlId; if
vendor.isVerified === falseand plugin has no directory-level signature marker, emit LOW advisory.
Alternatives
Considered and rejected:
- Java bytecode decompilation — requires JVM subprocess. Out of scope for zero-dep v6.6.0. Defer as v6.7+ if demand emerges.
- Scanning all bundled jars as first-class extensions — explodes scope. Plan: treat bundled jars as dependency data (OSV queries), not as recursive extension scanning.
- Running IDE's own Plugin Verifier — requires IntelliJ SDK tooling, not a security check. Out of scope.
Security
- Log4Shell remains the canonical evidence that bundled-jar audit matters.
- No JetBrains ecosystem prefix in OSV.dev. Only Maven matching works.
- Plugin signing: 2021.2+ dual-signature (author + JetBrains re-sign via AWS KMS). Sideloads bypass entirely; enterprise custom repos can self-sign.
- CVE-2024-37051 (GitHub plugin token leak) is the closest analogue to "malicious content → credential exfil" and is the threat model for the LLM01/LLM02 content checks already in MEM.
Known Issues
- YouTrack IJPL-212393 — unsigned plugin warning sometimes not shown. Do not trust signing as binary gate.
- JetBrains dismisses sideload bypass as "user responsibility." Scanner fills the gap the vendor declined to fill.
postStartupActivityis platform-recommended for plugin project-load code but the platform team explicitly says plugins "must not affect IDE startup sequence." Tension is real; scanner ranks<application-components>+AppLifecycleListener.appStartedas HIGH andpostStartupActivityas MEDIUM.
Synthesis
The triangulation surfaces three cross-cutting insights that neither local nor external research alone would produce:
1. Reusability is higher than initial estimation suggested. Task-finder shows wiring is 80% done (routing, envelope, CLI, data-loader). Architecture-mapper shows sandbox primitives generalize via one parameter. Docs-researcher confirms zip structure is nested ZIP (outer + main jar) — and local lib/zip-extract.mjs already handles arbitrary ZIP streams. Result: v6.6.0 is primarily integration work, not greenfield. Net new code estimated at 300–500 lines (parser + discovery walker + 2–3 new check functions + knowledge file population), plus test fixtures.
2. The threat model differs from VS Code in ways that reshape which checks matter. VS Code's Marketplace has documented malware campaigns; JetBrains' has zero. This inverts the check priority: blocklist match is LOW-value (nothing to match), typosquat is HIGH-value (primary vector per community research), sideload is HIGHEST-value (only unmitigated attack per OX research), broad-activation splits into HIGH (<application-components> + AppLifecycleListener) vs MEDIUM (postStartupActivity), and two entirely new signals emerge: Premain-Class Java agents and native-binary bundling.
3. The "blocklist cannot contain confirmed-malicious entries" finding forces a schema rethink. The existing top-vscode-extensions.json schema has "blocklist": ["publisher.name@version"] for confirmed-bad. The JetBrains equivalent must structure this as a typosquat-comparison corpus ("jetbrains": [xmlId, ...]) with an explicitly-empty "blocklist": [] and a comment explaining why. Scanner warnings about "plugin on blocklist" will never fire for JetBrains in v6.6.0 — that's correct behavior. Enterprise users can seed their own private blocklists via policy.json when they discover internal threats.
Open Questions
- Marketplace API rate limits — not publicly documented. Implementation should implement conservative 1 req/s default with opt-in higher concurrency. Monitor for 429 responses.
- Custom repository enumeration — JetBrains supports
updatePlugins.xmlon arbitrary HTTPS servers for enterprise. v6.6.0 focuses on Marketplace; enterprise custom repos deferred to v6.7+. - Whether IDE re-verifies sideloaded plugin signatures at runtime — not publicly documented. Assume no; treat sideload as always-elevated-risk.
- Lifetime of a plugin across IDE upgrades — when user installs IntelliJ IDEA 2025.1 over 2024.3, do plugins copy over? Worth confirming during implementation to decide if discovery walks all version dirs or only the newest.
- Toolbox App plugin cache location —
~/Library/Caches/JetBrains/Toolbox/plugins/...is for Toolbox extensions, not IDE plugins. Confirm during implementation that this path should be skipped.
Recommendation
Proceed with v6.6.0 as a focused integration release. Implementation plan should structure as:
Phase A — Discovery + parsing (core)
- Implement
discoverJetBrainsExtensionsinlib/ide-extension-discovery.mjs— walkgetJetBrainsBaseDir()/<Product><Version>/plugins/(every product/version subdir), plus Android Studio undergetAndroidStudioBaseDir(). Exclude Fleet and Toolbox paths. - Implement
parseIntelliJPlugininlib/ide-extension-parser.mjs— for each plugin directory, locate main jar inlib/(convention: jar matching plugin dir name, or largest jar), ZIP-extractMETA-INF/plugin.xml+META-INF/MANIFEST.MF, returnParsedManifestextended with JetBrains-specific fields (pluginId,since,until,depends,extensionDeclarations,hasPremainClass,nativeBinaries,bundledJars[{name, version, shaded}]). - Populate
knowledge/top-jetbrains-plugins.jsonwith ~50 verified xmlIds (see community Q5 — API-verified list).blocklist: []with comment explaining absence. - Wire
type === 'jetbrains'branch intoscanOneExtension— dispatch toparseIntelliJPlugin, callrunJetBrainsChecksinstead ofrunIdeChecks.
Phase B — Checks
runJetBrainsCheckswith: blocklist match (reuses algorithm), typosquat (reuses algorithm, new corpus), theme-with-code (new: infer from<themeProvider>+ other extensions), broad-activation (new: rank by extension point),<depends>-chain expansion (new), Java-agent detection (new:Premain-Classin MANIFEST.MF), native-binary detection (new: scan extracted jar entries for.dll/.so/.dylib/.exe).- Minor scanner adaptations: NET trusted-domains (+ JetBrains CDN hosts), TNT
CODE_EXTENSIONS(+.kt,.groovy,.scala), MEMmemFilesfilter in orchestrator (+plugin.xml,README*).
Phase C — URL target support
- Extend
detectUrlTypeinlib/vsix-fetch.mjsto recognizeplugins.jetbrains.com/plugin/...URLs. AddfetchJetBrainsPlugin(publisher?, xmlIdOrNumericId, version?). - Generalize
buildSandboxedWorker/runVsixWorkerto acceptworkerPathparameter (maintains backwards compat with existingrunVsixWorkersignature via default). - Create
lib/jetbrains-fetch-worker.mjs— same IPC asvsix-fetch-worker.mjs, usesfetchJetBrainsPlugin+extractToDir, detectsextRootas top-level dir containinglib/.
Phase D — Tests + docs
- Fixtures:
tests/fixtures/ide-extensions/root-jetbrains/with benign + adversarial cases (theme-with-code, broad-activation, typosquat, Java agent, native binary, shaded jar). - Tests: mirror
tests/scanners/ide-extension-scanner.test.mjspattern —rootsOverrideinjection,intellijOnly: true. Plustests/scanners/jetbrains-fetch.test.mjswith mockedglobalThis.fetch. - Documentation: update
commands/ide-scan.md(remove "v1.1 stub" language),knowledge/ide-extension-threat-patterns.md(add JetBrains sections), createknowledge/jetbrains-marketplace-api-notes.md(sibling of existing VSIX notes), update rootREADME.md+ pluginCLAUDE.md+CHANGELOG.mdper project "docs at change" rule.
Risk register for implementation planning
| Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|
plugin.xml parsing scope creep (DTD validation, XSD) |
Medium | Medium | Stop at structural extraction of documented-schema fields. Do NOT validate against schema. |
| Nested ZIP extraction blows memory on large plugins | Low | Low | Existing 500MB uncompressed cap + 100x ratio cap apply to each nested extraction. Confirm during implementation. |
| Marketplace API rate-limiting | Medium | Low | Single-request-per-second default; opt-in --online-concurrency N. |
False positives on legacy <application-components> |
High | Low | MEDIUM severity, not HIGH. Document in finding rationale that deprecated does not imply malicious. |
| Android Studio path divergence missed | Low | Medium | Explicit getAndroidStudioBaseDir() with OS-specific Google/ prefix. Test fixture for Android Studio discovery. |
Lombook Plugin legitimate typo triggers false positive |
Certain | Low | Whitelist exact match for this single xmlId in typosquat check. |
| Shaded-jar false negatives (bundled vuln lib, coords stripped) | High | High | Out-of-scope for v6.6.0 — emit INFO/MEDIUM advisory "cannot audit (shaded)" for each coord-less jar. |
Estimated effort: 3–5 focused sessions. No new npm dependencies. No new external network calls beyond optional JetBrains Marketplace API queries (behind --online flag, same convention as VS Code).
Sources
| # | Source | Type | Quality | Used in |
|---|---|---|---|---|
| 1 | https://plugins.jetbrains.com/docs/intellij/plugin-content.html | official | high | Plugin format |
| 2 | https://plugins.jetbrains.com/docs/intellij/plugin-configuration-file.html | official | high | Plugin format, plugin.xml schema |
| 3 | https://plugins.jetbrains.com/docs/intellij/plugin-components.html | official | high | Broad activation ranking (legacy components) |
| 4 | https://plugins.jetbrains.com/docs/intellij/dynamic-plugins.html | official | high | require-restart, dynamic plugin detection |
| 5 | https://plugins.jetbrains.com/docs/intellij/theme-structure.html | official | high | Theme-with-code check |
| 6 | https://plugins.jetbrains.com/docs/intellij/intellij-platform-extension-point-list.html | official | high | Broad-activation extension point enumeration |
| 7 | https://plugins.jetbrains.com/docs/intellij/plugin-signing.html | official | high | Signing model, warning-not-block |
| 8 | https://plugins.jetbrains.com/docs/marketplace/api-reference.html | official | high | Marketplace API base + endpoints |
| 9 | https://plugins.jetbrains.com/docs/marketplace/plugin-update-download.html | official | high | Download endpoints |
| 10 | https://plugins.jetbrains.com/docs/marketplace/understanding-plugin-security.html | official | high | No-sandbox acknowledgement |
| 11 | https://plugins.jetbrains.com/docs/marketplace/verified-vendor-badge.html | official | high | vendor.isVerified semantics |
| 12 | https://plugins.jetbrains.com/docs/marketplace/jetbrains-marketplace-approval-guidelines.html | official | high | Moderation + removal policy |
| 13 | https://www.jetbrains.com/help/idea/directories-used-by-the-ide-to-store-settings-caches-plugins-and-logs.html | official | high | Install locations (IntelliJ IDEA) |
| 14 | https://developer.android.com/studio/intro/studio-config | official (Google) | high | Android Studio path divergence |
| 15 | https://fleet-support.jetbrains.com/hc/en-us/articles/7648059182226 | official | high | Fleet exclusion |
| 16 | https://blog.jetbrains.com/security/2024/06/updates-for-security-issue-affecting-intellij-based-ides-2023-1-and-github-plugin/ | official | high | CVE-2024-37051 |
| 17 | https://blog.jetbrains.com/platform/2021/12/log4j-vulnerability-and-third-party-plugins-on-jetbrains-marketplace/ | official | high | Log4Shell propagation |
| 18 | https://www.darkreading.com/application-security/ide-extensions-risks-software-supply-chain | community | high | OX verified-badge bypass |
| 19 | https://www.ox.security/blog/can-you-trust-that-verified-symbol-exploiting-ide-extensions-is-easier-than-it-should-be/ | community | high | OX research primary |
| 20 | https://youtrack.jetbrains.com/projects/IJPL/issues/IJPL-212393/Installing-unsigned-plugin-did-not-show-error-redux | official (bug tracker) | high | Signing warning unreliability |
| 21 | https://platform.jetbrains.com/t/execute-pre-load-activity/958 | official (forum, maintainer) | high | "plugins must not affect IDE startup sequence" |
| 22 | https://workflowotg.com/malware-in-ide-plugins-an-attack-vector-to-look-out-for-in-2025/ | community | medium | Threat-model framing |
| 23 | https://arxiv.org/html/2503.22391v1 | academic | high | Maven ecosystem vulnerability base rate |
| 24 | https://osv.dev/ | official (OSV) | high | Maven ecosystem matching, bundled-jar audit |
| 25 | Live API calls to plugins.jetbrains.com/api/plugins/{id} |
primary | high | Marketplace API schema confirmation |
| 26 | Task-finder report (in-conversation, see Phase 4 agent results) | codebase | high | Touchpoint inventory (6 must-change files) |
| 27 | Architecture-mapper report (in-conversation, see Phase 4 agent results) | codebase | high | Reusability matrix, dependency diagram |
| 28 | CLAUDE.md — project instructions at /Users/ktg/.claude/plugins/marketplaces/ktg-plugin-marketplace/plugins/llm-security/CLAUDE.md |
codebase | high | Zero-dep constraint, test-harness convention, docs-at-change rule |
| 29 | MEMORY.md — memory note on sandbox reuse |
memory | high | Reuse sandbox primitives, do not copy |