chore(release): bump to v7.3.0
Batch C release. Closes 12 implementation tasks (E3, E8-E14, 8.4, 8.6, 8.7, 8.10) across four execution waves: A (bash + decoder), B (supply chain + workflow scanner), C (MCP cumulative drift), D (code quality). Wave E (9 new attack-simulator scenarios for the new defenses) deferred to v7.3.1 — defenses are unit-tested per wave; the deferred work adds attack-simulator regression coverage on top, not the primary safety net. Tests: 1665+ → 1777 (Wave A-D cumulative, +112). Version sync targets touched: - package.json - .claude-plugin/plugin.json - CLAUDE.md (header) - README.md (badge + new release-history row) - scanners/ide-extension-scanner.mjs (VERSION constant) - ../../README.md (marketplace root plugin entry) - CHANGELOG.md (new [7.3.0] section per Keep a Changelog, all 12 task IDs covered individually under Added/Changed/Documentation/Tests/Notes) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
1016914fc1
commit
c4183b8b4d
7 changed files with 186 additions and 7 deletions
|
|
@ -4,6 +4,184 @@ All notable changes to the LLM Security Plugin are documented in this file.
|
|||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
||||
|
||||
## [7.3.0] - 2026-05-01
|
||||
|
||||
Batch C release. Closes 12 implementation tasks (E3, E8-E14, 8.4, 8.6,
|
||||
8.7, 8.10) across four execution waves: Wave A (bash evasion + decoder),
|
||||
Wave B (supply chain + workflow scanner), Wave C (MCP cumulative drift),
|
||||
Wave D (code quality). Wave E (9 new attack-simulator scenarios for the
|
||||
new defenses) deferred to v7.3.1 — the defenses themselves are unit-tested
|
||||
per wave; the deferred work adds attack-simulator regression coverage on
|
||||
top.
|
||||
|
||||
### Added
|
||||
|
||||
- **E8 — T7 process-substitution normalization** in
|
||||
`scanners/lib/bash-normalize.mjs`. Collapses `<(cmd)` and `>(cmd)`
|
||||
process-substitution wrappers so the inner command name is surfaced
|
||||
to downstream destructive-command name matchers in
|
||||
`pre-bash-destructive.mjs`. Defends against split-command evasion.
|
||||
Nested wrappers handled up to depth 3. Single-quoted literals
|
||||
masked before T7 runs to avoid corrupting string content.
|
||||
|
||||
- **E10 — T9 eval-via-variable normalization** in
|
||||
`scanners/lib/bash-normalize.mjs`. Substitutes one-level variable
|
||||
assignments before destructive-name matching. One-level forward-flow
|
||||
only: chained-var attacks intentionally not followed (documented
|
||||
limit). Bare-form, curly-form, and double-quoted forms supported;
|
||||
single-quoted literals preserved.
|
||||
|
||||
- **E9 — T8 base64-pipe-shell BLOCK rule** in
|
||||
`hooks/scripts/pre-bash-destructive.mjs`. Direct match on the
|
||||
base64-decode-pipe-into-shell loader idiom — blocks the
|
||||
encoded-payload runner pattern that bypasses static name-matching by
|
||||
delivering the destructive command as encoded text.
|
||||
|
||||
- **E3 — rot13 layer for hidden-imperative comment-block detection**
|
||||
in `scanners/lib/injection-patterns.mjs`. The decoder is bounded
|
||||
in length to keep accidental rot13-look-alike short strings out of
|
||||
scope. Base64/hex/URL/HTML decoding is already done by
|
||||
`normalizeForScan`; the rot13 pass is the only genuinely new layer.
|
||||
|
||||
- **E12 — `.gitattributes` filter/diff/merge driver advisory** in
|
||||
`scanners/lib/git-clone.mjs`. New `scanGitAttributes(repoDir)`
|
||||
exported helper plus post-clone integration in the `clone` CLI
|
||||
branch — surfaces filter, diff, and merge driver directives as
|
||||
MEDIUM advisories so downstream consumers see the supply-chain
|
||||
surface that survives even a sandboxed clone.
|
||||
|
||||
- **E13 — npm scope-hopping typosquat detection** in
|
||||
`hooks/scripts/pre-install-supply-chain.mjs`. New shared
|
||||
`NPM_OFFICIAL_SCOPES` export from `scanners/lib/supply-chain-data.mjs`.
|
||||
When an install targets `@<scope>/<name>` where `<scope>` is unknown
|
||||
but `<name>` matches a popular unscoped package, the hook emits a
|
||||
MEDIUM advisory. Allowlist of legitimate scopes drives suppression.
|
||||
Configurable via `policy.json` `supply_chain.allowed_scopes`.
|
||||
|
||||
- **E11 — workflow-injection scanner** (`scanners/workflow-scanner.mjs`).
|
||||
Scans `.github/workflows/*.{yml,yaml}` and `.forgejo/workflows/*.{yml,yaml}`
|
||||
for dangerous expression interpolations inside `run:` step blocks.
|
||||
23-field canonical blacklist (GHSL Security Lab 17 + GlueStack-class
|
||||
6) targeting attacker-controlled fields. Sink-restricted: only
|
||||
`run:` steps are shell sinks; `if:`, `with:`, `env:`, `name:`,
|
||||
`runs-on:` are evaluated by the runner's expression engine, not the
|
||||
shell, and are suppressed. Severity matrix: privileged triggers →
|
||||
HIGH; semi-privileged → MEDIUM; safe fields (numeric / hex /
|
||||
fixed-string) → INFO. State machine extracted to
|
||||
`scanners/lib/workflow-yaml-state.mjs` for unit-level testability.
|
||||
Re-interpolation tracking — env-block bindings sourced from
|
||||
blacklisted fields, then read back inside `run:`, are flagged at
|
||||
MEDIUM as the Appsmith GHSL-2024-277 stealth pattern. Auth-bypass
|
||||
detection — `(github|forgejo).actor` compared against bot
|
||||
identities in `if:` conditions flagged at MEDIUM (Synacktiv 2023
|
||||
Dependabot spoofing class). New `WFL` prefix in
|
||||
`scanners/lib/severity.mjs` OWASP map. Registered in
|
||||
`scanners/scan-orchestrator.mjs`.
|
||||
|
||||
- **E14 — MCP cumulative-drift baseline** in
|
||||
`scanners/lib/mcp-description-cache.mjs`. Sticky `baseline` slot per
|
||||
tool plus a 10-event rolling `history` array (FIFO). Cumulative
|
||||
drift = `levenshtein(current, baseline.description) / max(|current|,
|
||||
|baseline|)`; when ratio ≥ `mcp.cumulative_drift_threshold`
|
||||
(default 0.25), `post-mcp-verify.mjs` emits a MEDIUM
|
||||
`mcp-cumulative-drift` advisory independent of the existing
|
||||
per-update >10% drift signal — both fire independently. Slow-burn
|
||||
rug-pulls that keep each update under the per-update threshold but
|
||||
cumulatively diverge from baseline are now caught. Baseline survives
|
||||
the 7-day TTL purge so detection persists across the full window.
|
||||
New `/security mcp-baseline-reset` slash command (plus
|
||||
`scanners/mcp-baseline-reset.mjs` CLI: `--list`, `--target <tool>`,
|
||||
or no-args clear-all) lets the user acknowledge a legitimate MCP
|
||||
server upgrade. New `LLM_SECURITY_MCP_CACHE_FILE` env var overrides
|
||||
the cache path for end-to-end testing without polluting the user's
|
||||
real `~/.cache/llm-security/mcp-descriptions.json`. Migration logic
|
||||
in `loadCache()` seeds `baseline` from existing entries on first
|
||||
read post-upgrade.
|
||||
|
||||
- **8.7 — env-var deprecation warnings** in
|
||||
`scanners/lib/policy-loader.mjs`. New `getPolicyValueWithEnvWarn(section,
|
||||
key, envVarName, defaultValue)` helper. Env-var still wins per
|
||||
existing Preferences, but when BOTH the env-var AND the
|
||||
`policy.json` key are explicitly set, the helper emits a single
|
||||
per-process stderr deprecation line pointing to v8.0.0 removal.
|
||||
Module-scoped `Set` dedupes per env-var name across call-sites.
|
||||
`DEFAULT_POLICY` gains `trifecta.escalation_window: 5` (closes the
|
||||
gap where `LLM_SECURITY_ESCALATION_WINDOW` had no `policy.json`
|
||||
equivalent). Wired through 4 hook call-sites:
|
||||
`pre-prompt-inject-scan`, `post-session-guard` (×2), and
|
||||
`audit-trail`. Env-only vars without `policy.json` equivalents are
|
||||
unchanged.
|
||||
|
||||
### Changed
|
||||
|
||||
- **8.10 — CLAUDE.md hooks count corrected** from `## Hooks (8)` to
|
||||
`## Hooks (9)`. Adds `pre-compact-scan.mjs` row to the hooks table
|
||||
(PreCompact — transcript scan before context compaction). The hook
|
||||
itself shipped in v6.2.0 but the count and table row drifted. New
|
||||
`Hooks count consistency` `describe` block in
|
||||
`tests/lib/doc-consistency.test.mjs` parses `hooks/hooks.json`,
|
||||
reads the CLAUDE.md `## Hooks (\d+)` header and the table rows,
|
||||
and asserts all three counts agree — locks in the fix and prevents
|
||||
future drift.
|
||||
|
||||
### Documentation
|
||||
|
||||
- **8.4 — `riskScoreV1` annotated `@deprecated`** in
|
||||
`scanners/lib/severity.mjs`. JSDoc explicitly tags v7.0.0 as the
|
||||
introduction of the v2 model and v8.0.0 as the removal target for
|
||||
v1, so library consumers see the deprecation in IDE tooling and
|
||||
not just in release notes. The function remains exported and
|
||||
functional for users who relied on it.
|
||||
|
||||
- **8.6 — sandbox-architecture rationale** in
|
||||
`docs/security-hardening-guide.md` §7. Documents why
|
||||
`lib/git-clone.mjs` and `lib/vsix-sandbox.mjs` remain separate
|
||||
rather than being collapsed into a single shared sandbox helper.
|
||||
Brief `Preferences` explicitly rejected the consolidation as
|
||||
premature abstraction over safety-critical code; the rationale is
|
||||
recorded so future maintainers see the deliberate decision.
|
||||
|
||||
### Tests
|
||||
|
||||
- 1665+ → 1777 (Wave A-D cumulative; ~+112 tests). Includes new
|
||||
files (`tests/scanners/bash-normalize-t7-t9.test.mjs`,
|
||||
`tests/lib/git-clone-gitattributes.test.mjs`,
|
||||
`tests/scanners/workflow-scanner.test.mjs`,
|
||||
`tests/lib/workflow-yaml-state.test.mjs`,
|
||||
`tests/scanners/mcp-baseline-reset.test.mjs`) plus extensions to
|
||||
`tests/lib/injection-patterns.test.mjs`,
|
||||
`tests/hooks/pre-bash-destructive.test.mjs`,
|
||||
`tests/hooks/pre-install-supply-chain.test.mjs`,
|
||||
`tests/scanners/scan-orchestrator.test.mjs`,
|
||||
`tests/lib/mcp-description-cache.test.mjs`,
|
||||
`tests/hooks/post-mcp-verify.test.mjs`,
|
||||
`tests/lib/severity.test.mjs`,
|
||||
`tests/lib/policy-loader.test.mjs`,
|
||||
`tests/lib/doc-consistency.test.mjs`. One pre-existing
|
||||
size-cap timing flake at `tests/hooks/pre-compact-scan.test.mjs`
|
||||
passes in isolation, fails sporadically under full-suite load —
|
||||
unchanged across Wave A-D, not a Batch C blocker.
|
||||
|
||||
### Notes
|
||||
|
||||
- **Wave E deferred (red-team coverage).** The plan called for 9 new
|
||||
attack-simulator scenarios covering every Wave A-D defense. The
|
||||
work was deferred from v7.3.0 because two of the scenarios test
|
||||
scanners (workflow-scanner, git-clone `scanGitAttributes`) that
|
||||
don't fit the existing hook-spawn model used by attack-simulator
|
||||
and would have required a new `scanner_test` execution mode.
|
||||
Tracked for v7.3.1. Defenses are unit-tested per wave; this is
|
||||
regression coverage on top of unit coverage, not the primary
|
||||
safety net.
|
||||
|
||||
- **Hooks runtime behavior unchanged for existing setups.** Every
|
||||
Wave A-D addition is either purely additive (new advisories at
|
||||
MEDIUM) or layered before existing detection (T7/T9 normalize
|
||||
before existing destructive-name matching; rot13 inside the
|
||||
existing decoder loop; cumulative-drift independent of per-update
|
||||
drift). Users who set neither the new `policy.json` keys nor the
|
||||
new env-vars see identical behavior.
|
||||
|
||||
## [7.2.0] - 2026-04-29
|
||||
|
||||
Batch B release. Closes the remaining critical-review B-tier scanner
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue