feat(llm-security)!: v8 Phase 3 complete - riskScoreV1, posture heuristic, docs
Closes Phase 3 (B11) of the v8.0.0 plan. Three parts, all with the failing
test written first.
riskScoreV1 removed. scanners/lib/severity.mjs drops riskScoreV1() and its
SEVERITY_WEIGHTS_V1 table - @deprecated since v7.0.0, kept for diff/comparison,
zero callers in code or tests (re-verified, not taken from the plan). The v1
weights are recorded in CHANGELOG so an old score stays re-derivable. riskScore
(v2) is untouched; a test pins that one critical still lands in the 70-95 tier
and that 50 lows score below it, which is exactly the case v1 collapsed to 100.
Posture category 12 no longer keys off an identifier name. The check was
/TRIFECTA_MODE/i over the session-guard source, which measured what a constant
was CALLED rather than whether enforcement was configurable. With the env-var
gone, that regex would have dropped every correctly-migrated project from PASS
to PARTIAL - the gate punishing the migration it exists to encourage. It now
matches getPolicyValue('trifecta', 'mode', ...) and still accepts a pre-v8
vendored guard reading the old env-var, because a third-party project carries
its own hook copy and is equally configurable either way; the evidence line
says which of the two was found. The PARTIAL finding recommended setting an
env-var that v8 ignores; it now names the policy key. The grade-a fixture hook
moves to the policy-era form.
Two never-implemented env-vars deleted from the docs. LLM_SECURITY_SCR_OFFLINE
(ci-cd-guide) and LLM_SECURITY_OFFLINE (supply-chain-attack example) were
documented as OSV.dev / npm-audit kill-switches. No code has ever read either -
verified by grep across scanners, hooks and scripts, which finds them only in
markdown. A promised kill-switch that does nothing is worse than a documented
absence: it is trusted precisely when the run is meant to be air-gapped. The
docs now say there is none and that egress must be blocked at the network
layer. The LLM_SECURITY_AUDIT_* wildcard is narrowed to the one real key.
Docs. Migration section in README + CHANGELOG with the env-var -> policy-key
table, the detection commands (env + shell rc + .envrc + workflows), and the
explicit warning that a removed variable is now INERT rather than an error -
which is the failure mode that loses a project its configuration silently. The
hardening-guide env table splits into surviving vars and a removed-vars
migration table; its "promote to block" runbook named two variables that no
longer exist. Also swept: CLAUDE.md hook table, scanner-reference, ci-cd-guide,
both lethal-trifecta example docs, mitigation-matrix, injection-research.
Test counts in README/CLAUDE.md synced 2034 -> 2045.
Suite 2045 tests, 0 fail (2039 + 4 posture-trifecta + 2 riskScoreV1). The two
known parallel-load flakes did not recur this run.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BB4vXvwvtW4dxbPRd6vsez
This commit is contained in:
parent
b6af9b46df
commit
fdec4b36ad
16 changed files with 333 additions and 62 deletions
55
CHANGELOG.md
55
CHANGELOG.md
|
|
@ -6,6 +6,61 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Removed — BREAKING
|
||||
|
||||
- **The four `LLM_SECURITY_*` configuration env-vars deprecated in v7.3.0.**
|
||||
`.llm-security/policy.json` is now the only source. A removed variable is
|
||||
**inert**: it neither warns nor configures, so a project relying on one
|
||||
silently returns to the default. See the Migration section in `README.md`
|
||||
for the detection commands.
|
||||
|
||||
| Removed env-var | Policy key | Default |
|
||||
|-----------------|------------|---------|
|
||||
| `LLM_SECURITY_INJECTION_MODE` | `injection.mode` | `block` |
|
||||
| `LLM_SECURITY_TRIFECTA_MODE` | `trifecta.mode` | `warn` |
|
||||
| `LLM_SECURITY_ESCALATION_WINDOW` | `trifecta.escalation_window` | `5` |
|
||||
| `LLM_SECURITY_AUDIT_LOG` | `audit.log_path` | unset |
|
||||
| `LLM_SECURITY_DEPRECATION_QUIET` | *(none)* | dies with the warning it silenced |
|
||||
|
||||
Env-vars with no policy equivalent are unaffected:
|
||||
`LLM_SECURITY_PRECOMPACT_MODE`, `LLM_SECURITY_PRECOMPACT_MAX_BYTES`,
|
||||
`LLM_SECURITY_UPDATE_CHECK`, `LLM_SECURITY_MCP_CACHE_FILE`,
|
||||
`LLM_SECURITY_IDE_ROOTS`.
|
||||
|
||||
`getPolicyValueWithEnvWarn` and its one-shot stderr deprecation line are
|
||||
deleted from `scanners/lib/policy-loader.mjs`; the four call sites collapse
|
||||
to `getPolicyValue`. Hook strings that advertised a removed variable as the
|
||||
escape hatch now name the policy key — a blocked user following the old text
|
||||
would have set a variable that does nothing.
|
||||
|
||||
- **`riskScoreV1()`** in `scanners/lib/severity.mjs`, plus its
|
||||
`SEVERITY_WEIGHTS_V1` table. `@deprecated` since v7.0.0, kept for
|
||||
diff/comparison, with zero callers in code or tests. The v1 weights are
|
||||
recorded here for anyone re-deriving an old score:
|
||||
`critical 25, high 10, medium 4, low 1, info 0`, summed and capped at 100.
|
||||
`riskScore()` (v2) is untouched, so no score, band, or verdict moves.
|
||||
|
||||
- **Two documented env-vars that were never implemented.**
|
||||
`LLM_SECURITY_SCR_OFFLINE` (`docs/ci-cd-guide.md`) and `LLM_SECURITY_OFFLINE`
|
||||
(`examples/supply-chain-attack/README.md`) were promised as OSV.dev / npm-audit
|
||||
kill-switches; no code has ever read either. The docs now say plainly that
|
||||
there is no kill-switch and that an air-gapped run must block egress at the
|
||||
network layer. The `LLM_SECURITY_AUDIT_*` wildcard phrasing (README,
|
||||
`docs/scanner-reference.md`, `docs/security-hardening-guide.md`) is narrowed
|
||||
to the single real key.
|
||||
|
||||
### Changed
|
||||
|
||||
- **Posture category 12 (Rule of Two) no longer keys off the identifier
|
||||
`TRIFECTA_MODE`.** The check was `/TRIFECTA_MODE/i` over the session-guard
|
||||
source, which measured what a constant was *named* rather than whether
|
||||
enforcement was configurable at all. It now matches
|
||||
`getPolicyValue('trifecta', 'mode', …)`, and still accepts a pre-v8 vendored
|
||||
guard reading `LLM_SECURITY_TRIFECTA_MODE` — third-party projects carry their
|
||||
own hook copy and are equally configurable. Without this, every correctly
|
||||
migrated project would have dropped from PASS to PARTIAL. The PARTIAL
|
||||
finding now recommends the policy key instead of the removed env-var.
|
||||
|
||||
## [7.8.3] - 2026-07-18
|
||||
|
||||
Security and correctness patch. 47 verified fixes from the v7.8.1/v7.8.2
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue