blitzstrike 2.4.168 → 2.4.169

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,19 @@ All notable changes to Blitz Strike are documented here.
5
5
  The format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/).
7
7
 
8
+ ## [2.4.169] — 2026-10-11
9
+
10
+ ### Added — finding retest loop (post-confirmation lifecycle)
11
+
12
+ - The finding lifecycle no longer ends at `confirmed`: added `retesting`, `fixed`,
13
+ and `still_vulnerable` states with the transitions `confirmed -> retesting ->
14
+ fixed | still_vulnerable`, and `still_vulnerable -> retesting` (re-retest after
15
+ the next patch window; `fixed` is terminal).
16
+ - New `retest_finding` tool: pass a confirmed/still_vulnerable finding + a retest
17
+ verdict (`fixed` or `still_vulnerable`) + reason; it advances the lifecycle and
18
+ records the verdict + reason as evidence. Run `strike_verify` first to obtain the
19
+ live verdict, then record it here.
20
+
8
21
  ## [2.4.168] — 2026-10-11
9
22
 
10
23
  ### Fixed — blind_sqli_extract: space extraction + drift-proof time fallback
package/dist/index.js CHANGED
@@ -33277,7 +33277,10 @@ var LIFECYCLE_TRANSITIONS = {
33277
33277
  triaged: ["hypothesis", "rejected", "out_of_scope"],
33278
33278
  hypothesis: ["validating", "false_positive", "rejected", "blocked"],
33279
33279
  validating: ["confirmed", "false_positive", "blocked", "out_of_scope"],
33280
- confirmed: [],
33280
+ confirmed: ["retesting"],
33281
+ retesting: ["fixed", "still_vulnerable", "false_positive"],
33282
+ fixed: [],
33283
+ still_vulnerable: ["retesting"],
33281
33284
  false_positive: [],
33282
33285
  rejected: [],
33283
33286
  blocked: [],
@@ -33440,6 +33443,17 @@ function rejectFinding(finding, status, reason, evidence) {
33440
33443
  timestamps: { ...updated.timestamps, updated: new Date().toISOString() }
33441
33444
  };
33442
33445
  }
33446
+ function retestFinding(finding, opts) {
33447
+ const retesting = transition(finding, "retesting");
33448
+ const ev = opts.evidence?.map((e) => makeEvidence(e)) ?? [];
33449
+ const result = transition(retesting, opts.verdict);
33450
+ return {
33451
+ ...result,
33452
+ remediation: { ...result.remediation, retest_note: opts.reason },
33453
+ evidence: [...result.evidence, ...ev],
33454
+ timestamps: { ...result.timestamps, updated: new Date().toISOString() }
33455
+ };
33456
+ }
33443
33457
 
33444
33458
  // src/sinks.ts
33445
33459
  init_secrets();
@@ -66341,7 +66355,7 @@ ${statusLine}` : statusLine },
66341
66355
  });
66342
66356
  server.registerTool("finding_transition", {
66343
66357
  title: "Advance a finding lifecycle (STATEFUL)",
66344
- description: "FINDINGS: advance a canonical Finding through its lifecycle (detected->triaged->hypothesis->validating->confirmed) and RETURN the updated finding. STATEFUL — pass the FULL finding JSON (from finding_create / run_engagement), not a status string. Rejects illegal transitions with the legal next states. Confirmed is terminal. To confirm FROM a live verdict use strike_resolve instead.",
66358
+ description: "FINDINGS: advance a canonical Finding through its lifecycle (detected->triaged->hypothesis->validating->confirmed, then the retest loop confirmed->retesting->fixed|still_vulnerable) and RETURN the updated finding. STATEFUL — pass the FULL finding JSON (from finding_create / run_engagement), not a status string. Rejects illegal transitions with the legal next states. To confirm FROM a live verdict use strike_resolve; to re-verify a confirmed finding use retest_finding.",
66345
66359
  inputSchema: {
66346
66360
  finding: string2().describe("JSON of the canonical Finding object (from finding_create / run_engagement)"),
66347
66361
  to: string2().describe("Target status (triaged/hypothesis/validating/confirmed/false_positive/rejected/blocked/out_of_scope)")
@@ -66370,6 +66384,46 @@ ${statusLine}` : statusLine },
66370
66384
  }]
66371
66385
  };
66372
66386
  });
66387
+ server.registerTool("retest_finding", {
66388
+ title: "Re-verify a confirmed finding (retest loop)",
66389
+ description: "FINDINGS: re-verify a CONFIRMED (or still_vulnerable) finding to check whether the vendor patched it. Pass the full finding JSON + the retest verdict: 'fixed' (the exploit no longer reproduces — patch applied) or 'still_vulnerable' (still exploitable). Advances confirmed -> retesting -> fixed|still_vulnerable and records the verdict + reason as evidence. still_vulnerable findings can be re-retested later. Run strike_verify FIRST to get the live verdict, then record it here.",
66390
+ inputSchema: {
66391
+ finding: string2().describe("JSON of the canonical Finding object (status confirmed or still_vulnerable)"),
66392
+ verdict: _enum(["fixed", "still_vulnerable"]).describe("Retest outcome: fixed (patch applied) or still_vulnerable (still exploitable)"),
66393
+ reason: string2().describe("Short note: what changed / what still reproduces"),
66394
+ evidence: string2().optional().describe("Optional JSON array of evidence entries [{type, description, content}]")
66395
+ }
66396
+ }, async ({ finding, verdict, reason, evidence }) => {
66397
+ let f;
66398
+ try {
66399
+ f = JSON.parse(finding);
66400
+ } catch {
66401
+ return { content: [{ type: "text", text: JSON.stringify({ error: "invalid finding JSON — pass the full Finding object" }) }] };
66402
+ }
66403
+ const from = f.status ?? "detected";
66404
+ if (!(from === "confirmed" || from === "still_vulnerable")) {
66405
+ return { content: [{ type: "text", text: JSON.stringify({ error: `retest only valid from 'confirmed' or 'still_vulnerable', not '${from}'`, legal_next: LIFECYCLE_TRANSITIONS[from] ?? [] }) }] };
66406
+ }
66407
+ let ev = [];
66408
+ if (evidence) {
66409
+ try {
66410
+ ev = JSON.parse(evidence);
66411
+ } catch {
66412
+ ev = [];
66413
+ }
66414
+ }
66415
+ const updated = retestFinding(f, { verdict, reason, evidence: ev });
66416
+ return {
66417
+ content: [{
66418
+ type: "text",
66419
+ text: JSON.stringify({
66420
+ ...updated,
66421
+ transition: `${from} -> retesting -> ${updated.status}`,
66422
+ ...updated.status === "fixed" ? { hint: "FIXED — the vendor patched it. The retest closes this finding's loop." } : { hint: "STILL_VULNERABLE — re-retest later via retest_finding after the next patch window." }
66423
+ })
66424
+ }]
66425
+ };
66426
+ });
66373
66427
  server.registerTool("capture_false_positive", {
66374
66428
  title: "Capture a verified false positive (self-hardening)",
66375
66429
  description: "SELF-HARDENING: record a VERIFIED false positive (a code pattern the detector flagged but live verification ruled out) into the writable benchmark corpus, so the next run_benchmark measures whether the detector STILL flags it. Pass the triggering CODE + language + detector + a short note. Every capture makes the detector more precise — close the loop, never just discard a refuted lead.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blitzstrike",
3
- "version": "2.4.168",
3
+ "version": "2.4.169",
4
4
  "description": "Blitz Strike — a universal MCP security-audit toolbelt. BLITZ sweeps the attack surface, EAGLE-EYE traces source-to-sink, STRIKE verifies live. 57 attack chains, 130-tool catalog, intelligence data layer. One server, every agent.",
5
5
  "type": "module",
6
6
  "bin": {