# Changelog

## 2.27.2

### Patch Changes

- e2b67fd: Secrets scanner: the gitleaks git-history pass no longer chokes on giant
  committed caches. `git log -p --all` materializes diffs of EVERY committed blob,
  so a repo that ever committed a large `.turbo/`/`node_modules` cache (hundreds of
  MB per blob) made the history pass hit its timeout — regardless of gitleaks'
  own scanning speed, because the cost was git producing the patch. The history
  pass now excludes the same generated/dependency/VCS dirs (WORKING_TREE_SKIP_DIRS)
  from git's diff via a `--log-opts` pathspec (`-- . :(exclude,glob)**/<dir>/**`).
  On our own repo this took the history pass from a 90s timeout (soft "history not
  fully scanned" note) to ~1.5s scanning all 372 commits.

  Also: removed a `--max-target-megabytes` cap that had been added alongside — it
  would silently skip files >50MB, contradicting the "never report clean when we
  didn't scan it" invariant. Giant caches are excluded structurally instead
  (working-tree readdir skip + history pathspec), so a large file in a REAL path is
  still scanned (or times out → honest degradation), never silently dropped.
  `.turbo/` added to `.gitignore` to prevent re-committing cache blobs. Independent
  security review: GO.

- 325d249: apps/web: bump Next.js 16.2.12 → 16.3.2, which pulls the patched `sharp` 0.35.3
  and clears the last high-severity advisories (libvips CVEs CVE-2026-33327/33328/
  35590/35591 via sharp, and the Next server-function disclosure). `apps/web` now
  audits with 0 vulnerabilities. (apps/web is the marketing/dashboard app, not part
  of the published `vaspera` package; Vercel builds it on deploy.)

## 2.27.1

### Patch Changes

- 95dc711: Dependency hygiene (found by dogfooding Vaspera's own SCA layer on this repo):
  applied all non-breaking `npm audit fix` updates. Root resolved 10 of 12
  advisories (incl. `ip-address` SSRF, `brace-expansion`/`shell-quote` DoS,
  `postcss`, `js-yaml`, `nanoid`, `hono`, `body-parser`) — all in-range lockfile
  updates, no `package.json` range changes, build verified clean. No criticals.

  Deferred (require breaking/forced bumps, tracked separately): `shell-quote` via
  the dev-only `concurrently` (negligible, not shipped), and `apps/web`'s `sharp`
  which needs a forced `next@16.3.2` bump — held for a deliberate Next upgrade +
  preview test. `apps/web` is not part of the published package.

- eff391f: Secrets scanner: run the critical working-tree pass FIRST and treat a git-history
  timeout as best-effort, not degradation. Previously both gitleaks passes shared a
  90s bound and a history-pass timeout (common on a large `--log-opts=--all`
  history) counted the same as a real failure. Now:

  - Working-tree pass (proves current code is clean) runs first with a generous,
    configurable timeout; only its failure sets `degraded` (current code unscanned).
  - History pass runs second, best-effort: a timeout leaves `scannedHistory=false`
    (a soft "history not fully scanned" note) without degrading the result.

  Self-cert distinguishes the two and runs gitleaks uncontended (outside the
  concurrent code-scanner batch). Regression tests lock both invariants
  (working-tree timeout → degraded; history timeout → not degraded). Independent
  security review: GO (recall preserved; a degraded/incomplete scan can never
  present as clean).

  Known limitation (separate follow-up): `gitleaks --no-git` walks the raw
  filesystem including `node_modules`, so on repos with a very large `node_modules`
  the working-tree pass can still time out and report degraded. A proper fix
  (skip gitignored/dependency dirs) is tracked separately.

- 0b97836: Secrets scanner: the gitleaks working-tree pass no longer scans `node_modules`
  (and other generated/dependency/VCS dirs). `gitleaks --no-git` walks the raw
  filesystem and ignores `.gitignore`, so on any JS project it scanned tens of
  thousands of dependency files (23k here) — minutes of work → timeout → a false
  "secrets DEGRADED". It now enumerates top-level entries and runs gitleaks
  per-entry, skipping only unambiguously generated/tooling dirs (`node_modules`,
  `.git`, `.next`, `.nuxt`, `.svelte-kit`, `.turbo`, `.cache`, `coverage`,
  `.vaspera`, `.venv`, `venv`). Ambiguous dirs a project might fill with
  first-party code (`build/`, `out/`, `vendor/`) are deliberately NOT skipped, so
  recall is preserved.

  - Path integrity: gitleaks reports absolute file paths, rebased to repo-relative
    via `relative(projectPath, …)`; a pure-unit test (no binary) enforces this in
    CI so finding locations can't silently corrupt.
  - Degradation invariant preserved: any working-tree sub-scan hard failure
    (crash/timeout) still degrades the whole result; a history-pass timeout remains
    a best-effort soft note. Independent security review: GO.

  Result: the working-tree pass completes in seconds instead of timing out — a
  universal win for any JS project, and self-cert reports clean instead of a
  spurious degradation.

- 13a6363: Precision: stop the built-in JS/TS engines from firing on test/fixture files and
  labeled-vulnerable eval corpora, and fix an inverted clickjacking rule.

  Found by dogfooding Vaspera on its own repo: a default scan reported ~13 false
  critical findings because the built-in engines (`web-safety`, `adversary-tactics`,
  `db-antipatterns`, `detection`) scanned `src/eval/fixtures.ts` — our
  intentionally-vulnerable labeled corpus — and other test files. The 2.27.0
  test-dir exclusion only covered the external CLI scanners (Bandit/Gosec/Brakeman).

  - Built-in engines now skip test/fixture paths in a normal directory scan, scoped
    narrowly to the corpus file (`eval/fixtures.*`, `*.fixtures.*`, `fixtures/`,
    `__tests__/`, `*.test.*`, `*.spec.*`) — NOT any bare `eval/` directory, so a real
    product's `eval/` feature dir is still scanned. Eval/benchmark recall is
    unaffected (the harness scans fixture content from a temp dir; an explicit
    `scanTestFixtures` escape hatch is also available).
  - Fixed a semantically-inverted clickjacking rule that flagged `frame-ancestors
'none'` and `X-Frame-Options: DENY` (both PROTECTIONS) as "frame options
    disabled." It now fires only on genuine disables (`frameguard: false`,
    `X-Frame-Options: ALLOWALL`).

  Result on a self-scan: false positives on the eval corpus drop to zero and the
  inverted clickjacking finding is gone — remaining findings are real code.

- c81e940: Revive the TypeScript scanner — it was silently dead for every user. The scanner
  module is ESM (`"type": "module"`) but its tsconfig-discovery helpers used
  `require("fs")` / `require("path")`, which throws `require is not defined` at
  runtime. The whole scanner failed (`success:false`, 0 findings) on every scan, so
  `tsc` always landed in `failedScanners` and no TypeScript type-safety findings
  (any-usage, `@ts-ignore`, unsafe assertions, missing return types) were ever
  produced. Replaced the `require()` calls with real ESM namespace imports.

  Found by dogfooding Vaspera on its own repo (`failedScanners:["tsc"]`). After the
  fix the scanner completes and returns findings; a regression test asserts it runs
  under ESM without the `require is not defined` failure.

- 4432c8a: Self-certification now gates on the deterministic code-scanning layer, not just
  the agent scanners — so the "we pass our own strictest certification" claim
  finally covers our SAST/code engines.

  - `scripts/self-certify.ts` runs `runAllScannersWithAutoDetect` as a second phase
    and BLOCKS on code-layer critical/high > 0. Dependency CVEs are report-only
    (governed by the supply-chain scanner + audit flow); secrets are handled
    separately with a loud degradation warning (never allowed to silently pass or
    pollute the gate with regex-fallback noise).
  - Honors the 2.27.0 trust invariant: the gate BLOCKS if a required code scanner
    (semgrep/detection/logic/adversary-tactics/web-safety/db-antipatterns/tsc) did
    not actually run — a clean result is meaningless if the scanner never executed.
  - Hermetic: self-cert runs semgrep with offline bundled rules
    (`VASPERA_SEMGREP_NO_REGISTRY=1`) — no network, no `semgrep login`, fast.

  Product precision fixes (found dogfooding): trivy now excludes build-artifact
  dirs (`dist`/`build`/`.next`/`coverage`) and the eval fixture corpus, matching
  the built-in engines; `runAdversaryTacticsScanner` gained an `additionalIgnore`
  option so the scanner's own rule/tactic-definition dirs (which contain
  vuln-SHAPED strings by design) aren't self-flagged.

  Also bumped `concurrently` and forced `shell-quote` ^1.8.5 (root now audits clean).

- cde49d7: Self-hardening (found by dogfooding Vaspera on its own repo):

  - **`scripts/release-notes.ts`** now runs git via `spawnSync` with array args
    instead of `execSync` with a concatenated shell string — clearing two critical
    `cmd-exec-concat` findings our own scanner (correctly) raised against us, and
    satisfying our own "no string-concat shell commands" constitution rule.
  - **`.gitleaks.toml`** had custom `[[rules]]` with empty allowlists, which made
    gitleaks 8.x **fail to load the config and silently skip the git-history secret
    pass on our own repo**. Replaced with valid global-allowlist path entries that
    preserve the original intent (suppress secret-shaped regexes in
    pattern-definition/redaction/help-text files) without weakening recall
    elsewhere. Verified: config loads and the history pass runs.

## 2.27.0

### Minor Changes

- Restore trust: never report "clean" when a scan didn't actually run.

  - **Secrets (recall-biased):** gitleaks now scans BOTH git history (all refs) and
    the working tree, then merges/dedups — so secrets that were committed and later
    removed are still caught. Suppression is relaxed for the secrets scanner only
    (no test-path skipping, lower entropy floor, exact-token placeholder matching)
    so a live credential in `tests/` or one containing a substring like "secret" is
    no longer dropped. Added Postgres/MySQL/MongoDB/JDBC/`DATABASE_URL` connection-
    string patterns to the regex fallback.
  - **Loud degradation:** scanners now carry a `degraded` signal. If gitleaks is
    missing (weak regex fallback) OR a core scanner (gitleaks/semgrep) crashes,
    times out, or overflows its buffer, `certification_scan` prepends an
    "INCOMPLETE COVERAGE — DO NOT TREAT AS CLEAN" banner and a Coverage & Degradation
    report. A clean result now means "we actually scanned with real tools."
  - **Python precision:** Bandit config (`pyproject.toml [tool.bandit]` / `.bandit` /
    `setup.cfg [bandit]`) is auto-detected and propagated, and code scanners
    (Bandit/Gosec/Brakeman) now exclude test directories by default — killing the
    `B101 assert_used` noise. The secrets scanner is deliberately exempt.
  - **Scan scope:** `certification_scan` accepts optional `include`/`exclude` globs
    (user `exclude` merges with the default test-dir exclusion).
  - **Telemetry is now OPT-IN, off by default.** Nothing is sent unless
    `VASPERA_TELEMETRY_ENABLED=1`. Docs updated (README + TELEMETRY.md).
  - **Docs/install fixes:** correct npm package name (`vaspera`, bin
    `vaspera-hardening`) across README, CLAUDE.md, the audit skill, and the MCP
    registry manifest (`server.json`); working Quickstart + Claude Desktop config.

## 2.26.0

### Minor Changes

- [#162](https://github.com/RCOLKITT/hardening-mcp/pull/162) [`caeefe8`](https://github.com/RCOLKITT/hardening-mcp/commit/caeefe81b85f080b8f16149d90a43828b40f0b24) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Mass-assignment (CWE-915) and prototype-pollution (CWE-1321) detection

  Two new default-on deterministic rules for classes that commonly breach AI-built apps:

  - **`vaspera-mass-assignment`** — the whole request body flowing into an ORM/DB write is over-posting: a user can set fields they shouldn't (e.g. `isAdmin`, `role`). Flags Drizzle `.values(req.body)` / `.values({ ...req.body })` / `.set(req.body)`, Prisma `create({ data: req.body })` / `update({ …, data: req.body })`, and Mongoose `updateOne`/`findByIdAndUpdate(…, req.body)`. Structural matching keeps an explicit field allowlist (`values({ email: String(req.body.email) })`) a clean true negative — the fix is to allowlist fields.
  - **`vaspera-prototype-pollution`** — user-controlled dynamic property writes: `obj[req.body.key] = value` and `Object.assign(target, req.body/query/params)`. Static keys and no-source assigns are true negatives.

  Verified at 100% precision on the labeled corpus and zero false positives on a real Drizzle/Supabase app.

## 2.25.0

### Minor Changes

- [#159](https://github.com/RCOLKITT/hardening-mcp/pull/159) [`6667661`](https://github.com/RCOLKITT/hardening-mcp/commit/6667661f4fdeeb923a2ee5f6d1013823233ac42b) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Deterministic path-traversal detection (CWE-22)

  Path traversal was barely detected by the deterministic layer — the only rule matched `fs.readFile($path)` (the `fs.`-prefixed, direct-path form) and missed the two most common modern patterns: destructured `import { readFile } from "fs/promises"` and a `join(dir, userInput)`-wrapped path. A new `vaspera-path-traversal` taint rule (default-on) now flags request input (`req.query`/`params`/`body`/`headers`) flowing into filesystem read/write sinks in both the `fs.`-prefixed and bare/destructured forms (readFile/readFileSync/writeFile/createReadStream/unlink/rm/sendFile/…), following the dataflow through `join()`/`path.join()`. `path.basename()` is recognized as a sanitizer. Verified at 100% precision on the labeled corpus and zero false positives on two real production apps. Known limitation: a const-object allowlist lookup (`ALLOWED_FILES[userKey]`) is over-flagged, because taint analysis can't distinguish it from unsafe user-controlled indexing without missing real vulnerabilities.

## 2.24.3

### Patch Changes

- [#155](https://github.com/RCOLKITT/hardening-mcp/pull/155) [`96c12ed`](https://github.com/RCOLKITT/hardening-mcp/commit/96c12ed2a255f335004328e0c0a551ce0c909ddd) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - SQL-injection detection: don't false-flag parameterizing `sql`` tags (Drizzle/postgres.js/slonik) + clean semgrep rule ids

  The `vaspera-sql-injection` taint rule flagged `db.execute(sql`... ${req.query.id}`)` as SQL injection — but a `sql`` tagged template turns `${}`into a bound parameter, so it is safe. This false-positived on essentially every Drizzle/Supabase codebase. Added a`sql```sanitizer to the rule (raw string-concatenation and raw-driver template-literal queries are still flagged;`sql.raw()`remains unsanitized because it is genuinely unsafe). Also fixed a cosmetic bug where builtin semgrep findings rendered their rule id with a temp-directory path prefix — they now render cleanly as`semgrep:vaspera-sql-injection`.

## 2.24.2

### Patch Changes

- [#152](https://github.com/RCOLKITT/hardening-mcp/pull/152) [`e8d8a6f`](https://github.com/RCOLKITT/hardening-mcp/commit/e8d8a6fbf56ba19f65eb2fcceb61bd44a9bc5561) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Scanner precision: webhook-signature and detection auth-bypass false positives (found by dogfooding VasperaGTM + AccountingQB)

  - **Webhook signature detector** no longer flags verified webhooks (Clerk `verifyWebhook`, Stripe `stripe().webhooks.constructEvent`, svix, HMAC) or non-webhook routes (a bare POST handler; a module that merely references a `*_WEBHOOK_SECRET`). It now requires a real webhook signal (a webhook route path or a signature-header read), recognizes more provider headers, and strips comments before the verify check so a commented-out verify call can't hide a real finding.
  - **Detection engine** now excludes test/spec/fixture/mock/example files from all rules, so `auth-bypass:missing-middleware` no longer fires on test files (e.g. Python `tests/test_*.py`).

  Both were found by running the free deterministic scan on real apps and fixed with regression tests that pin the true positives. Recall preserved.

## 2.24.1

### Patch Changes

- [#147](https://github.com/RCOLKITT/hardening-mcp/pull/147) [`b6b7960`](https://github.com/RCOLKITT/hardening-mcp/commit/b6b7960ad7449b65eba736629544a05ef70c5762) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Logic access-control scanner: real-repo precision fix (dedup + pure-insert guard)

  Dogfooding a real app surfaced the logic scanner emitting one BOLA/IDOR/BFLA finding per data-access token (from/eq/select) instead of one per endpoint — inflating an endpoint that lacks an ownership check into many near-duplicate findings. Now findings are deduplicated per (file, endpoint, vulnerability type), keeping the most-severe representative; distinct endpoints and vulnerability types stay separate, so recall of the distinct set is unchanged. A conservative pure-insert guard also stops flagging genuine object-creation-with-no-id endpoints (e.g. a waitlist/newsletter signup) as BOLA/IDOR, while a create that reads an existing object id from the request body (real IDOR-via-body) is still flagged.

## 2.24.0

### Minor Changes

- [#144](https://github.com/RCOLKITT/hardening-mcp/pull/144) [`f111002`](https://github.com/RCOLKITT/hardening-mcp/commit/f1110023cb6082f88107859b01ba599db8f85bdc) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Runtime-proof variants for the web-safety findings + a real-repo precision fix

  - **Runtime-proof variants (Pro).** `runtime_flow_generate --template security-proof` now also scaffolds behavioral proofs for the deterministic web-safety findings — `rls-off-cross-tenant-leak` (account A creates a row, account B reads it → must be denied), `webhook-signature-forgery` (a forged non-destructive event is rejected), and `csrf-token-replay` (a cross-origin state-change with no token is rejected). These only execute via `runtime_verify`, which is gated on `authorized: true` (CFAA) + the Pro runtime-proof entitlement. Non-destructive by design.
  - **Precision fix (found by dogfooding a real app).** The `web-safety:service-role-client-exposed` rule matched the word `window.` inside a JSDoc comment and flagged legitimate server-only service code as a browser-exposed critical. Client-reachability checks now run against comment-stripped source, and the `use client` signal is tightened to a leading directive. Verified on a real financial repo: two critical false positives dropped to zero while the real RLS-disabled findings held.

## 2.23.0

### Minor Changes

- [#140](https://github.com/RCOLKITT/hardening-mcp/pull/140) [`0cbf1cc`](https://github.com/RCOLKITT/hardening-mcp/commit/0cbf1cc472ab75abf24faa1fd3b6e2039b077f1c) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Vibe-safety: the deterministic detectors for the top real-world AI-coding breach classes are now default-on and free

  A plain `certification_scan` (no `auto_detect` needed) now catches — for free, deterministically — the classes that actually breach vibe-coded apps, which the default scan previously missed:

  - **RLS-disabled Supabase/Postgres tables** — the #1 breach (a table shipping without Row Level Security). Global cross-file analysis so a table created in one migration and RLS-enabled in another is correctly not flagged.
  - **Client-exposed secrets** — `NEXT_PUBLIC_*` service-role / secret keys leaked to the browser bundle (the public anon key is intentionally not flagged).
  - **Missing webhook signature verification** — Stripe/Clerk/svix handlers with no `constructEvent`/`verify`/HMAC check.
  - **CSRF, CORS misconfiguration, security headers / clickjacking, missing rate-limits** — the `adversary-tactics` web checklist, now eval-gated (low-precision rules quarantined) and default-on.
  - **Missing auth on endpoints + IDOR/BOLA** and the **DB/scalability antipattern** and **Dockerfile/container** scanners now run in the base free scan too (previously only under `auto_detect`).

  All hostile-input-hardened (bounded walks, size caps, symlink-skip, ReDoS-safe) and validated against the zero-false-positive accuracy floor; each `src/scanners` change went through an independent security review. Positioning is unchanged: deterministic detection is free ($0 COGS); Pro remains LLM deep-proof + runtime two-account proof + autofix + Sigstore attestation + framework breadth. See `docs/COVERAGE-MATRIX.md`.

## 2.22.0

### Minor Changes

- [#134](https://github.com/RCOLKITT/hardening-mcp/pull/134) [`7968f52`](https://github.com/RCOLKITT/hardening-mcp/commit/7968f5289614097550b0ff931cd84c4a6470ef18) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Container/base-image scanning + certification drift detection

  - **Container & base-image scanning (#132).** The Trivy scanner now lints Dockerfiles (`FROM` unpinned/`:latest`, missing `@sha256:` digest — no network, always on when a Dockerfile is present), runs Dockerfile/IaC misconfig via `trivy config`, and adds an opt-in `baseImageCve` mode that pulls the base images named in the repo's `FROM` lines and reports their OS-package CVEs. Base-image scanning is off by default and hardened for hostile repos (anchored image-ref validation, `--` arg terminator, 5-image cap, per-image timeout).
  - **Certification drift & staleness detection (#133).** New `certification_check_drift` MCP tool reports when a certification has gone stale: age-expiry, code-change drift (project_hash), and — the new capability — **advisory drift**, i.e. new CVEs that dropped against the certified dependency set since the cert was issued (diffed against an advisory baseline snapshotted at finalization). Ships a standalone drift entrypoint + a daily scheduled GitHub Actions workflow that flags when a re-scan is recommended.
  - Attestation honesty: `certification_check_drift` and `certification_scan` now declare `codeExecution`/`networkAccess` in the signed manifest, locked by a guard test.

## 2.21.0

### Minor Changes

- [#130](https://github.com/RCOLKITT/hardening-mcp/pull/130) [`6bee770`](https://github.com/RCOLKITT/hardening-mcp/commit/6bee77053ca5b0e07565949d10040ba277f29dc2) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Scanner coverage: multi-package (monorepo) dependency audit + deterministic DB/scalability antipattern scanner

  - **Monorepo-aware SCA (#128).** `npm audit` now runs per package across the whole repo, not just the root — nested standalone packages (e.g. an `apps/web` with its own lockfile that isn't a declared root workspace) are discovered and audited, with advisories attributed to `<pkg>/package.json`. The package walk is hostile-input hardened (skips symlinks, depth/count/node caps, pinned registry). This closes a real miss where a nested app's dependency CVEs went unreported.
  - **DB/scalability antipattern scanner, default-on (#129).** A new deterministic scanner runs in every certification and flags missing pagination, `SELECT *` over-fetch, connection-pool-per-request, missing indexes (cross-referenced against the project's Drizzle schema), O(n²) iteration, and Drizzle-aware N+1. Previously scale detection was only reachable via the `scale_*` tools and never ran in a normal `certification_scan`.
  - Also includes the Snyk-reported dependency vulnerability fixes (#127).

## 2.20.0

### Minor Changes

- [#125](https://github.com/RCOLKITT/hardening-mcp/pull/125) [`d7fce23`](https://github.com/RCOLKITT/hardening-mcp/commit/d7fce2339ed2388dacd40f393ff0e12f82a21321) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - CLI/MCP → dashboard sync. Completed certifications now push to your Vaspera
  dashboard when connected, so scans show up under Certifications (and power
  Trends + Compliance) instead of only emitting anonymous telemetry.

  - New `hardening_connect` MCP tool: link a machine to your account once — it
    verifies your API key against the dashboard and saves it per-user to
    `~/.vaspera/profile.json` (owner-only). Call with no key to check status.
  - Per-user credential resolution: the scan push uses `VASPERA_API_KEY` (env,
    wins) or the saved profile — no shared/platform env var required.
  - Opt out any time with `VASPERA_INGEST_DISABLED=1`.

## 2.19.3

### Patch Changes

- [#114](https://github.com/RCOLKITT/hardening-mcp/pull/114) [`52bc585`](https://github.com/RCOLKITT/hardening-mcp/commit/52bc585ed8dcb8c82eb6886632a9104af27952f6) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - `tsc` and `eslint` scanners are now **monorepo-aware** — they discover and run
  per workspace instead of scanning only the repo root. On a pnpm/npm workspace
  monorepo (where the root has a solution-style or absent config and the real
  `tsconfig.json` / `eslint.config.*` live under `apps/*` and `packages/*`), both
  scanners previously resolved zero files and reported "did-not-run — coverage
  INCOMPLETE" (the loud-failure surfacing shipped in 2.19.1). Now they actually
  certify types and lint across the whole monorepo.

  - New `src/util/workspaces.ts` (`findWorkspaceRoot`, `discoverWorkspaceDirs`)
    discovers workspace dirs from root `package.json` `workspaces` globs +
    `pnpm-workspace.yaml`; extracted from the hallucination checker, which now
    reuses it.
  - `tsc`: enumerates each workspace's `tsconfig.json`, resolves solution-style
    `references`, runs `createProgram` per config, dedups diagnostics by
    `file:line:code`, hard-capped at 25 configs.
  - `eslint`: runs per workspace with the correct `cwd`, handles ESLint 9 flat
    config (no `--ext`) vs legacy `.eslintrc`, dedups by `file:line:ruleId`,
    capped at 25 workspaces.
  - **Path containment**: workspace globs and TS project `references` are gated so
    a hostile scanned repo (e.g. `pnpm-workspace.yaml` with `packages: ["/etc"]`
    or a `references` entry pointing `../../..`) cannot steer discovery, an eslint
    `cwd`, or a tsconfig load outside the validated project tree.

## 2.19.2

### Patch Changes

- [#112](https://github.com/RCOLKITT/hardening-mcp/pull/112) [`ca96d5c`](https://github.com/RCOLKITT/hardening-mcp/commit/ca96d5c4a4b5d9669500a123561982b97d0a8cd6) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Precision safety-net for the consensus scoring (P1/P2 follow-up to the
  heuristic-scanner FP fixes): an **un-cross-verified finding from a low-precision
  heuristic scanner** (detection, adversary-tactics, ai-code) can no longer, on its
  own, hard-block a certification or drive the score to zero. Via a new
  `effectiveSeverity()`:

  - a heuristic critical/high with no cross-verification is demoted one notch for
    scoring + level determination (a heuristic "critical" no longer forces BLOCKED),
  - below an 85 confidence floor it drops to `info` (stays visible, stops inflating
    the critical/high counts),
  - **deterministic scanners** (semgrep/gitleaks/npm-audit/trivy) and any
    **cross-verified** finding keep their full severity and still block as before.

  This prevents the "18 phantom heuristic criticals → 0/100, BLOCKED" outcome from
  the dogfood while preserving real signal. Reserves the certification-blocking
  power for the trustworthy deterministic layer and confirmed findings.

## 2.19.1

### Patch Changes

- [#110](https://github.com/RCOLKITT/hardening-mcp/pull/110) [`9c4f80c`](https://github.com/RCOLKITT/hardening-mcp/commit/9c4f80cd12a85820b682552cbc9d05518fd2527a) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Major precision fix for the heuristic scanners, driven by dogfooding on a real
  clean monorepo that produced ~777 findings / ~0 real (all from three heuristic
  scanners emitting under `critical` / `confidence:100`). The deterministic core
  (semgrep, gitleaks, npm-audit, trivy) was always correct; these fixes bring the
  heuristic layer in line. On the dogfood repo: SQLi criticals 17→0, IDOR FPs 7→1
  (the 1 is a genuine service-role+request-input flag), hallucinations 639→1 — with
  recall guards so genuinely vulnerable code still fires.

  - **Preserve per-finding confidence.** The scanner→certification mapping hardcoded
    `confidence: 100`, so a 70–95-confidence heuristic finding masqueraded as
    certain. It now carries the scanner's real confidence (deterministic scanners
    still default 100).
  - **SQL-injection requires a real sink.** Removed two sinkless adversary regex
    rules (`sql-raw-query`, `sql-format-string`) that matched any SQL-ish keyword +
    `${` (so `` `Option A: Update Code ${badge}` `` was a "critical SQLi"); dropped
    bare `exec(` (shell, not SQL) from `sql-string-concat`. The detection engine's
    taint rule now also requires a SQL-execution callee **and** a SQL statement
    keyword before flagging a template-literal sink.
  - **IDOR taint precision.** The detection engine now treats values from
    `auth.getUser()` / `getSession()` (and `.user.id`) as server-derived (not
    request taint), binds the IDOR sink to the tenant-boundary column specifically
    (a request value on a non-tenant `.eq()` is not IDOR), and recognizes guard
    middleware (`getAdminOrError`, `requireUser`, `withAuth`, …) as authorizing the
    handler.
  - **Monorepo-aware hallucination checker.** Import resolution now walks to the
    nearest workspace `package.json` (unioning all dep buckets), reads `workspaces`
    globs + `pnpm-workspace.yaml`, honors tsconfig `paths`/`baseUrl` aliases (`@/*`),
    and skips relative/type-only/built-in imports — so real workspace deps and path
    aliases are no longer flagged as "not installed".

## 2.19.0

### Minor Changes

- [#107](https://github.com/RCOLKITT/hardening-mcp/pull/107) [`b82473f`](https://github.com/RCOLKITT/hardening-mcp/commit/b82473fe9273c54634adc5443fdcad380eced665) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Teach the LLM analysis agents + refutation verifier to detect **cross-query /
  RLS-bypass cross-tenant leaks** — a class found by an independent audit of a real
  product that the agents previously missed. The shape: a read/write via a
  service-role / admin / RLS-bypassing client on a per-user/per-tenant table that is
  scoped only by shared, non-tenant columns (a slug, name, repo, email), or where an
  authorization/opt-in gate is checked on one query but the data is read by a
  separate query that is not joined on the same `user_id` — so the served row can
  belong to another tenant. Most severe on public/unauthenticated endpoints.

  - `logic-flaw-detector`: new "Multi-tenant / RLS" prompt guidance (report as its
    own high/critical trust-boundary finding, not buried in a reliability note),
    plus a precision rule so a service-role query that IS scoped to the session
    `user_id`/`tenant_id`, or a query on a shared non-per-user reference table, is
    not flagged.
  - `antagonist/verifier`: the ACCESS CONTROL rule now confirms the cross-query /
    service-role variant.
  - Regression fixtures: `authz-104` (the vulnerable badge pattern — caught + kept
    end-to-end) and `safe-009` (the same query correctly scoped to the session user
    — stays clean).

  - Optional **multi-pass ensemble** (`VASPERA_AGENT_PASSES`, default 1, bounded 1–3):
    runs the analysis agent N times and unions + dedupes the findings before
    verifying. Single-issue LLM recall is probabilistic on messy multi-issue files;
    an ensemble raises the clean-catch rate on the hard logic / access-control
    classes (on the audited real file, ~1/4 per single pass → ~1/2+ at 3 passes).
    Opt-in and bounded so cost stays predictable — enable it on a higher analysis
    tier; default behaviour and cost are unchanged.

  Note: on the clean fixture the cross-tenant pattern is detected deterministically;
  on a real multi-issue file the clean surfacing is LLM-probabilistic per pass — the
  ensemble above is the lever that makes it consistent, at N× the agent's LLM cost.

## 2.18.0

### Minor Changes

- [#93](https://github.com/RCOLKITT/hardening-mcp/pull/93) [`ab95ea1`](https://github.com/RCOLKITT/hardening-mcp/commit/ab95ea16145b232e3799bf33b147814b40f5c79f) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Substantially improve the LLM analysis agents' recall (logic-flaw detector,
  zero-day hunter, exploit-chain), measured against an external code-review
  benchmark:

  - **Ungate the LLM pass.** The logic-flaw detector only sent files to the LLM if
    the _heuristics had already flagged them_ — starving the LLM of exactly the
    "clean-looking" files where subtle bugs hide. The per-run **cap** already
    bounds cost, so the heuristic flag now only _orders_ candidates (flagged
    first), never gates them out. On a 6-file benchmark this took the detector
    from 3 findings (catching 0 of a reviewer's issues) to 16, now catching the
    marquee funnel/identity bug it previously never even looked at.
  - **Retire the deprecated model.** All three analysis agents moved off
    `claude-sonnet-4-20250514` (EOL 2026-06) to a shared, env-overridable
    `DEFAULT_ANALYSIS_MODEL` (`VASPERA_ANALYSIS_MODEL`, default `claude-sonnet-4-6`)
    so the model can be advanced without a code change.

- [#98](https://github.com/RCOLKITT/hardening-mcp/pull/98) [`a598372`](https://github.com/RCOLKITT/hardening-mcp/commit/a59837222e3ba78b9e1fec9620eab585f8e35b07) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Add a **per-finding refutation verifier** to the LLM analysis agents (logic-flaw,
  zero-day) — **on by default**. After the agents surface findings (they favour
  recall and over-report), a second adversarial pass reviews each finding in full
  file context with the opposite bias: it assumes every finding is a false positive
  and keeps it only if it can confirm a concrete vulnerability by the rules for that
  finding's _class_ — injection (attacker-influenceable source → sink → no guard),
  IDOR / RLS (a data access with no ownership/tenant filter), **missing or
  client-side-only authentication on a sensitive endpoint**, unsafe deserialization /
  XXE, or hardcoded secret / weak crypto — above a confirm-confidence floor
  (`VASPERA_VERIFY_CONFIRM_FLOOR`, default 70). It never touches
  deterministic/heuristic findings, batches by file, reuses the bounded candidate LLM
  pass, and no-ops without an API key (so the free deterministic path is unaffected).

  Measured on the labeled fixture corpus (now including false-positive-bait safe
  controls and access-control regression fixtures), this moves the LLM agents from
  **P43 / R87** to **P93 / R77** (F1 58 → 84): a ~50-point precision gain for a
  ~10-point recall cost. Against a real AI-SAST peer (Corgea) on the same corpus, the
  verified agents **beat it on all three metrics** — precision (92.9% vs 85.7%),
  recall (76.5% vs 58.1%), and F1 (83.9 vs 69.2) — and Vaspera runs locally without
  uploading code. The class rules were hardened against three real production apps,
  where the verifier concentrated the raw agent's noisy output (~12% precision on
  real code) onto genuine access-control / IDOR / missing-auth bugs.

  It roughly doubles the agents' LLM calls, so opt out per run with
  `VASPERA_VERIFY_FINDINGS=0` if you want raw, higher-recall output.

- [#86](https://github.com/RCOLKITT/hardening-mcp/pull/86) [`2b5a516`](https://github.com/RCOLKITT/hardening-mcp/commit/2b5a516ea52ec4dbf2414dfc2217d50f96470dc3) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - The zero-day hunter, logic-flaw detector, and exploit-chain analyzer now perform
  real LLM analysis (Claude), not heuristics alone — making the "AI" in these
  agents literally true.

  A cheap heuristic pass runs first and flags candidates; the LLM then analyses
  **only those candidates** (candidate-bounded, via a shared bounded pass), so cost
  scales with signal, not repo size — a hard file cap and a single consolidated
  call per candidate keep it cost-safe. Zero-day hunter and logic-flaw detector
  reason over the flagged files; exploit-chain reasons over the full finding set to
  surface attack paths the rules miss.

  When no `ANTHROPIC_API_KEY` is configured, each agent degrades to pure heuristics
  and labels the result `modelUsed: "pattern-only"` — the "AI" claim is only made
  when an LLM actually ran. On the CLI this uses the caller's own Anthropic key
  (BYO); hosted runs use the platform key.

- [#85](https://github.com/RCOLKITT/hardening-mcp/pull/85) [`febfd61`](https://github.com/RCOLKITT/hardening-mcp/commit/febfd6184860fd98df1a444f09d2d6b029f94e05) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Real cryptographic Sigstore verification (`verifySignedArtifact`).

  Verification previously did structural checks only — it confirmed the digest
  matched and a transparency-log entry was _present_, but did not verify the
  signature itself. It now runs the bundle through the `sigstore` verifier against
  the public-good trust root, which checks that:

  - the DSSE signature is valid over the signed payload,
  - the Fulcio certificate chains to the Sigstore root,
  - the Rekor transparency-log **inclusion proof** is valid, and
  - the certificate was valid at signing time.

  It additionally binds the bundle to the artifact (digest + signed-payload match)
  so a valid bundle can't be paired with different content, and returns the Rekor
  log index and the signing identity for transparency. A forged or structurally-
  shaped-but-invalid bundle that the old check would have accepted is now rejected.
  This makes the "independently verifiable — don't trust us, verify" guarantee
  actually hold. The legacy synchronous `verifySignature` is now documented as a
  structural-only pre-check.

### Patch Changes

- [#104](https://github.com/RCOLKITT/hardening-mcp/pull/104) [`1a71889`](https://github.com/RCOLKITT/hardening-mcp/commit/1a718890ec666cb5e974f5156aedffa63c7d1717) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Two low-risk precision controls for the logic-flaw agent, plus the honest
  conclusion of the precision investigation:

  - Targeted anti-false-positive prompt guidance for the specific correct patterns
    the model misreads (schema-validated input, a present ownership check, a
    clamped numeric parse, a fetch with an AbortController timeout, a rethrown
    error, a trusted env value). Modest effect (~20% FP cut on the bait corpus);
    the access-control moat categories stay at 100% recall.
  - `VASPERA_MIN_LLM_CONFIDENCE` — an opt-in confidence floor (default off) to trade
    recall for precision when desired.

  Finding: a _conservative_ LLM verifier ("is this real?") and confidence
  thresholding both fail — ~half the false positives are high-confidence
  ("confidently wrong" on safe code). What does work is the opposite bias: a
  **refutation** verifier that defaults to dropping each finding and keeps it only
  on a confirmed, class-specific exploit path (shipped separately, on by default).
  These two prompt controls remain a useful cheap first pass ahead of it.

- [#94](https://github.com/RCOLKITT/hardening-mcp/pull/94) [`88b1abf`](https://github.com/RCOLKITT/hardening-mcp/commit/88b1abf7446c448c357de50ddf4b25682c12a24c) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Improve logic-flaw detector precision (P2, after the recall fix):

  - **Framework- and trust-boundary-aware prompt.** The LLM now distinguishes
    attacker-controlled input from trusted config/env, accounts for guards present
    elsewhere in the file, and is told to prefer a few high-signal findings — which
    removed a class of false positives (e.g. flagging an env-configured email
    recipient as "unvalidated input") while surfacing real, framework-specific bugs
    (serverless fire-and-forget, effects running before auth resolves, error paths
    that resume in a bad state).
  - **Heuristic findings no longer add noise on LLM-analysed files.** When the LLM
    actually analysed a file, its contextual reasoning supersedes the blunt regex
    heuristics: low-confidence pattern findings on that file are dropped (they
    duplicated or contradicted the LLM — e.g. "timer not cleared" when the timer is
    cleared elsewhere). Heuristics still stand alone on files the LLM didn't reach.

- [#102](https://github.com/RCOLKITT/hardening-mcp/pull/102) [`98583aa`](https://github.com/RCOLKITT/hardening-mcp/commit/98583aa32e3f17f1438de08ca06c19dc64f2f36b) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Spend the LLM analysis cap on the files that matter on large repos. The
  logic-flaw detector capped the LLM at ~15 files but ordered the non-flagged
  candidates arbitrarily, so on a big repo (e.g. a 172-route app) the budget could
  land on incidental files. Extract the zero-day hunter's `isSecurityRelevant`
  heuristic into a shared `src/agents/security-relevance.ts` and rank the
  detector's candidates by it (routes / auth / data-access / admin first). No
  effect on small or focused runs (everything fits under the cap).

- [#91](https://github.com/RCOLKITT/hardening-mcp/pull/91) [`fe3f38c`](https://github.com/RCOLKITT/hardening-mcp/commit/fe3f38c3be6e43c6cc97b9bc299c75c53c046c6d) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Harden the monitoring/telemetry code surfaced by an external review, and bump
  `sigstore` past the `certificateOIDs` verification-bypass advisory
  (GHSA-52v5-jr5w-gjxr, sigstore <=4.1.0):

  - Sentry: uncaughtException / unhandledRejection now capture **then flush + exit
    non-zero** (report-then-crash) instead of resuming in an undefined state.
  - `trackCliFirstRun` self-enforces its "never blocks startup" contract with an
    internal try/catch, so a flush rejection can't surface as an unhandled
    rejection at boot.
  - Upgrade `sigstore` to v5 (P0 signing/verify code verified compatible).

- [#103](https://github.com/RCOLKITT/hardening-mcp/pull/103) [`a5e2523`](https://github.com/RCOLKITT/hardening-mcp/commit/a5e25238ebf50269bc3c488d026311ff5f9efe79) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Add a false-positive-bait fixture set (`safeControlFixtures`, 6 correct-but-
  tempting files modelled on real agent false positives) so the benchmark can
  score PRECISION, which the vulnerable fixtures alone couldn't. Also adds an
  `--only <prefix>` filter to the competitive benchmark for targeted measurement.

  Finding recorded from these fixtures: the agent produced 13 false positives on
  the 6 safe files, and the (opt-in) verification pass refuted **0** of them —
  same result with a stronger cross-model verifier (Opus reviewing Sonnet). LLMs
  hedge to "questioned" rather than confidently refuting plausible-looking safe
  code, so an LLM verifier can't remove the false positives it generates. The
  verifier stays opt-in and is documented as ineffective; the real precision lever
  is deterministic FP-filtering / confidence thresholding, not an LLM verifier.

- [#96](https://github.com/RCOLKITT/hardening-mcp/pull/96) [`0412d19`](https://github.com/RCOLKITT/hardening-mcp/commit/0412d194b75b605f2739bee5544d879365d393ff) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Retire the deprecated `claude-sonnet-4-20250514` / `claude-opus-4-20250514`
  models (EOL 2026-06-15) across the remaining subsystems — the central config
  default (`src/config/flags.ts`) and the antagonist/adversary agents — moving to
  `claude-sonnet-4-6` (Pro) and `claude-opus-4-8` (Enterprise). Pricing-map rates
  are unchanged (same tiers). The repo now has no references to the deprecated
  model ids.

- [#99](https://github.com/RCOLKITT/hardening-mcp/pull/99) [`035e4e3`](https://github.com/RCOLKITT/hardening-mcp/commit/035e4e31eb2bc93f5863ff9f9d3c6a70c02467fe) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Cut gitleaks false-positive noise in the secrets scanner. gitleaks is
  high-recall but noisy — on a real app it reported 140 findings where Snyk Code
  found ~33, dominated by the _same_ secret repeated across files. Add a
  conservative `filterGitleaksResults()` post-parse: dedupe by secret value, drop
  low-entropy matches from entropy-scored rules (format rules like AWS keys are
  kept), and skip test/fixture/example/mock/vendor paths. On that app: **140 → 34**
  (94 duplicates, 10 non-production paths, 2 low-entropy) with no real secret lost.

## 2.17.1

### Patch Changes

- [#88](https://github.com/RCOLKITT/hardening-mcp/pull/88) [`e5baf49`](https://github.com/RCOLKITT/hardening-mcp/commit/e5baf49841d5a4abf1d7506feb39aee11fd8fb62) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Add an anonymous, opt-out `cli_first_run` telemetry event so fresh installs are
  visible even when they never complete a run — closing the distributed-adoption
  blind spot. Fires at most once per install (guarded by the existing
  `~/.vaspera/install-id` marker), honors all existing opt-out signals
  (`DO_NOT_TRACK`, `VASPERA_TELEMETRY_DISABLED`), and is fire-and-forget so it
  never blocks startup.

## 2.17.0

### Minor Changes

- [#83](https://github.com/RCOLKITT/hardening-mcp/pull/83) [`c5a3974`](https://github.com/RCOLKITT/hardening-mcp/commit/c5a3974242adca3cb575eab985616ff0cdb865d1) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Add the **CCPA / CPRA** compliance framework.

  Findings now map to California Consumer Privacy Act / Privacy Rights Act
  controls — data security (§1798.150), breach notification, the rights to
  delete / correct / know / opt-out, sensitive personal information handling,
  the privacy-notice requirement, and the CPRA risk-assessment obligation.
  Available through `compliance_report` / `compliance_multi_report` and included
  in the Pro and Enterprise framework sets alongside GDPR.

- [#73](https://github.com/RCOLKITT/hardening-mcp/pull/73) [`339197e`](https://github.com/RCOLKITT/hardening-mcp/commit/339197e49f37ce71c959434fe6dd1ee08f665a67) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Enable the Vaspera detection engine and logic scanner by default for JS/TS, and add framework-aware Semgrep rulesets.

  **Behavior change.** Scans of JavaScript/TypeScript projects now run, by default:

  - the proprietary **data/control-flow detection engine** (including the composed
    cross-tenant IDOR / RLS-bypass rule that catches Broken Access Control, OWASP
    A01 — the class deterministic SAST structurally misses), and
  - the **endpoint/auth-flow logic scanner** (IDOR/BOLA/BFLA, missing ownership
    checks).

  These analyzers were previously dark. The detection engine's taint propagation
  was also fixed (it had been inert), so all of its data-flow rules now actually
  fire. Eval on the labeled fixture set shows precision ~0.95 with detection on
  (recall improved; detection-only introduces no false positives across the set).

  When a Supabase or Next.js project is detected, the `p/supabase` / `p/nextjs`
  Semgrep registry rulesets are added as a **fault-isolated** best-effort pass —
  a failure to fetch them (e.g. no `semgrep login`) never affects the primary scan.

  Because these rules run against real codebases for the first time, expect new
  findings (some critical) on projects that previously passed; a certification can
  flip to BLOCKED when a genuine A01-class hole is present. Opt out per scan with
  `forceDisable: ["detection", "logic"]`.

- [#83](https://github.com/RCOLKITT/hardening-mcp/pull/83) [`c5a3974`](https://github.com/RCOLKITT/hardening-mcp/commit/c5a3974242adca3cb575eab985616ff0cdb865d1) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Add the pre-launch security checklist, a curated free adversary-tactics
  scanner, and behavioral runtime proof.

  - **`pre_launch_checklist` MCP tool** — maps findings to the 11-item pre-launch
    checklist every AI-built app needs before shipping (cross-tenant/RLS, OWASP,
    security headers, rate limits, CAPTCHA/bot protection, client-exposed secrets,
    error disclosure, …) and renders a markdown report of what passes and what is
    still open.
  - **Curated adversary-tactics scanner** — a high-precision, deterministic
    ($0 LLM cost) tactics pass gated to the `web-app` / `api` / `auth` / `injection`
    focus areas, with noisy rules quarantined.
  - **Runtime proof** (`runtime_verify`) — launches the app and runs a two-account
    cross-tenant isolation probe plus auth failure-path tests (lockout /
    enumeration), emitting findings that can gate a certification. This is the
    behavioral proof of checklist items #2 (cross-tenant) and #3 (auth).

- [#83](https://github.com/RCOLKITT/hardening-mcp/pull/83) [`c5a3974`](https://github.com/RCOLKITT/hardening-mcp/commit/c5a3974242adca3cb575eab985616ff0cdb865d1) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Require explicit authorization before active runtime testing.

  **Behavior change.** The `runtime_launch`, `runtime_verify`, and `runtime_health`
  tools now require an `authorized: true` parameter before they will launch or
  probe a target. These tools actively exercise a running application — including
  two-account cross-tenant and auth failure-path probes — so the gate ensures the
  caller attests they own or are authorized to test the target (a Computer Fraud
  and Abuse Act safeguard). Calls without `authorized: true` are rejected and
  nothing is launched. The static runtime tools (`runtime_detect`,
  `runtime_flow_generate`, `runtime_flows_list`, `runtime_stop`) are unaffected.

### Patch Changes

- [#83](https://github.com/RCOLKITT/hardening-mcp/pull/83) [`c5a3974`](https://github.com/RCOLKITT/hardening-mcp/commit/c5a3974242adca3cb575eab985616ff0cdb865d1) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Fix `forceEnable` / `forceDisable` for the adversary-tactics scanner.

  The `runAllScannersWithAutoDetect` overrides mapped kebab-case scanner types
  to their option keys for `npm-audit`, `tsc`, and `gitleaks`, but not for
  `adversary-tactics` (whose option key is camelCase `adversaryTactics`) — so
  `forceDisable: ["adversary-tactics"]` silently did nothing. Added the mapping
  so the documented opt-out actually turns the scanner off.

- [#83](https://github.com/RCOLKITT/hardening-mcp/pull/83) [`c5a3974`](https://github.com/RCOLKITT/hardening-mcp/commit/c5a3974242adca3cb575eab985616ff0cdb865d1) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Rename product output from "Vaspera Hardening" to **"Vaspera Certify"**.

  Affects user-visible output: the SARIF `tool.name`, GitHub Action PR comments
  and headers, compliance / eval report footers, and autofix commit messages.

  **Note for SARIF / GitHub code scanning consumers:** code scanning keys alert
  deduplication and history off `tool.name`, so alerts previously reported under
  "Vaspera Hardening" will be superseded by new alerts under "Vaspera Certify".
  The npm package name (`vaspera`) and CLI binary (`vaspera-hardening`) are
  unchanged.

## 2.16.0

### Minor Changes

- [#70](https://github.com/RCOLKITT/hardening-mcp/pull/70) [`d79820c`](https://github.com/RCOLKITT/hardening-mcp/commit/d79820cee28743a0dad7457b34ed3aa2a4def33e) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Anonymous, opt-out usage telemetry

  The CLI / MCP server now reports anonymous usage metrics — no source code, no
  secrets, no file contents — so adoption can be measured and the product
  improved. It is **opt-out**: a one-time first-run notice is shown, and it can be
  disabled with `VASPERA_TELEMETRY_DISABLED=1` or the cross-tool standard
  `DO_NOT_TRACK=1`. Events carry only an anonymous install id, a hashed project
  path, version/platform, and aggregate result counts. Full disclosure in
  `TELEMETRY.md`.

  Also resolves high-severity transitive dependency advisories (undici, vite,
  hono) surfaced by self-certification.

## 2.15.0

### Minor Changes

- [#61](https://github.com/RCOLKITT/hardening-mcp/pull/61) [`1ecf11d`](https://github.com/RCOLKITT/hardening-mcp/commit/1ecf11dbc073af3430e6df17d0792e2b87ad2568) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Agent Certification, independent verification, accuracy + red-team benchmarks, and hardening.

  **Agent Certification**

  - Versioned, signable agent certificate schema (six dimensions) with deterministic content digest; `agent_certificate_generate` / `agent_certificate_verify` MCP tools.
  - ISO 42001 + NIST AI RMF compliance mappings and tamper-evident decision provenance (`decision_record`) on the hash chain.
  - EU AI Act control mapping wired into the certification path (31 controls).

  **Independent verification (don't trust us — verify)**

  - Standalone certificate verifier: `npm run verify:cert` CLI and a public, unauthenticated `POST /verify` HTTP endpoint that re-checks schema, content digest, and signature without trusting the issuer.

  **Measured accuracy + red-team**

  - Accuracy benchmark (`npm run benchmark`, `npm run benchmark:llm`) over labeled fixtures with precision/recall/F1; built-in Semgrep taint rules took deterministic recall from ~10% to ~63% (added SQLi/cmd/SSRF, then insecure-deserialization + XXE), precision 100%.
  - LLM-layer + Anthropic/OpenAI cross-model consensus benchmark.
  - Red-team resistance harness (`npm run benchmark:redteam`) — reproducible prompt-injection resistance score + tool-scope/exfil exposure; fixed a false-positive bug that flagged 100% of tools.

  **Integrity + supply chain**

  - Evidence bundles can now be Sigstore-signed and their signatures are really verified (was a presence-only stub).
  - Published manifest now exposes real per-tool input schemas (was an empty placeholder for all tools).
  - Resolved a transitive esbuild advisory.

  **Hardening (potentially breaking for three tools)**

  - `deploy_vercel_promote`, `deploy_vercel_rollback`, and `consensus_clear` are now fail-closed: they return a no-op preview unless called with `confirm: true`. Callers that previously relied on these executing immediately must now pass `confirm: true`.

## [2.14.0] - 2026-06-05

### Added

#### Antagonist Agent

- New meta-analysis agent that runs after all other agents complete
- **Synthesis mode**: Chains findings into attack narratives mapped to MITRE ATT&CK kill chain
- **Challenger mode**: Internal critic that flags false positives, coverage gaps, and inconsistencies
- Prioritized remediation recommendations based on attack surface reduction
- New `antagonist_synthesize` tool - full analysis with narratives, challenges, and prioritization
- New `antagonist_challenge` tool - manually challenge specific findings

#### Attack Narrative Features

- Builds attack graphs from findings and exploit chains
- Maps vulnerabilities to 14 MITRE ATT&CK kill chain phases
- Identifies bottleneck findings that block multiple attack paths
- Generates human-readable attack stories with difficulty/likelihood ratings

#### Challenger Features

- Detects potential false positives (test files, low confidence, generic descriptions)
- Identifies untested attack vectors (17 categories tracked)
- Flags agents with zero findings as potentially incomplete
- Calculates coverage score across attack surface

### Fixed

- Empty catch blocks in `store.ts` and `signing.ts` now log errors
- Antagonist agent integration test types corrected

### Changed

- MCP tools increased from 108 to 110
- New agent type `antagonist` with weight 0.15 (informs but doesn't dominate consensus)
- Added to AGENT_VERIFICATION_MAP (verified by security, adversary, redteam)

## [2.13.0] - 2026-06-04

### Added

#### False Positive Feedback System

- New `feedback_submit` tool to mark findings as true/false positives
- New `feedback_report` tool to view FP rates by scanner and rule
- New `feedback_suppressions` tool to get rule suppression suggestions based on feedback
- Feedback stored in `.vaspera/fp-feedback.json` with full audit trail

#### Diff-Aware CI Scanning

- New `certification_scan_diff` tool scans only changed files (git diff)
- Estimates scan time savings vs full scan
- Auto-detects security-critical files that always get scanned

#### Standalone Autofix Preview

- `autofix_preview` now works without certification_id
- Provide file + pattern_id to preview fixes directly
- Use `autofix_list_patterns` to see available fix patterns

### Fixed

#### Persistence DB Fallback

- Added JSON file fallback when SQLite is unavailable
- New `src/persistence/json-fallback.ts` with atomic writes
- Graceful degradation: warns but continues operating

#### scale_bottlenecks False Positives

- Added semantic analysis for workflow/pipeline patterns
- Confidence scoring (60-100) based on context
- Sequential workflows no longer flagged as N+1 queries

#### ai_code_verify Diagnostics

- Returns detailed diagnostics when 0 files found
- Shows which extensions were searched
- Reports which exclude patterns matched
- Suggests alternative file extensions

#### Scanner Error Messages

- Added `ScannerErrorDetails` with actionable suggestions
- tsc/eslint now report phase (init/scan/parse) and fix steps
- Full error output available for debugging

### Changed

- MCP tools increased from 103 to 108

## 2.10.0

### Minor Changes

- [#37](https://github.com/RCOLKITT/hardening-mcp/pull/37) [`f9b8a59`](https://github.com/RCOLKITT/hardening-mcp/commit/f9b8a59f7af6470f90a16c96aa9c6e5e845e2476) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - ## Property-Based Testing

  - Added `fast-check` dependency for scanner robustness testing
  - 52 new property tests for `extractPathParams`, `inferResourceType`, `analyzeFilePath`

  ## Expanded Eval Fixtures

  - 9 new fixtures across 5 categories (22 total, up from 13)
  - command-injection (CWE-78), ssrf (CWE-918), xxe (CWE-611), insecure-deserialization (CWE-502), rls-bypass (CWE-639)

  ## Constitution for Autofix Governance

  - Risk tolerance levels: conservative | moderate | aggressive
  - Pattern-specific approvals with conditions
  - Directory restrictions (neverAutofix, requireReview)
  - Safety constraints (dryRunDefault, maxFilesPerRun, runTestsAfterFix)
  - 33 new tests for constitution validation

## [2.10.0] - 2026-05-26

### Added

#### Property-Based Testing

- Added `fast-check` dependency for property-based tests
- New `src/__tests__/property-test-helpers.ts` with shared generators
- PBT for `extractPathParams()` - tests all 4 framework styles (Express, Next.js, Flask, Spring)
- PBT for `inferResourceType()` - tests singularization invariants
- PBT for `analyzeFilePath()` - tests file classification rules
- 52 new property tests ensuring scanner robustness

#### Expanded Eval Fixtures

- 9 new test fixtures across 5 vulnerability categories (22 total, up from 13)
- `command-injection` (2 fixtures): CWE-78 - exec/spawn with user input
- `ssrf` (2 fixtures): CWE-918 - fetch/axios with user-controlled URLs
- `xxe` (1 fixture): CWE-611 - XML parser without entity restrictions
- `insecure-deserialization` (2 fixtures): CWE-502 - eval/yaml.load vulnerabilities
- `rls-bypass` (2 fixtures): CWE-639 - missing ownership filters, service role bypass

#### Constitution for Autofix Governance

- Added `yaml` dependency for constitution file parsing
- New `src/autofix/constitution.schema.ts` with Zod validation
- New `src/autofix/constitution.ts` loader with evaluation logic
- Constitution integration with PR generator
- 33 new tests for constitution validation and enforcement
- Example constitution file in `examples/constitution.yaml`

**Constitution Features:**

- Risk tolerance levels: `conservative` | `moderate` | `aggressive`
- Pattern-specific approvals with conditions (path, lines changed, severity)
- Directory restrictions: `neverAutofix`, `requireReview`
- Safety constraints: `dryRunDefault`, `maxFilesPerRun`, `runTestsAfterFix`
- PR rules: required labels, commit prefix, max PRs per run

### Changed

- Test count increased from 2772 to 2942 (170 new tests)
- MCP tools increased from 68 to 78

---

## 2.9.2

### Patch Changes

- [#30](https://github.com/RCOLKITT/hardening-mcp/pull/30) [`8110af7`](https://github.com/RCOLKITT/hardening-mcp/commit/8110af76da720332e43f296b7357987e7edec533) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - ## Telemetry Integration

  - Wired up telemetry tracking to certification tools (`certification_scan`, `agent_cert_scan`, `certification_finalize`)
  - Added scan registry for persistent analytics storage
  - Telemetry is opt-in via `VASPERA_TELEMETRY_ENABLED` environment variable
  - Privacy-respecting: repo URL, org name, and email require explicit opt-in
  - Backend API endpoint for receiving telemetry events with rate limiting

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.9.0] - 2026-05-01

### Added

#### Optimization Plan Modules

##### Corpus Expansion (P0)

- 7 new payload categories bringing total from 220 to 430+ payloads
- `multi-turn.json` - 30 payloads for context-building attacks across turns
- `context-manipulation.json` - 30 payloads for conversation history attacks
- `output-redirection.json` - 30 payloads for forcing specific outputs
- `token-smuggling.json` - 30 payloads exploiting tokenization boundaries
- `mcp-attacks.json` - 30 payloads for MCP protocol-specific vectors
- `tool-chaining.json` - 30 payloads for tool composition exploits
- `privilege-escalation.json` - 30 payloads for read→write escalation
- Updated corpus sizes: quick=100, standard=400, thorough=800, exhaustive=1500

##### Usage Telemetry (P0)

- `src/telemetry/usage.ts` - Event tracking with privacy controls
- `src/telemetry/registry.ts` - Persistent scan registry for analytics
- Opt-in telemetry for repo URL, org name, user email
- Analytics methods for dashboard and case study candidates

##### Badge Service (P0)

- `src/badge-service/index.ts` - HTTP handlers for badge serving
- Badge verification endpoint with Sigstore bundle support
- `generateBadgeEmbedCode()` for markdown/HTML embedding
- CertificationStorage interface with memory implementation

##### Frontier Model Interface (P1)

- `src/frontier/types.ts` - Interfaces for Mythos/GPT-5.5-Cyber integration
- `src/frontier/orchestrator.ts` - Multi-model orchestration with consensus
- `src/frontier/providers/stub.ts` - Test provider placeholder
- FrontierModelProvider interface with capabilities, cost estimation
- ExploitChain and ConsensusResult types

##### Data Flow Analysis (P1)

- `src/analysis/data-flow.ts` - Source→sink tracking for JS/TS/Python
- Pattern-based detection of user input sources (req.body, event.body, etc.)
- Dangerous sink detection (SQL, command exec, eval, file write)
- Risky flow identification (untrusted source → sensitive sink without sanitizer)
- LLM context formatting for focused analysis

##### Agent Chain Analysis (P2)

- `src/scanners/agent/agent-chain-analysis.ts` - Multi-hop attack paths
- Trust boundary modeling between agents and MCP servers
- AgentGraph construction from MCP server configs
- Attack path detection with severity calculation
- Mermaid diagram generation for visualization

### Changed

- Extended PayloadCategory type with 7 new categories
- Updated FuzzerOptions corpus type to include "exhaustive"
- Increased test count from 2,332 to 2,484 across 104 test files

## [2.8.0] - 2026-04-29

### Added

#### Agent Batch Submit Tool

- New `agent_batch_submit` tool for submitting findings from subagent JSON output
- Solves MCP permission issues when certification agents run as subagents
- Accepts array of findings and optional summary in one call
- Updated certification command docs to recommend batch submit

### Fixed

#### CI/CD Improvements

- Lazy Stripe initialization to allow builds without `STRIPE_SECRET_KEY`
- Fixed TypeScript test timeout for CI environments
- Synced package-lock.json for CI compatibility

## [2.7.0] - 2026-04-26

### Added

#### Plan Enforcement

- New plan-limits system for free/pro/enterprise tiers
- Certification monthly limits enforced at API level
- Agent count limits based on subscription plan
- Compliance framework access gating (SOC2 free, HIPAA/NIST pro+)
- 403 responses with `PLAN_LIMIT_EXCEEDED` code and upgrade prompts

#### Plan Limits

| Limit                | Free | Pro               | Enterprise |
| -------------------- | ---- | ----------------- | ---------- |
| Certifications/month | 3    | 50                | Unlimited  |
| Projects             | 2    | 20                | Unlimited  |
| Agents               | 3    | 7                 | All        |
| Frameworks           | SOC2 | SOC2, HIPAA, NIST | All        |
| Red team             | ❌   | ❌                | ✓          |

## [2.6.0] - 2026-04-26

### Added

#### Test Coverage

- 147 new tests across 5 test files
- `agent-integrity.test.ts` - Consensus analysis and outlier detection
- `agent-privacy.test.ts` - PII detection with Luhn validation
- `otel.test.ts` - OpenTelemetry metrics and tracing
- `loader.test.ts` - Plugin registry and sandboxed execution
- `flags.test.ts` - Feature flags and config loading

#### Feature Flags System

- New `.vaspera/config.yaml` configuration format
- Per-agent weights and model selection
- Per-scanner timeouts and custom rules
- Feature toggles for multiModel, costTracking, autofix, etc.

#### Plugin System

- Scanner plugin architecture with manifest schema
- Local plugins from `.vaspera/plugins/`
- npm plugins from `vaspera-scanner-*` packages
- Sandboxed execution in child processes

## [2.5.0] - 2026-04-24

### Added

#### Mythos-Class Security Scanners

- New `binary-analysis` scanner for native module security
  - Detects Node.js native addons, shared libraries, Rust FFI, Go CGO
  - Checks RELRO, NX, PIE, CANARY protections via checksec
  - Scans for dangerous imports and hardcoded paths
- New `memory-safety` scanner for memory corruption vulnerabilities
  - Integrates with cppcheck for C/C++ analysis
  - Detects buffer overflows (CWE-120, CWE-787)
  - Detects use-after-free (CWE-416) and double-free (CWE-415)
  - Pattern-based detection for dangerous C functions (strcpy, sprintf, gets)
  - Rust unsafe code detection via cargo-geiger
- New `race-condition` scanner for concurrency bugs
  - Go: goroutine data race detection via go vet
  - Node.js: async/await shared state patterns
  - Python: threading and multiprocessing issues
  - Java: check-then-act and synchronized patterns

#### Semantic AI Agents

- New `zero-day-hunter` agent for novel vulnerability discovery
  - AI-powered semantic code analysis beyond pattern matching
  - Discovers logic flaws, auth bypasses, cryptographic weaknesses
  - Confidence scoring with evidence extraction
  - CWE mapping for compliance alignment
- New `logic-flaw-detector` agent for business logic bugs
  - Detects state inconsistencies and race conditions
  - Identifies boundary condition issues and error handling gaps
  - Analyzes trust boundaries and client-side data usage
- New `exploit-chain` analyzer for attack path mapping
  - Automatically chains multiple vulnerabilities into attack paths
  - Maps SSRF → internal API, XSS → session hijacking paths
  - MITRE ATT&CK technique mapping for each chain
  - Severity escalation calculation (medium + medium = critical)

#### New MCP Tools

- `certification_scan_binary` - Scan compiled code and native modules
- `certification_analyze_chains` - Analyze findings for exploitable chains
- `certification_semantic_analysis` - Run AI-powered semantic analysis

#### Compliance Enhancements

- Added MITRE ATT&CK technique mapping for AI/ML systems
- New CWE mappings for memory safety vulnerabilities
- New CWE mappings for race condition vulnerabilities
- OWASP LLM Top 10 integration

### Changed

- Updated scanner count from 9 to 13+ scanners
- Updated agent count from 4 to 7+ agents
- Updated frontend marketing pages with Mythos-class capabilities
- Demo page now reflects new scanner and agent counts

## [2.0.0] - 2024-01-15

### Added

#### Cost Tracking

- New `cost_track` tool to start tracking costs for a certification
- New `cost_estimate` tool to estimate costs before running
- New `cost_status` tool to get current cost status
- New `cost_report` tool to generate detailed cost reports
- New `cost_budget` tool to set/update budget limits
- New `cost_models` tool to list supported models and pricing
- Support for 13 LLM models: Claude (4), GPT (5), Gemini (3), O1 (3)
- Budget limits with automatic warnings and abort capability

#### Multi-Model Consensus

- New `multimodel_record` tool to record findings from model runs
- New `multimodel_consensus` tool to calculate inter-model agreement
- New `multimodel_disagreements` tool to identify model disagreements
- New `multimodel_merged` tool to get deduplicated findings
- New `multimodel_summary` tool to generate multi-model summaries
- New `multimodel_models` tool to list/configure available models
- New `multimodel_clear` tool to clear results
- Fleiss' kappa calculation for inter-rater reliability
- Finding similarity matching across models
- Disagreement detection by type (existence, severity, location, description)

#### Compliance Mapping

- New `compliance_report` tool for single-framework reports
- New `compliance_multi_report` tool for multi-framework reports
- New `compliance_controls` tool to list framework controls
- SOC 2 Type II mapping (17 controls)
- ISO 27001 Annex A mapping (14 categories)
- Control status assessment (Compliant/At-Risk/Non-Compliant)
- Finding-to-control mapping by category

#### SBOM & Provenance

- New `sbom_generate` tool for CycloneDX SBOM generation
- New `sbom_provenance` tool for SLSA provenance attestation
- New `sbom_sign` tool for Sigstore signing
- New `sbom_verify_provenance` tool for provenance verification
- Dependency inventory generation
- Build attestation with SLSA Level 2 support

#### Documentation

- New `docs/` folder with feature documentation
- Cost tracking guide (`docs/cost-tracking.md`)
- Multi-model consensus guide (`docs/multi-model.md`)
- Compliance mapping guide (`docs/compliance.md`)
- Complete MCP tools reference (`docs/mcp-tools.md`)
- Example workflows (`docs/examples/`)

### Changed

- Updated MCP tool count from 36 to 52
- Updated package description to highlight enterprise features
- README now includes v2.0.0 features section

### Fixed

- Finding type now uses `description` consistently (removed legacy `title`)
- Multi-model consensus correctly handles partial model agreement
- Cost calculation uses accurate per-model pricing

## [1.1.0] - 2024-01-01

### Added

#### Deterministic Scanners

- Semgrep integration for OWASP Top 10
- gitleaks integration for secrets detection
- npm audit integration for CVE detection
- TypeScript analysis for type safety

#### GitHub Action

- `action.yml` for CI/CD integration
- Diff-mode scanning for PRs
- PR comment formatting
- SARIF upload to GitHub Code Scanning

#### Evaluation Harness

- Test fixtures for scanner accuracy
- Precision, recall, F1 metrics
- Stability testing across runs
- Target thresholds for publication

#### Custom Rules

- `rules_load` for custom rule loading
- `rules_templates` for built-in templates
- `rules_generate_config` for config generation
- `rules_check_file` for file checking

### Changed

- Scanner findings now have confidence: 100
- LLM agents reference scanner findings by ID

## [1.0.2] - 2023-12-15

### Added

- Cross-verification system between agents
- Consensus scoring with certification levels
- SARIF export for GitHub integration

### Fixed

- Evidence validation for LLM findings
- Finding deduplication logic

## [1.0.1] - 2023-12-01

### Added

- File hash-based caching
- Agent finding submission tools
- Basic certification workflow

### Fixed

- Project discovery on macOS
- Command installation paths

## [1.0.0] - 2023-11-15

### Added

- Initial release
- 6 certification agents (security, reliability, typesafety, performance, quality, redteam)
- Hardening command installation
- Portfolio dashboard
- AUDIT.md and HARDENING-REPORT.md generation
