feat(llm-security): add pre-compact-poisoning example for PreCompact hook [skip-docs]

Runnable demonstration of hooks/scripts/pre-compact-scan.mjs (the
only PreCompact hook in the plugin) detecting both a CRITICAL
injection pattern and an AWS-shaped credential inside a synthetic
JSONL transcript, exercised across all three values of
LLM_SECURITY_PRECOMPACT_MODE plus a benign-transcript control case
in block mode that proves the gate is not a brick wall.

The transcript is generated at runtime in a per-invocation tempdir
under os.tmpdir() and the directory is removed in a finally block,
so the user's real ~/.claude/projects/.../transcripts/ are never
touched. The AWS-shaped key uses the same 'AK' + 'IA' + ...
fragmentation idiom as tests/e2e/attack-chain.test.mjs so this
source contains no literal credentials and pre-edit-secrets does
not block writes during development.

Nine independent assertions (9/9 must pass):
- block mode + poisoned: exit 2, decision=block JSON, reason text
  covers both injection and AWS labels (3 assertions)
- warn mode + poisoned: exit 0, systemMessage JSON, no decision
  field (2 assertions)
- off mode + poisoned: exit 0, no JSON on stdout (2 assertions)
- block mode + benign: exit 0, no decision=block JSON (2 assertions)

OWASP / framework mapping: LLM01, LLM02, ASI01, AT-1, AT-3.

Docs updated: plugin README "Other runnable examples", plugin
CLAUDE.md "Examples" tabellen, CHANGELOG [Unreleased] Added.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-05-05 15:22:28 +02:00
commit b6d912200e
6 changed files with 525 additions and 0 deletions

View file

@ -538,6 +538,16 @@ demonstrations — each with `README.md`, fixture, run script, and
doesn't trip `pre-write-pathguard` on `.claude-plugin/`. Maps to
ASI01 / ASI02 / ASI05 / LLM01 / LLM02 / LLM06. Run:
`node examples/toxic-agent-demo/run-toxic-flow.mjs`
- **`pre-compact-poisoning/`** — `pre-compact-scan` PreCompact hook
detecting both an injection pattern and a credential-shaped string
in a synthetic transcript across all three modes (off / warn /
block). The transcript is generated at runtime in a per-invocation
tempdir; the AWS-shaped key uses the same `'AK' + 'IA' + ...`
fragmentation idiom as `tests/e2e/attack-chain.test.mjs`, so the
source contains no literal credentials. Includes a benign-transcript
control case in block mode to prove the gate is not a brick wall.
Maps to LLM01 / LLM02 / ASI01 / AT-1 / AT-3. Run:
`node examples/pre-compact-poisoning/run-pre-compact-poisoning.mjs`
---