chore(llm-security): STATE — v7.8.2 shipped; next = the 52 MEDIUM

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TcQyMTQfyrsAapaCMPxTtQ
This commit is contained in:
Kjell Tore Guttormsen 2026-07-18 09:35:21 +02:00
commit 629a5e6e8c

View file

@ -1,50 +1,56 @@
# STATE — llm-security # STATE — llm-security
**👉 NESTE — START HER (fresh session, Opus 4.8 xhigh) — v7.8.2: the ~6 HIGH:** **👉 NESTE — START HER (fresh session, Opus 4.8 xhigh) — the MEDIUM sweep:**
**v7.8.1 SHIPPED** — the CRITICAL auto-cleaner RCE is fixed, released, tagged, catalog-synced and **v7.8.2 SHIPPED** — all 5 HIGH from the completion review are fixed, released, tagged,
pushed. Next up is the HIGH tier from the same review. Iron Law per defect (regression test FIRST), catalog-synced and pushed. Next is the MEDIUM tier (52 findings) from the same review.
one commit per defect, then ship v7.8.2. All six are in the 59-finding review output (harvest source Expect it to be its own release (v7.8.3 or v7.9.0), not a continuation of v7.8.2.
below). Order them yourself; suggested by blast radius: Same discipline that worked this session: **verify each finding against the code FIRST**
1. `rm -rf /` + `rm -rf ~` bypass the root-block — `hooks/pre-bash-destructive.mjs:24`. (STATE's own descriptions proved wrong 3x — see below), Iron Law per defect, one commit each.
2. Entropy scanner suppresses ALL findings when the ABSOLUTE path contains test/spec/fix — Triage first: 52 MEDIUMs will contain duplicates and non-defects — do a verification pass and
`scanners/entropy-scanner.mjs:308` (a repo cloned to `/tmp/fix-me/` silently reports nothing). report the real count before planning the release.
3. Unparseable JetBrains plugin crashes the whole ide-scan + null-manifest deref —
`scanners/ide-extension-scanner.mjs:684` (likely 1 root cause / 2 findings).
4. Obfuscated injections are reported but NOT stripped from the LLM evidence package —
`scanners/content-extractor.mjs:119` (defeats the remote-scan injection defense).
5. Out-of-range numeric char-ref raises RangeError, breaking the no-throw contract —
`scanners/ide-extension-parser.mjs:147`.
Then the MEDIUM sweep (52 more) — likely its own release, not v7.8.2.
**Review output (harvest source):** confirmed array + per-finding adversarial reasoning in task **Review output (harvest source):** confirmed array + per-finding adversarial reasoning in task
`w8s4rsaw8` output: `…/dfcab047-5467-4484-ab1a-5d6526439f78/tasks/w8s4rsaw8.output` (result.confirmed, `w8s4rsaw8` output: `…/dfcab047-5467-4484-ab1a-5d6526439f78/tasks/w8s4rsaw8.output` (result.confirmed,
59 items). Durable journal (one result-line/agent): `~/.claude/projects/-Users-…-llm-security/ 59 items). Durable journal: `~/.claude/projects/-Users-…-llm-security/
f99dcf73-d344-4377-b8ba-09fe878f32a2/subagents/workflows/wf_99daed37-f8b/journal.jsonl`. f99dcf73-d344-4377-b8ba-09fe878f32a2/subagents/workflows/wf_99daed37-f8b/journal.jsonl`.
## Lesson from v7.8.2 — the review's own text is a premiss, not a fact
Three of five findings were described inaccurately in STATE/the review. Verify before acting:
- Paths were wrong: hooks live in `hooks/scripts/`, the parser in `scanners/lib/`.
- Blast radius was understated (the rm-block also missed `/*`, `-fr`, and sudo-prefixed forms).
- Severity was overstated once: the char-ref defect does NOT break the no-throw contract
(`safe()` catches it) and needs non-well-formed XML, so it is below HIGH. Said so in the commit.
- The old `pre-bash-destructive.test.mjs` had **encoded the bug as expected behaviour** with a
wrong root-cause NOTE. Green suites can be green because the test was shaped around the defect —
when a test comment explains why something *isn't* caught, treat it as a lead, not a spec.
## ⚠️ NEVER `git add -A` in this repo
Did it this session and swept the 3 parked docs into a release commit aimed at a PUBLIC mirror.
Caught before push and amended out, but the guard is: **stage explicit paths, always.**
## PARKED — v8 family strategy (behind an operator visibility decision, DO NOT PUSH) ## PARKED — v8 family strategy (behind an operator visibility decision, DO NOT PUSH)
4 of 6 deliverables written, LOCAL ONLY: `docs/JOBS-TO-BE-DONE.md`, `docs/FAMILY-MAP.md`, 4 of 6 deliverables written, LOCAL ONLY: `docs/JOBS-TO-BE-DONE.md`, `docs/FAMILY-MAP.md`,
`docs/commons-extraction-plan.md`, `docs/roadmap.md` [gitignored]. Remaining v8 docs (do NOT start until `docs/commons-extraction-plan.md`, `docs/roadmap.md` [gitignored]. Remaining v8 docs (do NOT start
visibility is decided): formal `docs/completion-review-2026-07-17.md` (findings table + until visibility is decided): formal `docs/completion-review-2026-07-17.md` and `V8-ANNOUNCEMENT.md`.
`severity.mjs` framework-coverage map + citations; roadmap B8/P3 reference it) and `V8-ANNOUNCEMENT.md`. **DO NOT PUSH the 3 untracked docs:** origin `open/llm-security.git` is a PUBLIC mirror; they describe
**⚠️ DO NOT PUSH the 3 untracked docs:** origin `open/llm-security.git` is a PUBLIC mirror; docs describe cross-repo strategy + a sibling (`claude-code-llm-wiki`, "Private pending Anthropic ToS").
cross-repo strategy + a sibling (`claude-code-llm-wiki`, "Private pending Anthropic ToS"). Do NOT `git add` NOTE: `docs/FAMILY-MAP.md:42` says v7.8.0/1863 tests — stale, fix when the parking ends.
them without a visibility call (accept-public / keep-local `.local.md` / private family home).
NOTE: `docs/FAMILY-MAP.md:42` still says v7.8.0/1863 tests — stale, fix when the parking ends.
## Ground truth (verified 2026-07-18) ## Ground truth (verified 2026-07-18)
- **`npm test` = 1865/0 green** at tip. Run tests with `npm test``node --test tests/` is NOT a valid - **`npm test` = 1901/0 green** at tip (1865 + 36 new). Run with `npm test``node --test tests/`
invocation (it fails as a harness error, not a regression); the script is `node --test 'tests/**/*.test.mjs'`. is NOT valid; the script is `node --test 'tests/**/*.test.mjs'`.
- v7.8.1 released: tag `v7.8.1` pushed, catalog ref bumped, `check-versions.mjs` = **0 ERROR** - v7.8.2 released: tag `v7.8.2` pushed, catalog ref bumped, `check-versions.mjs` = **0 ERROR**
(the one WARN is `okr`, pre-existing and unrelated). (the one WARN is `okr`, pre-existing and unrelated).
- CRITICAL RCE: **reproduced live before the fix** (canary via `$CLEANER_RCE_CANARY` env expansion, - Test-pollution trap (hit and fixed): `jetbrains-parser.test.mjs` asserts globally that no
proving a shell parsed the filename), gone after. Both sinks in `scanners/auto-cleaner.mjs` are now `llmsec-jb-*` dir survives in tmpdir. Any new test using that mkdtemp prefix fails it
`spawnSync` argv-arrays; `execSync` is no longer imported there. order-dependently — passed one full run, failed the next. Pick a non-colliding prefix.
- Regression coverage is deliberately TWO tests (`tests/scanners/auto-cleaner-rce.test.mjs`): the belt - Exported for testability, do not "tidy" away: `validateContent` (auto-cleaner, v7.8.1),
in `applyFixes` (metachar refusal) stops hostile input BEFORE the sink, so a single applyFixes-level `stripInjection` (content-extractor, v7.8.2), `scanOneExtension` (ide-extension-scanner).
test would pass without proving the shell was gone. `validateContent` is exported for that reason — `content-extractor.mjs` now runs `main()` behind an `isMain` guard — CLI re-verified working.
do not "tidy" that export away. - Known residual gap (documented, not a bug to re-file): `stripInjection` cannot attribute a
payload encoded ACROSS lines; those findings carry `unstripped: true` by design. Whole-file
redaction was considered and rejected (normalizeForScan base64-decodes any long blob).
- Prior security: F-1/2/3/5/6 fixed; F-4 open (optional/LOW); B1/B2/E14 fixed. - Prior security: F-1/2/3/5/6 fixed; F-4 open (optional/LOW); B1/B2/E14 fixed.
- Stray `undefined/` (scan artifact, 2026-07-17): **removed**.
## Position taken (strategic anchor) ## Position taken (strategic anchor)
llm-security **consolidates**; growth at **family level** (security-commons + `llm-retrieval-guard` llm-security **consolidates**; growth at **family level** (security-commons + `llm-retrieval-guard`
@ -56,6 +62,8 @@ extraction + verified fixes + docs consistency.
## Continuity ## Continuity
origin = Forgejo `open/llm-security` (PUBLIC, never GitHub). Push window: weekdays 20:0023:00; origin = Forgejo `open/llm-security` (PUBLIC, never GitHub). Push window: weekdays 20:0023:00;
weekends/holidays anytime. STATE.md is intentionally TRACKED + committed (`.gitignore:19-20` NOTE). weekends/holidays anytime. STATE.md is intentionally TRACKED + committed (`.gitignore:19-20` NOTE).
**Disclosure convention (set this session):** a security fix to public code is committed but HELD until **Disclosure convention:** a security fix to public code is committed but HELD until its release tag
its release tag exists, so the exploit description in the commit/notes never lands before the fixed exists, so the exploit description never lands before the fixed version. Fix, bump, tag, catalog, push.
version users can upgrade to. Fix, bump, tag, catalog, push — one sequence. **Release mechanics:** `catalog/scripts/release-plugin.mjs <plugin> --version X.Y.Z` (dry-run by
default; `--create-tag`, then `--write --commit --push`). It refuses unless plugin.json == README
badge == target. Push the plugin repo's commits BEFORE `--create-tag`.