blitzstrike 2.4.169 → 2.4.170
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 +14 -0
- package/dist/index.js +35 -12
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,20 @@ 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.170] — 2026-10-11
|
|
9
|
+
|
|
10
|
+
### Added — 3-way retest verdict + planner doctrine (from ARTEX reference)
|
|
11
|
+
|
|
12
|
+
- `retest_finding` now supports a third verdict `inconclusive` (could not determine —
|
|
13
|
+
WAF blocked / target down / missing login / evidence insufficient), so one failed
|
|
14
|
+
request is never recorded as "fixed". `inconclusive -> retesting` re-opens the loop.
|
|
15
|
+
- Added 5 doctrine rules distilled from ARTEX's planner/pentest/worker discipline:
|
|
16
|
+
`never_stall` (always emit the next action — a 0-action stall is not restraint),
|
|
17
|
+
`breadth_then_focus` (2-3 mechanically-different routes in parallel, then focus),
|
|
18
|
+
`quantitative_acceptance` (verify measured coverage/findings before "done"),
|
|
19
|
+
`negative_recheck_once` (a negative observation is not a verdict — re-check once),
|
|
20
|
+
`observed_vs_inferred` (never upgrade a version/CVE/inferred hit to confirmed).
|
|
21
|
+
|
|
8
22
|
## [2.4.169] — 2026-10-11
|
|
9
23
|
|
|
10
24
|
### Added — finding retest loop (post-confirmation lifecycle)
|
package/dist/index.js
CHANGED
|
@@ -33278,9 +33278,10 @@ var LIFECYCLE_TRANSITIONS = {
|
|
|
33278
33278
|
hypothesis: ["validating", "false_positive", "rejected", "blocked"],
|
|
33279
33279
|
validating: ["confirmed", "false_positive", "blocked", "out_of_scope"],
|
|
33280
33280
|
confirmed: ["retesting"],
|
|
33281
|
-
retesting: ["fixed", "still_vulnerable", "false_positive"],
|
|
33281
|
+
retesting: ["fixed", "still_vulnerable", "inconclusive", "false_positive"],
|
|
33282
33282
|
fixed: [],
|
|
33283
33283
|
still_vulnerable: ["retesting"],
|
|
33284
|
+
inconclusive: ["retesting"],
|
|
33284
33285
|
false_positive: [],
|
|
33285
33286
|
rejected: [],
|
|
33286
33287
|
blocked: [],
|
|
@@ -63735,6 +63736,31 @@ var HUNTING_DOCTRINE = [
|
|
|
63735
63736
|
id: "per_domain_exhaustion",
|
|
63736
63737
|
title: "Depth-First Per Domain — Drive Each to Exhaustion (Dead-End)",
|
|
63737
63738
|
rule: "When scope spans many domains/hosts, treat EACH as a SEPARATE engagement and go DEPTH-FIRST: finish one domain to total exhaustion before touching the next — never spray a shallow recon across the whole scope. A domain is EXHAUSTED (a true dead-end) only when EVERY item on the exhaustion checklist passes: (a) every subdomain/host enumerated (asset_discovery), (b) every endpoint/param discovered (param_surface / action_surface / JS refs), (c) every class × eligible shape carries a terminal verdict (confirmed/dead/partial/skipped), (d) every hypothesis verified (strike_verify / OOB) or refuted (dead verdict), (e) every foothold escalated to REAL impact (records/admin/PII) or genuinely blocked, and (f) zero obligations remain pending (next_obligation returns none). Only then move to the next domain — a shallow 'found one bug' pass is NEVER a finished domain, and skipping any checklist item means the domain is NOT done."
|
|
63739
|
+
},
|
|
63740
|
+
{
|
|
63741
|
+
id: "never_stall",
|
|
63742
|
+
title: "Never Stall — Always Emit the Next Action",
|
|
63743
|
+
rule: "HARD BOTTOM LINE: whenever the goal is NOT met and there is no in-flight or queued work (zero pending obligations, zero un-verified hypotheses), you MUST produce at least ONE concrete next action toward the goal — emitting zero actions at that moment is a stall, not restraint. A '0 next steps' answer is only legitimate when (a) every identified direction is already covered by in-flight work, or (b) the next step truly depends on an upstream result that has not landed yet. Never let 'nothing left to do' be the lazy default while a goal is unmet and scope remains untested."
|
|
63744
|
+
},
|
|
63745
|
+
{
|
|
63746
|
+
id: "breadth_then_focus",
|
|
63747
|
+
title: "Breadth-First Route Diversity, Then Focus",
|
|
63748
|
+
rule: "Do NOT tunnel-vision the first promising lead. Open by laying out 2–3 MECHANICALLY-DIFFERENT routes in parallel (e.g. an upload chain vs an auth-bypass chain) and let them progress side-by-side; only concentrate effort on a route once it delivers evidence that actually approaches the goal. Early tunnel-vision onto one elegant route is the single-agent failure mode that misses the real bug. Diversity is bounded by scope/constraints: a direction excluded by scope is never opened no matter how different."
|
|
63749
|
+
},
|
|
63750
|
+
{
|
|
63751
|
+
id: "quantitative_acceptance",
|
|
63752
|
+
title: "Quantitative Acceptance Gate — No Premature 'Done'",
|
|
63753
|
+
rule: "When a goal carries a QUANTITATIVE condition (coverage ≥ X%, N flags, a specific privilege, a named asset), you MUST verify the MEASURED value (coverage %, findings count, obtained privilege) against that condition BEFORE marking it met — never declare 'done' on 'roughly achieved / core is in hand'. If the measured value falls short, keep hunting to close the gap instead of stamping the goal complete early."
|
|
63754
|
+
},
|
|
63755
|
+
{
|
|
63756
|
+
id: "negative_recheck_once",
|
|
63757
|
+
title: "A Negative Observation Is Not a Conclusion — Re-Check Once",
|
|
63758
|
+
rule: "A recorded negative ('not injectable', 'port closed', 'not vulnerable', 'filter blocked it') is an OBSERVATION, not a verdict. Before trusting it as a dead-end, inspect its evidence: if it is solid (controlled disproof, path exhausted via multiple encodings/methods/params) then respect it; if it is weak ('looked like' / 'tried once' / inferred) and the direction is in-scope with no other coverage, dispatch ONE re-check via a DIFFERENT path. Re-check the same negative direction AT MOST ONCE — after a second solid negative, record it as dead and move on; never spin on 'one more try'."
|
|
63759
|
+
},
|
|
63760
|
+
{
|
|
63761
|
+
id: "observed_vs_inferred",
|
|
63762
|
+
title: "Observed vs Inferred — Never Upgrade Inferred to Confirmed",
|
|
63763
|
+
rule: "Tag every conclusion with its confidence honestly: OBSERVED (you directly triggered it and hold the request/response or command output) vs INFERRED (you deduced it from a fingerprint/version/diff/phenomenon without actually triggering it). A version/CVE match, a 'looks injectable' param, or a patch-diff inference is INFERRED and must never be reported as a confirmed finding — record it as a hypothesis and verify it live (strike_verify / OOB / a clean oracle) before it can claim confirmed. Disproof is worth as much as proof: an honest dead verdict is a deliverable, an overstated inferred-as-confirmed is a retraction waiting to happen."
|
|
63738
63764
|
}
|
|
63739
63765
|
];
|
|
63740
63766
|
var DOMAIN_EXHAUSTION_CHECKLIST = [
|
|
@@ -66386,11 +66412,11 @@ ${statusLine}` : statusLine },
|
|
|
66386
66412
|
});
|
|
66387
66413
|
server.registerTool("retest_finding", {
|
|
66388
66414
|
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' (
|
|
66415
|
+
description: "FINDINGS: re-verify a CONFIRMED (or still_vulnerable/inconclusive) finding to check whether the vendor patched it. Pass the full finding JSON + the retest verdict: 'fixed' (exploit no longer reproduces — patch applied), 'still_vulnerable' (still exploitable), or 'inconclusive' (could NOT determine — WAF blocked / target down / missing login / evidence insufficient; one failed request proves nothing). Advances confirmed -> retesting -> fixed|still_vulnerable|inconclusive and records the verdict + reason as evidence. Run strike_verify FIRST to get the live verdict, then record it here.",
|
|
66390
66416
|
inputSchema: {
|
|
66391
|
-
finding: string2().describe("JSON of the canonical Finding object (status confirmed or
|
|
66392
|
-
verdict: _enum(["fixed", "still_vulnerable"]).describe("Retest outcome: fixed (patch applied)
|
|
66393
|
-
reason: string2().describe("Short note: what changed / what still reproduces"),
|
|
66417
|
+
finding: string2().describe("JSON of the canonical Finding object (status confirmed, still_vulnerable, or inconclusive)"),
|
|
66418
|
+
verdict: _enum(["fixed", "still_vulnerable", "inconclusive"]).describe("Retest outcome: fixed (patch applied), still_vulnerable (still exploitable), or inconclusive (could not determine)"),
|
|
66419
|
+
reason: string2().describe("Short note: what changed / what still reproduces / what blocked the check"),
|
|
66394
66420
|
evidence: string2().optional().describe("Optional JSON array of evidence entries [{type, description, content}]")
|
|
66395
66421
|
}
|
|
66396
66422
|
}, async ({ finding, verdict, reason, evidence }) => {
|
|
@@ -66401,8 +66427,8 @@ ${statusLine}` : statusLine },
|
|
|
66401
66427
|
return { content: [{ type: "text", text: JSON.stringify({ error: "invalid finding JSON — pass the full Finding object" }) }] };
|
|
66402
66428
|
}
|
|
66403
66429
|
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'
|
|
66430
|
+
if (!(from === "confirmed" || from === "still_vulnerable" || from === "inconclusive")) {
|
|
66431
|
+
return { content: [{ type: "text", text: JSON.stringify({ error: `retest only valid from 'confirmed'/'still_vulnerable'/'inconclusive', not '${from}'`, legal_next: LIFECYCLE_TRANSITIONS[from] ?? [] }) }] };
|
|
66406
66432
|
}
|
|
66407
66433
|
let ev = [];
|
|
66408
66434
|
if (evidence) {
|
|
@@ -66413,14 +66439,11 @@ ${statusLine}` : statusLine },
|
|
|
66413
66439
|
}
|
|
66414
66440
|
}
|
|
66415
66441
|
const updated = retestFinding(f, { verdict, reason, evidence: ev });
|
|
66442
|
+
const hint = updated.status === "fixed" ? "FIXED — the vendor patched it. The retest closes this finding's loop." : updated.status === "inconclusive" ? "INCONCLUSIVE — could not determine (blocker). One failed request proves nothing; re-retest via retest_finding once the blocker clears." : "STILL_VULNERABLE — re-retest later via retest_finding after the next patch window.";
|
|
66416
66443
|
return {
|
|
66417
66444
|
content: [{
|
|
66418
66445
|
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
|
-
})
|
|
66446
|
+
text: JSON.stringify({ ...updated, transition: `${from} -> retesting -> ${updated.status}`, hint })
|
|
66424
66447
|
}]
|
|
66425
66448
|
};
|
|
66426
66449
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "blitzstrike",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.170",
|
|
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": {
|