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>
This commit is contained in:
parent
7bcf5fae9d
commit
6252e55700
33 changed files with 1849 additions and 20 deletions
69
plugins/llm-security/scanners/lib/ide-extension-data.mjs
Normal file
69
plugins/llm-security/scanners/lib/ide-extension-data.mjs
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
// ide-extension-data.mjs — Loads top-extensions + blocklist from knowledge files.
|
||||
// Zero dependencies (Node.js builtins only).
|
||||
// Used by ide-extension-scanner.mjs for typosquat + blocklist checks.
|
||||
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import { join, dirname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const KNOWLEDGE_DIR = join(__dirname, '..', '..', 'knowledge');
|
||||
|
||||
let _vscode = null;
|
||||
let _jetbrains = null;
|
||||
|
||||
async function loadJson(path) {
|
||||
try {
|
||||
const raw = await readFile(path, 'utf8');
|
||||
return JSON.parse(raw);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load top VS Code extension IDs.
|
||||
* @returns {Promise<string[]>} Lowercased "publisher.name" strings.
|
||||
*/
|
||||
export async function loadTopVSCode() {
|
||||
if (_vscode !== null) return _vscode.vscode || [];
|
||||
_vscode = await loadJson(join(KNOWLEDGE_DIR, 'top-vscode-extensions.json')) || { vscode: [], blocklist: [] };
|
||||
return (_vscode.vscode || []).map(normalizeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load VS Code extension blocklist entries.
|
||||
* @returns {Promise<string[]>} Entries of form "publisher.name@version" or "publisher.name@*".
|
||||
*/
|
||||
export async function loadVSCodeBlocklist() {
|
||||
if (_vscode !== null) return _vscode.blocklist || [];
|
||||
_vscode = await loadJson(join(KNOWLEDGE_DIR, 'top-vscode-extensions.json')) || { vscode: [], blocklist: [] };
|
||||
return _vscode.blocklist || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Load top JetBrains plugin IDs (stub for v1.1).
|
||||
* @returns {Promise<string[]>}
|
||||
*/
|
||||
export async function loadTopJetBrains() {
|
||||
if (_jetbrains !== null) return _jetbrains.jetbrains || [];
|
||||
_jetbrains = await loadJson(join(KNOWLEDGE_DIR, 'top-jetbrains-plugins.json')) || { jetbrains: [], blocklist: [] };
|
||||
return (_jetbrains.jetbrains || []).map(normalizeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize extension ID for comparison.
|
||||
* @param {string} id
|
||||
* @returns {string}
|
||||
*/
|
||||
export function normalizeId(id) {
|
||||
return String(id || '').toLowerCase().trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset cache (for tests).
|
||||
*/
|
||||
export function _resetCache() {
|
||||
_vscode = null;
|
||||
_jetbrains = null;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue