Three new self-contained, runnable threat demonstrations under
examples/, continuing the batch started in 583a78c. Each example
has README.md + run-*.mjs + expected-findings.md and uses
state-isolation discipline so the user's real cache/state files
are never polluted.
- examples/supply-chain-attack/ — two-layer demonstration:
pre-install-supply-chain (PreToolUse) blocks compromised
event-stream version 3.3.6 and emits a scope-hop advisory for
the @evilcorp scope; dep-auditor (DEP scanner, offline) flags
5 typosquat dependencies plus a curl-piped install-script
vector in the fixture package.json. Maps to LLM03/LLM05/ASI04.
- examples/poisoned-claude-md/ — all 6 memory-poisoning detectors
fire on a deliberately poisoned CLAUDE.md plus a fixture
agent file under .claude/agents (E15/v7.2.0 surface):
detectInjection, detectShellCommands, detectSuspiciousUrls,
detectCredentialPaths, detectPermissionExpansion,
detectEncodedPayloads. No agent runtime needed — scanner
imported directly. Maps to LLM01/LLM06/ASI04.
- examples/bash-evasion-gallery/ — one disguised variant per
T1 through T9 evasion technique fed through pre-bash-destructive,
verified BLOCK after bash-normalize strips the evasion. T8
base64-pipe-shell uses its own BLOCK_RULE. The canonical
destructive form uses a path token rather than the bare slash
(regex word-boundary requires it). Source-string fragmentation
pattern reused from the e2e attack-chain test. Maps to
LLM06/ASI01/LLM01.
Plugin README "Other runnable examples" section + plugin
CLAUDE.md "Examples" table + CHANGELOG Unreleased/Added
all updated. Marketplace root README unchanged
([skip-docs] for marketplace-level gate — plugin's outward
coverage is unchanged, only demonstrations were added).
2.3 KiB
2.3 KiB
Expected Findings — Memory-Poisoning Walkthrough
This is the testable contract. run-memory-poisoning.mjs exits 0
only when each detector category has at least one finding.
Per-detector contract
| Detector | Min findings | Severity floor | OWASP |
|---|---|---|---|
| detectInjection | 1 | MEDIUM | LLM01 |
| detectShellCommands | 1 | LOW | LLM06 |
| detectSuspiciousUrls | 1 | HIGH | LLM02 |
| detectCredentialPaths | 1 | HIGH | LLM02 |
| detectPermissionExpansion | 1 | CRITICAL | LLM06 / ASI06 |
| detectEncodedPayloads | 1 | MEDIUM | LLM01 |
Total: at least 6 unique findings, severity-weighted such that the highest tier in any single file is CRITICAL.
File-level expectations
| File | Min findings |
|---|---|
CLAUDE.md |
12 |
.claude/agents/health-checker.md |
3 |
The agent file count is lower because the fixture is intentionally shorter — its purpose is to prove E15 (v7.2.0) coverage of the agent-file surface, not to exhaustively replicate every CLAUDE.md signal.
Bucket-mapping logic (in run-memory-poisoning.mjs)
Findings are bucketed in priority order:
- permission expansion (most specific) — matches "permission expansion"
or
allowed-tools/bypassPermissions/dangerously/skip-permissions - credential paths — matches "credential path" or
.ssh/.aws/kubeconfig/wallet/service-account-key - suspicious URLs — matches "suspicious exfiltration url/domain" or
webhook.site/requestbin - encoded payloads — matches "base64" or "encoded payload"
- shell commands — matches "shell command" or
curl/wget/eval - injection (broadest, last) — matches "injection" / "ignore previous" / "spoofed"
The order matters because some findings carry "directive" or "override" wording that would otherwise fall into the injection bucket — by checking permission-expansion first we avoid double-counting.
Side effects
- No file is modified
- No network call (scanner is fully offline)
- Discovery uses
scanners/lib/file-discovery.mjs::discoverFiles() - Memory-poisoning-scanner only inspects files matching
MEMORY_FILE_PATTERNS— the fixture deliberately usesCLAUDE.mdand.claude/agents/health-checker.mdto ensure the scanner picks them up