blitzstrike 2.4.168 → 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 +27 -0
- package/dist/index.js +79 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,33 @@ 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
|
+
|
|
22
|
+
## [2.4.169] — 2026-10-11
|
|
23
|
+
|
|
24
|
+
### Added — finding retest loop (post-confirmation lifecycle)
|
|
25
|
+
|
|
26
|
+
- The finding lifecycle no longer ends at `confirmed`: added `retesting`, `fixed`,
|
|
27
|
+
and `still_vulnerable` states with the transitions `confirmed -> retesting ->
|
|
28
|
+
fixed | still_vulnerable`, and `still_vulnerable -> retesting` (re-retest after
|
|
29
|
+
the next patch window; `fixed` is terminal).
|
|
30
|
+
- New `retest_finding` tool: pass a confirmed/still_vulnerable finding + a retest
|
|
31
|
+
verdict (`fixed` or `still_vulnerable`) + reason; it advances the lifecycle and
|
|
32
|
+
records the verdict + reason as evidence. Run `strike_verify` first to obtain the
|
|
33
|
+
live verdict, then record it here.
|
|
34
|
+
|
|
8
35
|
## [2.4.168] — 2026-10-11
|
|
9
36
|
|
|
10
37
|
### Fixed — blind_sqli_extract: space extraction + drift-proof time fallback
|
package/dist/index.js
CHANGED
|
@@ -33277,7 +33277,11 @@ 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", "inconclusive", "false_positive"],
|
|
33282
|
+
fixed: [],
|
|
33283
|
+
still_vulnerable: ["retesting"],
|
|
33284
|
+
inconclusive: ["retesting"],
|
|
33281
33285
|
false_positive: [],
|
|
33282
33286
|
rejected: [],
|
|
33283
33287
|
blocked: [],
|
|
@@ -33440,6 +33444,17 @@ function rejectFinding(finding, status, reason, evidence) {
|
|
|
33440
33444
|
timestamps: { ...updated.timestamps, updated: new Date().toISOString() }
|
|
33441
33445
|
};
|
|
33442
33446
|
}
|
|
33447
|
+
function retestFinding(finding, opts) {
|
|
33448
|
+
const retesting = transition(finding, "retesting");
|
|
33449
|
+
const ev = opts.evidence?.map((e) => makeEvidence(e)) ?? [];
|
|
33450
|
+
const result = transition(retesting, opts.verdict);
|
|
33451
|
+
return {
|
|
33452
|
+
...result,
|
|
33453
|
+
remediation: { ...result.remediation, retest_note: opts.reason },
|
|
33454
|
+
evidence: [...result.evidence, ...ev],
|
|
33455
|
+
timestamps: { ...result.timestamps, updated: new Date().toISOString() }
|
|
33456
|
+
};
|
|
33457
|
+
}
|
|
33443
33458
|
|
|
33444
33459
|
// src/sinks.ts
|
|
33445
33460
|
init_secrets();
|
|
@@ -63721,6 +63736,31 @@ var HUNTING_DOCTRINE = [
|
|
|
63721
63736
|
id: "per_domain_exhaustion",
|
|
63722
63737
|
title: "Depth-First Per Domain — Drive Each to Exhaustion (Dead-End)",
|
|
63723
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."
|
|
63724
63764
|
}
|
|
63725
63765
|
];
|
|
63726
63766
|
var DOMAIN_EXHAUSTION_CHECKLIST = [
|
|
@@ -66341,7 +66381,7 @@ ${statusLine}` : statusLine },
|
|
|
66341
66381
|
});
|
|
66342
66382
|
server.registerTool("finding_transition", {
|
|
66343
66383
|
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.
|
|
66384
|
+
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
66385
|
inputSchema: {
|
|
66346
66386
|
finding: string2().describe("JSON of the canonical Finding object (from finding_create / run_engagement)"),
|
|
66347
66387
|
to: string2().describe("Target status (triaged/hypothesis/validating/confirmed/false_positive/rejected/blocked/out_of_scope)")
|
|
@@ -66370,6 +66410,43 @@ ${statusLine}` : statusLine },
|
|
|
66370
66410
|
}]
|
|
66371
66411
|
};
|
|
66372
66412
|
});
|
|
66413
|
+
server.registerTool("retest_finding", {
|
|
66414
|
+
title: "Re-verify a confirmed finding (retest loop)",
|
|
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.",
|
|
66416
|
+
inputSchema: {
|
|
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"),
|
|
66420
|
+
evidence: string2().optional().describe("Optional JSON array of evidence entries [{type, description, content}]")
|
|
66421
|
+
}
|
|
66422
|
+
}, async ({ finding, verdict, reason, evidence }) => {
|
|
66423
|
+
let f;
|
|
66424
|
+
try {
|
|
66425
|
+
f = JSON.parse(finding);
|
|
66426
|
+
} catch {
|
|
66427
|
+
return { content: [{ type: "text", text: JSON.stringify({ error: "invalid finding JSON — pass the full Finding object" }) }] };
|
|
66428
|
+
}
|
|
66429
|
+
const from = f.status ?? "detected";
|
|
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] ?? [] }) }] };
|
|
66432
|
+
}
|
|
66433
|
+
let ev = [];
|
|
66434
|
+
if (evidence) {
|
|
66435
|
+
try {
|
|
66436
|
+
ev = JSON.parse(evidence);
|
|
66437
|
+
} catch {
|
|
66438
|
+
ev = [];
|
|
66439
|
+
}
|
|
66440
|
+
}
|
|
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.";
|
|
66443
|
+
return {
|
|
66444
|
+
content: [{
|
|
66445
|
+
type: "text",
|
|
66446
|
+
text: JSON.stringify({ ...updated, transition: `${from} -> retesting -> ${updated.status}`, hint })
|
|
66447
|
+
}]
|
|
66448
|
+
};
|
|
66449
|
+
});
|
|
66373
66450
|
server.registerTool("capture_false_positive", {
|
|
66374
66451
|
title: "Capture a verified false positive (self-hardening)",
|
|
66375
66452
|
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.
|
|
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": {
|