Pre-trekexecute snapshot of in-progress CLAUDE.md/SKILL.md edits and extracted docs/ files. Captured as one commit so /trekexecute claude-design can run against a clean working tree. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
122 lines
15 KiB
Markdown
122 lines
15 KiB
Markdown
# LLM Security — Scanner reference
|
||
|
||
Detailed scanner, CLI, CI/CD, knowledge-file and example documentation. Imported from `CLAUDE.md` via `@docs/scanner-reference.md`.
|
||
|
||
## Scanners
|
||
|
||
**Orchestrated (10):** Run via `node scanners/scan-orchestrator.mjs <target> [--fail-on <severity>] [--compact] [--output-file <path>] [--baseline] [--save-baseline]`.
|
||
`--fail-on <critical|high|medium|low>`: exit 1 if findings at/above severity, exit 0 otherwise. `--compact`: one-liner per finding format. Both configurable via `policy.json` `ci` section.
|
||
With `--output-file`: full JSON to file, compact aggregate to stdout. `--baseline` diffs against stored baseline. `--save-baseline` saves results for future diffs. Baselines stored in `reports/baselines/<target-hash>.json`.
|
||
|
||
10 scanners: unicode, entropy, permission, dep-audit, taint, git-forensics, network, memory-poisoning, supply-chain-recheck, toxic-flow.
|
||
|
||
Lib: `mcp-description-cache.mjs` — caches MCP tool descriptions in `~/.cache/llm-security/mcp-descriptions.json`, detects per-update drift via Levenshtein (>10% = alert), 7-day TTL. v7.3.0 (E14) adds a sticky baseline slot per tool plus a 10-event rolling history; cumulative drift = `levenshtein(current, baseline) / max(|current|,|baseline|)`. When ratio ≥ `mcp.cumulative_drift_threshold` (default 0.25), emits `mcp-cumulative-drift` advisory through `post-mcp-verify.mjs`. Baseline survives TTL purge so slow-burn drift is preserved across the 7-day window. `clearBaseline(tool?)` exposed for the `/security mcp-baseline-reset` command. `LLM_SECURITY_MCP_CACHE_FILE` env var overrides the cache path for testing.
|
||
|
||
Supply-chain-recheck (SCR) re-audits installed dependencies from lockfiles (package-lock.json, yarn.lock, requirements.txt, Pipfile.lock) against blocklists, OSV.dev batch API, and typosquat detection. Offline fallback available. Shared data module: `scanners/lib/supply-chain-data.mjs`.
|
||
|
||
Memory-poisoning (MEM) detects cognitive state poisoning in CLAUDE.md, memory files, and .claude/rules — injection patterns, shell commands, credential paths, permission expansion, suspicious URLs, encoded payloads.
|
||
|
||
Toxic-flow (TFA) is a post-processing correlator that runs LAST — detects "lethal trifecta" (untrusted input + sensitive data access + exfiltration sink) by correlating output from prior scanners.
|
||
|
||
Utility: `node scanners/lib/fs-utils.mjs <backup|restore|cleanup|tmppath> [args]`.
|
||
|
||
Lib: `sarif-formatter.mjs` — converts scan output to OASIS SARIF 2.1.0 format. Used by `--format sarif` flag.
|
||
Lib: `audit-trail.mjs` — writes structured JSONL audit events (ISO 8601, OWASP tags, SIEM-ready). Env: `LLM_SECURITY_AUDIT_*`.
|
||
Lib: `policy-loader.mjs` — reads `.llm-security/policy.json` for distributable hook configuration. Includes `ci` section (`failOn`, `compact`) for CI/CD defaults. Defaults match hardcoded values.
|
||
|
||
**Standalone (8):** `posture-scanner.mjs` — deterministic posture assessment, 16 categories (incl. EU AI Act, NIST AI RMF, ISO 42001), <50ms. NOT in scan-orchestrator (meta-level, not code-level).
|
||
Run: `node scanners/posture-scanner.mjs [path]` → JSON stdout. Scanner prefix: PST. Used by `/security posture` and `/security audit`.
|
||
|
||
`mcp-live-inspect.mjs` — NOT in scan-orchestrator. MCP servers are running processes, not files.
|
||
Run: `node scanners/mcp-live-inspect.mjs [target] [--timeout 10000] [--skip-global]`
|
||
Scanner prefix: MCI. OWASP: MCP03, MCP06, MCP09. Invoked by `mcp-inspect` and `mcp-audit --live`.
|
||
|
||
`watch-cron.mjs` — standalone cron wrapper. Reads `reports/watch/config.json`, scans all targets, writes `reports/watch/latest.json`. Run: `node scanners/watch-cron.mjs [--config <path>]`
|
||
|
||
`reference-config-generator.mjs` — generates Grade A reference config based on posture gaps. Detects project type (plugin/monorepo/standalone). Templates in `templates/reference-config/`. Run: `node scanners/reference-config-generator.mjs [path] [--apply]`
|
||
|
||
`dashboard-aggregator.mjs` — cross-project security dashboard. Discovers Claude Code projects under ~/ (depth 3) and ~/.claude/plugins/, runs posture-scanner on each, aggregates to machine-grade (weakest link). Cache in `~/.cache/llm-security/dashboard-latest.json` (24h staleness). Run: `node scanners/dashboard-aggregator.mjs [--no-cache] [--max-depth N]`
|
||
|
||
`attack-simulator.mjs` — red-team harness. Data-driven: 64 scenarios in 12 categories from `knowledge/attack-scenarios.json`. Payloads constructed at runtime (fragment assembly to avoid triggering hooks on source). Uses `runHook()` from test helper. Adaptive mode (`--adaptive`): 5 mutation rounds per passing scenario (homoglyph, encoding, zero-width, case alternation, synonym). Mutation rules in `knowledge/attack-mutations.json`. Benchmark mode (`--benchmark`): outputs structured pass/fail metrics. Run: `node scanners/attack-simulator.mjs [--category <name>] [--json] [--verbose] [--adaptive] [--benchmark]`
|
||
|
||
`ai-bom-generator.mjs` — AI Bill of Materials generator. Discovers AI components (models, MCP servers, plugins, knowledge, hooks) and outputs CycloneDX 1.6 JSON. Scanner prefix: BOM. Run: `node scanners/ai-bom-generator.mjs <target> [--output-file <path>]`
|
||
|
||
`ide-extension-scanner.mjs` — scans installed VS Code (and forks: Cursor, Windsurf, VSCodium, code-server, Insiders, Remote-SSH) extensions and JetBrains IDE plugins (IntelliJ IDEA, PyCharm, GoLand, WebStorm, RubyMine, PhpStorm, CLion, DataGrip, RustRover, Rider, Aqua, Writerside, Android Studio). Fleet + Toolbox excluded. OS-aware discovery via `lib/ide-extension-discovery.mjs` (`~/.vscode/extensions/` + `~/Library/Application Support/JetBrains/<IDE><version>/plugins/` on macOS, `%APPDATA%\JetBrains\...` on Windows, `~/.config/JetBrains/...` on Linux). Parses VS Code `package.json` via `lib/ide-extension-parser.mjs` and JetBrains `META-INF/plugin.xml` + `META-INF/MANIFEST.MF` (with nested-jar extraction) via `lib/ide-extension-parser-jb.mjs`. 7 VS Code checks: blocklist match, theme-with-code, sideload (vsix), broad activation (`*` / `onStartupFinished`), typosquat (Levenshtein ≤2 vs top-100), extension-pack expansion, dangerous `vscode:uninstall` hooks. 7 JetBrains checks: theme-with-code, broad activation (`application-components`), `Premain-Class` instrumentation (HIGH — javaagent retransform), native binaries (`.so`/`.dylib`/`.dll`/`.jnilib`), long `<depends>` chains, typosquat vs top JetBrains plugins, shaded-jar advisory. Both branches orchestrate reused scanners (UNI/ENT/NET/TNT/MEM/SCR) per extension with bounded concurrency (default 4). Scanner prefix: IDE. OWASP: LLM01, LLM02, LLM03, LLM06, ASI02, ASI04. Offline by default, `--online` opt-in for Marketplace/OSV.dev lookups. Knowledge: `knowledge/top-vscode-extensions.json`, `knowledge/top-jetbrains-plugins.json`, `knowledge/ide-extension-threat-patterns.md`, `knowledge/marketplace-api-notes.md`, `knowledge/jetbrains-marketplace-api-notes.md`.
|
||
|
||
**v6.4.0 — URL support.** Targets can be Marketplace, OpenVSX, or direct `.vsix` URLs. Pipeline: `lib/vsix-fetch.mjs` (HTTPS-only fetch with 50MB cap, 30s timeout, SHA-256, manual redirect host whitelist) → `lib/zip-extract.mjs` (zero-dep ZIP parser, rejects zip-slip/symlink/absolute/drive-letter/encrypted/ZIP64, caps: 10 000 entries, 500MB uncomp, 100x ratio, depth 20) → existing scan pipeline against extracted `extension/` subdir → temp dir always cleaned in `try/finally`. Envelope.meta.source = `{ type: "url", kind, url, finalUrl, sha256, size, publisher?, name?, version? }`.
|
||
|
||
**v6.5.0 — OS sandbox.** Fetch + extract for URL targets now spawns `lib/vsix-fetch-worker.mjs` in a sub-process wrapped by `sandbox-exec` (macOS) or `bwrap` (Linux) — same primitives reused from `git-clone.mjs`. Helper: `lib/vsix-sandbox.mjs` exports `buildSandboxProfile`, `buildBwrapArgs`, `buildSandboxedWorker`, `runVsixWorker`. Worker IPC: argv `--url <url> --tmpdir <dir>` → single JSON line on stdout (`{ok, sha256, size, finalUrl, source, extRoot}` or `{ok:false, error, code?}`). Defense-in-depth — if the in-process ZIP parser ever has a bypass, the kernel still refuses writes outside `<tmpdir>`. `scan(target, { useSandbox })` defaults to `true`; tests pass `false` since `globalThis.fetch` mocks do not cross process boundaries. Windows fallback: in-process with `meta.warnings` advisory. Envelope `meta.source.sandbox`: `'sandbox-exec' | 'bwrap' | 'none' | 'in-process'`.
|
||
|
||
**v6.6.0 — JetBrains Marketplace URL fetch + JetBrains branch.** URL targets can also be `https://plugins.jetbrains.com/plugin/<numericId>-<slug>` (metadata-resolved → xmlId download) or `https://plugins.jetbrains.com/plugin/download?pluginId=<xmlId>&version=<v>` (direct). `lib/vsix-fetch.mjs` gains `detectUrlType` JetBrains kinds, `fetchJetBrainsPlugin`, host allowlist `plugins.jetbrains.com`. `buildSandboxedWorker(dirs, workerPath)` now accepts a custom worker path — `lib/jetbrains-fetch-worker.mjs` reuses the same IPC contract. Envelope `meta.source.kind` can be `'jetbrains-marketplace' | 'jetbrains-download'`. Installed-plugin scan runs JB-specific checks (see scanner bullet above) and shares the UNI/ENT/NET/TNT/MEM/SCR orchestration. `.kt`, `.groovy`, `.scala` added to `taint-tracer` code extensions.
|
||
|
||
Run: `node scanners/ide-extension-scanner.mjs [target|url] [--vscode-only] [--intellij-only] [--include-builtin] [--online] [--format json|compact] [--fail-on <sev>] [--output-file <path>]`. Invoked by `/security ide-scan`.
|
||
|
||
## Token Budget (ENFORCED)
|
||
|
||
All commands total ~600 lines. All commands use registered subagent types.
|
||
|
||
- Commands are short dispatchers (~30-60 lines) — no inline report templates or format specs
|
||
- All agents use registered `subagent_type` — agent instructions are system prompt, never file reads
|
||
- Max 1-2 knowledge files per agent invocation (threat-patterns + secrets-patterns)
|
||
- OWASP files are NEVER passed by commands — agents reference them from their own system prompt
|
||
- Agents run sequentially to avoid burst rate limits
|
||
- `pre-install-supply-chain.mjs` queries OSV.dev for CVEs on every package install
|
||
|
||
## CLI
|
||
|
||
`bin/llm-security.mjs` — standalone CLI entry point. Works without Claude Code via `npx llm-security` or `node bin/llm-security.mjs`.
|
||
Subcommands: `scan`, `deep-scan`, `posture`, `audit-bom`, `benchmark`. Dispatches to scanner scripts via `child_process.spawn`.
|
||
`package.json` `bin` field: `"llm-security": "./bin/llm-security.mjs"`. `files` whitelist: only `bin/` + `scanners/` published to npm.
|
||
|
||
## CI/CD Integration
|
||
|
||
Pipeline templates in `ci/`: `github-action.yml`, `azure-pipelines.yml`, `gitlab-ci.yml`. Documentation: `docs/ci-cd-guide.md`.
|
||
All templates use `--fail-on high --format sarif --output-file results.sarif` with SARIF upload per platform.
|
||
Standalone CLI makes zero network calls in default mode. Schrems II compatible in default offline mode. Optional OSV.dev enrichment (`supply-chain-recheck --online`) transmits package identifiers to a Google-operated API and is a separate compliance consideration.
|
||
|
||
## Knowledge Files (20)
|
||
|
||
| File | Content |
|
||
|------|---------|
|
||
| `skill-threat-patterns.md` | 7 threat categories for skill/command scanning |
|
||
| `mcp-threat-patterns.md` | 9 MCP threat categories (MCP01-MCP10) |
|
||
| `secrets-patterns.md` | Regex patterns for 10+ secret types |
|
||
| `owasp-llm-top10.md` | OWASP LLM Top 10 (2025) with Claude Code mappings |
|
||
| `owasp-agentic-top10.md` | OWASP Agentic AI Top 10 (ASI01-ASI10) |
|
||
| `owasp-skills-top10.md` | OWASP Skills Top 10 (AST01-AST10) — skill-specific threats |
|
||
| `mitigation-matrix.md` | Threat-to-control mappings |
|
||
| `top-packages.json` | Known package lists for supply chain checks |
|
||
| `skill-registry.json` | Seed data for skill signature registry |
|
||
| `prompt-injection-research-2025-2026.md` | 7 research papers (2025-2026) with implications for hook defenses |
|
||
| `deepmind-agent-traps.md` | DeepMind AI Agent Traps — 6 categories, 43 techniques, coverage matrix |
|
||
| `attack-scenarios.json` | 64 red-team scenarios across 12 categories for attack simulation |
|
||
| `attack-mutations.json` | Synonym tables and mutation rules for adaptive red-team testing |
|
||
| `compliance-mapping.md` | EU AI Act, NIST AI RMF, ISO 42001, MITRE ATLAS mappings to plugin capabilities |
|
||
| `norwegian-context.md` | Norwegian regulatory landscape — Datatilsynet, NSM, Digitaliseringsdirektoratet |
|
||
| `ide-extension-threat-patterns.md` | 10 IDE-extension detection categories (VS Code + JetBrains) with 2024-2026 case studies |
|
||
| `top-vscode-extensions.json` | Top ~100 VS Code Marketplace extension IDs (typosquat seed) + blocklist entries |
|
||
| `top-jetbrains-plugins.json` | Top JetBrains plugin IDs (typosquat seed) + blocklist entries (v6.6.0) |
|
||
| `marketplace-api-notes.md` | VS Code Marketplace + OpenVSX API endpoints used by `lib/vsix-fetch.mjs` (v6.4.0) |
|
||
| `jetbrains-marketplace-api-notes.md` | JetBrains Marketplace API endpoints used by `fetchJetBrainsPlugin` (v6.6.0) |
|
||
|
||
## Reports
|
||
|
||
Scan reports are stored in `reports/` as `.docx` (for sharing) with `.md` source.
|
||
|
||
## Examples (runnable demonstrations)
|
||
|
||
Self-contained, deterministic threat-fixture mappes under `examples/`. Each mappe har `README.md`, fixture/script/transcript, `run-*.{sh,mjs}`, og `expected-findings.md`. Demonstrasjoner — ikke unit-tester.
|
||
|
||
| Mappe | Demonstrerer | Hooks/scanners | Sentinel |
|
||
|-------|--------------|----------------|----------|
|
||
| `malicious-skill-demo/` | Skill scanner end-to-end (UNI/ENT/PRM/DEP/TNT/NET + 7 LLM-kategorier) | `scan-orchestrator` + agents | BLOCK 100/100 |
|
||
| `prompt-injection-showcase/` | 61 payloads × 19 kategorier mot `pre-prompt-inject-scan`, `post-mcp-verify`, `pre-bash-destructive` | runtime hooks | per-kategori expected outcome |
|
||
| `lethal-trifecta-walkthrough/` | Rule-of-Two advisory på leg 3 (WebFetch → Read .env → Bash curl POST) + suppression | `post-session-guard` | advisory på stage 3 |
|
||
| `mcp-rug-pull/` | Cumulative drift-advisory (E14, v7.3.0) — 7 stadier under per-update-terskel, kumulativt over 25% baseline | `post-mcp-verify` + `mcp-description-cache.mjs` | advisory på stage 7 |
|
||
| `supply-chain-attack/` | PreToolUse-blokk på kompromittert pakke + scope-hop advisory + dep-auditor typosquats + postinstall curl-pipe | `pre-install-supply-chain` + `dep-auditor` + `supply-chain-data` | 6+ funn, 2 advisories, 1 BLOCK |
|
||
| `poisoned-claude-md/` | 6 detektorer (injection / shell / URL / credential paths / permission expansion / encoded payloads) inkl. E15 agent-fil-overflate | `memory-poisoning-scanner` | ≥18 funn fordelt på 2 filer |
|
||
| `bash-evasion-gallery/` | T1-T9 disguised destructive commands → normalisert + blokkert (defense-in-depth over Claude Code 2.1.98+) | `pre-bash-destructive` + `bash-normalize` | 10 BLOCK eksitkoder |
|
||
| `toxic-agent-demo/` | Single-component lethal trifecta — agent med [Bash, Read, WebFetch] uten hook-guards = CRITICAL TFA-finding | `toxic-flow-analyzer` (TFA) | 1 CRITICAL `Lethal trifecta:` |
|
||
| `pre-compact-poisoning/` | PreCompact-hook fanger injection + AWS-shaped credential i syntetisk transcript på tvers av off/warn/block-modus | `pre-compact-scan` | 9 pass: block exit 2 + reason; warn systemMessage; off skip; benign passes |
|
||
|
||
State-isolering: alle eksempler som muterer global state bruker run-script PID (post-session-guard via `${ppid}.jsonl`) eller env-overrides (`LLM_SECURITY_MCP_CACHE_FILE` for MCP-cache). Brukerens reelle `/tmp/llm-security-session-*.jsonl` og `~/.cache/llm-security/` røres aldri.
|