The v7.0.0 entropy-scanner rule 18 suppressed every line whose pattern
matched  — regardless of the URL host or what the URL
carried. A markdown image URL pointing at a non-CDN host (or carrying a
secret-shaped token in its query string) would therefore mask a real
high-entropy credential.
Refactor:
* MARKDOWN_IMAGE now captures the full URL (was a host-only prefix
matcher), so rule 18 can inspect host and query.
* MARKDOWN_IMAGE_CDN_HOSTS allowlist constant covers cdn./images./
media./assets./static./*.cdn./*.amazonaws.com/{s3,cloudfront}/
*.cloudflare./*.fastly./*.akamaized./raw.githubusercontent.com/
*.imgix.net/*.cloudinary.com/.
* MARKDOWN_IMAGE_QUERY_SECRET catches secret-shaped query keys
(token, key, secret, password, api_key, access_token, auth) plus
well-known provider prefixes (AKIA, Bearer, sk_live_, ghp_, ghs_,
ghu_, gho_, ghr_, npm_).
* Rule 18 now suppresses iff (host matches CDN allowlist) AND
(query has no secret-shaped token). Anything else falls through
to entropy classification.
+4 tests in tests/scanners/entropy-context.test.mjs (29 → 33).
Existing rule 18 fixture (cdn.example.com, no secret query) still
suppresses, so no regression on the legitimate path.
Refs: Batch B Wave 5 / Step 13 / v7.2.0
critical-review-2026-04-20.md §E18
The v7.0.0 entropy-scanner ran rules 11-13 (GLSL/CSS-in-JS/inline-markup
line-proximity suppressions) for every line regardless of file type. A
polyglot `.ts` file with an embedded fragment-shader template literal
could therefore mask a real high-entropy credential when the credential
literal happened to share a line with a GLSL keyword. Critical-review
B5 documented the false-negative class.
Refactor:
* New `classifyFileContext(absPath, lines)` returns
`'shader-dominant' | 'markup-dominant' | 'code-dominant' | 'mixed'`,
keyed off file extension with a content-density fallback for
code-extension files (≥50% of sampled non-blank lines matching
GLSL/inline-markup → downgrade to `mixed`).
* `isFalsePositive(str, line, absPath, context)` gates rules 11-13
on `context !== 'code-dominant'`. Rules 1-10 and 14-19 still run
unconditionally, so URL/path/test-fixture/ffmpeg/UA/SQL/error-
template suppression behaves identically.
* `scanFileContent` computes `fileContext` once per file and threads
it through every per-string suppression check.
Conservative defaults to keep the regression surface minimal:
* Files with `<5` sampled non-blank lines fall back to `mixed`
(preserves the existing rule-11/12/13 behaviour for the single-
line .js fixtures used by entropy-context.test.mjs).
* Unknown extensions fall back to `mixed`.
* Code-extension files densely populated with shader/markup
content fall back to `mixed`.
Net effect: a `.ts` file with an embedded GLSL block but mostly TS
code on the surrounding lines now surfaces credentials that the
v7.0.0 line-proximity heuristic suppressed. Pure shader/markup
files are unaffected (extension skip / mixed default).
New fixture: tests/fixtures/entropy/polyglot-ts-with-glsl.ts (with
runtime placeholder so it does not commit a high-entropy literal).
+3 tests in tests/scanners/entropy-context.test.mjs (26 → 29).
Existing entropy.test.mjs and entropy-context.test.mjs all remain
green. Full suite 1658 → 1661.
Refs: Batch B Wave 5 / Step 12 / v7.2.0
critical-review-2026-04-20.md §B5
E2E verification against content-heavy repo (`content-claude-code`) revealed
413 entropy findings (8 HIGH / 405 MEDIUM) from markdown image CDN URLs in
JSON content indexes — e.g., ``.
These are legitimate content-repo artifacts, not credentials. The 40-char
hash segment in the CDN URL trips Shannon entropy (H=5.29 over 300 chars),
and rule 13 (inline <svg>) doesn't match since there's no literal `<svg>`
tag — the `.svg` is just a URL path suffix.
Added rule 18 `MARKDOWN_IMAGE = /!\[[^\]]*\]\(\s*https?:\/\//` — matches
`` / ``. Line-level (not string-level) so URL
is not over-specific.
E2E impact on `content-claude-code`:
- Before: BLOCK / 65 / 8H 437M 0L
- After: WARNING / 56 / 3H 427M 0L
Hyperframes unchanged: BLOCK / 80 / 1C 4H 92M — real CRITICAL SQL-injection
and HIGH findings still detected.
Tests: 2 new (positive + negative fixture) bringing entropy-context to 26,
total suite 1485 → 1487.
Docs updated to "rules 11-18" and "8 new line-suppression rules".
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Final commit in the trustworthy-scoring series. Bundles verdict cutoff
alignment, the last suite of tests, and all documentation touch-points
that quote version numbers or describe v7.0.0 behaviour.
Verdict/band co-monotonicity
- `scanners/lib/severity.mjs` — verdict cutoffs moved from 61/21 to 65/15
so `BLOCK >= 65`, `WARNING >= 15` locks onto the v2 riskBand() boundaries.
Prevents "BLOCK / Medium band" contradictions under the v2 formula.
Scanner hardening (bug fixes from v7.0.0 testing)
- `scanners/entropy-scanner.mjs` — `policy_source` now uses
`existsSync('.llm-security/policy.json')` instead of value-based check.
Old heuristic always reported 'policy.json' because DEFAULT_POLICY now
carries an `entropy.thresholds` section.
- `scanners/lib/file-discovery.mjs` — `.sass` and GPU shader extensions
(`.glsl, .frag, .vert, .shader, .wgsl`) added to TEXT_EXTENSIONS. Without
this, shader files were invisible to file-discovery, so they were never
counted as skipped by the entropy-scanner extension filter.
Tests
- `tests/scanners/entropy-context.test.mjs` (new, 24 tests) — A. File-ext
skip (4), B. Line-level rules 11-17 (8), C. Policy overrides (3).
Fixtures generate 80-char base64 payloads at runtime via
`crypto.randomBytes` to dodge the plugin's own pre-edit credential hook
on the test source.
- `tests/lib/severity.test.mjs` — rewritten with v2 scoring table (70
tests total, was 52).
- `tests/lib/output.test.mjs:243` — "1 critical = score 80" under v2
(was 25 under v1).
- Full suite: 1485/1485 green (was 1461).
Docs
- `CHANGELOG.md` — v7.0.0 entry with BREAKING CHANGES section.
- `README.md` (plugin + marketplace root) — version badge, history table,
plugin-card version string, test count.
- `CLAUDE.md` — header version, "v7.0.0 — Trustworthy scoring" summary
paragraph at the top.
- `docs/security-hardening-guide.md` — new section 6 "Calibration & false
positives" documenting v2 formula, context-aware entropy scanner,
typosquat allowlist, and §6.4 tuning workflow. Existing "Recommended
baseline" section renumbered to §7.
Version bump
- `6.6.0 -> 7.0.0` across package.json, .claude-plugin/plugin.json,
scanners/ide-extension-scanner.mjs VERSION const, README badge,
CLAUDE.md header, marketplace root README card.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>