chore(llm-security): v7.8.2 — security patch release

Bumps package.json, .claude-plugin/plugin.json and the README badge to
7.8.2; adds the release entry to CHANGELOG.md, docs/version-history.md,
the README recent-versions table and the CLAUDE.md highlights block.

Also fixes test pollution introduced with the ide-extension regression
suite: its temp roots used an `llmsec-jb-plugin-` prefix, and
jetbrains-parser.test.mjs asserts globally that no `llmsec-jb-*`
directory survives anywhere in tmpdir. The shared prefix made that
assertion fail depending on test order — it passed on the first full run
and failed on the next. Prefix is now `llmsec-nullmanifest-`.

npm test: 1901/1901 green, three consecutive runs.

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:33:40 +02:00
commit f4c65070ff
7 changed files with 146 additions and 6 deletions

View file

@ -6,6 +6,73 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
## [Unreleased]
## [7.8.2] - 2026-07-18
Security patch. Fixes five defects from the v7.8.1 completion review, four of
which caused a scanner or hook to fail silently — reporting success while the
check it was named for did not run. No feature changes. 1901 tests, 0 fail.
### Fixed
- **HIGH — bare root/home targets bypassed the rm block**
(`hooks/scripts/pre-bash-destructive.mjs`). The BLOCK rule's target
alternation ended in a shared `\b`, and a word boundary cannot hold after `/`
or `~` at end-of-command. `rm -rf /`, `rm -rf ~`, `rm -rf /*`, `rm -fr /` and
the sudo-prefixed forms all fell through to WARN (exit 0) — advisory only,
command executed. Only targets starting with a word character (`/etc`,
`/usr`) were ever blocked. `\b` now applies to the `$HOME` alternative alone,
where it is meaningful.
- **HIGH — entropy suppression keyed off the absolute path**
(`scanners/entropy-scanner.mjs`). The test/fixture suppression rule matched
`/(test|spec|fixture|mock|__test__|__spec__)/i` against the **absolute**
path, so any directory name above the scan root silenced every entropy
finding in the entire target while still reporting status `ok`. The rule now
keys off the path relative to the scan root.
- **HIGH — one unparseable JetBrains plugin crashed the whole ide-scan**
(`scanners/ide-extension-scanner.mjs`). The two manifest parsers disagree on
how they signal failure: `parseVSCodeExtension` returns bare `null`,
`parseIntelliJPlugin` returns a truthy `{ manifest: null, warnings }`. Only
the bare-null form was guarded, so every JetBrains failure path dereferenced
`manifest.hasSignature`; the TypeError escaped through `mapConcurrent`'s
unguarded `Promise.all` and aborted the scan of every other installed
extension. Guard widened, plus per-extension fault isolation at the call
site.
- **HIGH — obfuscated injections were reported but not stripped**
(`scanners/content-extractor.mjs`). `stripInjection` scanned both the raw and
the decoded text but removed matches only via a literal replace against the
raw text. For a decoded-only match, `match[0]` is the decoded string, which
by construction does not occur in the raw text — so the replace was a silent
no-op and the encoded payload reached the LLM agent verbatim via
`sanitized_content`, alongside a finding announcing it. Every obfuscation the
normalizer exists to defeat was affected. Decoded-only matches are now
removed by redacting the source line; multi-line payloads that cannot be
attributed are flagged `unstripped: true` rather than left silently.
- **Out-of-range numeric character reference emptied a plugin.xml field**
(`scanners/lib/ide-extension-parser.mjs`). `decodeEntities` guarded
`parseInt` with `Number.isFinite`, which bounds nothing, so any code point
above `0x10FFFF` made `String.fromCodePoint` raise `RangeError`. The
no-throw contract held (the per-field `safe()` wrapper catches it), but the
affected field was discarded and replaced with `''`. Undecodable references
are now left literal. Filed as HIGH; it is lower — such a document is not
well-formed XML, so the plugin would not load in IntelliJ either.
### Changed
- `stripInjection` (content-extractor) and `scanOneExtension` (ide-extension-
scanner) are exported for testing; `content-extractor.mjs` runs `main()`
behind the standard `isMain` guard so importing it no longer executes the
CLI. The remote-scan injection boundary had no direct test coverage before
this release.
### Removed
- `tests/hooks/probe-rm.mjs` — a self-labelled temporary debug probe with no
assertions, pointing at a hardcoded path into the installed marketplace copy.
## [7.8.1] - 2026-07-18
Security patch. Fixes a CRITICAL command-injection defect in the auto-cleaner