blitzstrike 2.4.174 → 2.4.176
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 +19 -0
- package/dist/index.js +81 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,25 @@ 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.176] — 2026-10-11
|
|
9
|
+
|
|
10
|
+
### Added — retest context (completes the retest loop)
|
|
11
|
+
|
|
12
|
+
- New `retest_context` tool: given a confirmed/still_vulnerable/inconclusive
|
|
13
|
+
finding, return everything needed to re-verify it — finding key fields, PoC
|
|
14
|
+
evidence grouped by role (proof/baseline/verification) + reproducible flag,
|
|
15
|
+
the active operation constraints, and the current goal state.
|
|
16
|
+
|
|
17
|
+
## [2.4.175] — 2026-10-11
|
|
18
|
+
|
|
19
|
+
### Added — evidence roles (structured proof/baseline/verification/supporting)
|
|
20
|
+
|
|
21
|
+
- Evidence records now carry a `role` (proof = trigger request/response, baseline =
|
|
22
|
+
normal request, verification = negative control/marker, supporting = anything else).
|
|
23
|
+
- `finding_attach_evidence` accepts a `role`; new `finding_evidence_roles` tool
|
|
24
|
+
returns the role breakdown + a `reproducible` flag (true only when a finding has
|
|
25
|
+
proof + baseline + verification — the three roles a HackerOne-grade PoC needs).
|
|
26
|
+
|
|
8
27
|
## [2.4.174] — 2026-10-11
|
|
9
28
|
|
|
10
29
|
### Added — observation ledger + lineage (third write-back channel)
|
package/dist/index.js
CHANGED
|
@@ -33211,6 +33211,7 @@ function makeEvidence(input) {
|
|
|
33211
33211
|
return {
|
|
33212
33212
|
evidence_id: nextEvidenceId(),
|
|
33213
33213
|
type: input.type,
|
|
33214
|
+
role: input.role ?? "supporting",
|
|
33214
33215
|
description: redactSecrets(input.description),
|
|
33215
33216
|
source: input.source ? redactObject(input.source) : undefined,
|
|
33216
33217
|
sink: input.sink ? redactObject(input.sink) : undefined,
|
|
@@ -33236,6 +33237,18 @@ function verifyEvidence(evidence) {
|
|
|
33236
33237
|
}
|
|
33237
33238
|
return { ok: failed.length === 0, failed };
|
|
33238
33239
|
}
|
|
33240
|
+
function evidenceRoles(evidence) {
|
|
33241
|
+
const roles = { proof: 0, baseline: 0, verification: 0, supporting: 0 };
|
|
33242
|
+
for (const e of evidence)
|
|
33243
|
+
roles[e.role] = (roles[e.role] ?? 0) + 1;
|
|
33244
|
+
return {
|
|
33245
|
+
roles,
|
|
33246
|
+
proof: roles.proof > 0,
|
|
33247
|
+
baseline: roles.baseline > 0,
|
|
33248
|
+
verification: roles.verification > 0,
|
|
33249
|
+
reproducible: roles.proof > 0 && roles.baseline > 0 && roles.verification > 0
|
|
33250
|
+
};
|
|
33251
|
+
}
|
|
33239
33252
|
|
|
33240
33253
|
// src/invariants.ts
|
|
33241
33254
|
function checkFindingInvariants(finding) {
|
|
@@ -66758,23 +66771,87 @@ ${statusLine}` : statusLine },
|
|
|
66758
66771
|
});
|
|
66759
66772
|
server.registerTool("finding_attach_evidence", {
|
|
66760
66773
|
title: "Attach evidence to a finding",
|
|
66761
|
-
description: "FINDINGS: attach a redacted, SHA-256-tagged evidence record to an existing canonical finding (without advancing its lifecycle).",
|
|
66774
|
+
description: "FINDINGS: attach a redacted, SHA-256-tagged evidence record to an existing canonical finding (without advancing its lifecycle). Pass role (proof = the request/response that triggered it; baseline = the normal request showing the differential; verification = the negative control/marker; supporting = anything else) so the finding's evidence stays structured. A reproducible PoC needs proof + baseline + verification.",
|
|
66762
66775
|
inputSchema: {
|
|
66763
66776
|
finding: string2().describe("JSON of the Finding object"),
|
|
66764
66777
|
type: string2().describe("Evidence type (source_location/response/validation_result/negative_control/...)"),
|
|
66765
66778
|
description: string2().describe("Evidence description"),
|
|
66779
|
+
role: _enum(["proof", "baseline", "verification", "supporting"]).optional().describe("Evidence role (default supporting)"),
|
|
66766
66780
|
content: string2().optional().describe("Evidence artifact content")
|
|
66767
66781
|
}
|
|
66768
|
-
}, async ({ finding, type, description, content }) => {
|
|
66782
|
+
}, async ({ finding, type, description, role, content }) => {
|
|
66769
66783
|
let f;
|
|
66770
66784
|
try {
|
|
66771
66785
|
f = JSON.parse(finding);
|
|
66772
66786
|
} catch {
|
|
66773
66787
|
return { content: [{ type: "text", text: JSON.stringify({ error: "invalid finding JSON" }) }] };
|
|
66774
66788
|
}
|
|
66775
|
-
const ev = makeEvidence({ type, description, artifacts: content ? [{ name: "artifact", kind: "evidence", content }] : [] });
|
|
66789
|
+
const ev = makeEvidence({ type, role, description, artifacts: content ? [{ name: "artifact", kind: "evidence", content }] : [] });
|
|
66776
66790
|
const updated = attachEvidence(f, ev);
|
|
66777
|
-
return { content: [{ type: "text", text: JSON.stringify(updated) }] };
|
|
66791
|
+
return { content: [{ type: "text", text: JSON.stringify({ ...updated, roles: evidenceRoles(updated.evidence) }) }] };
|
|
66792
|
+
});
|
|
66793
|
+
server.registerTool("finding_evidence_roles", {
|
|
66794
|
+
title: "Summarize a finding's evidence by role",
|
|
66795
|
+
description: "FINDINGS: given a finding, return its evidence broken down by role (proof/baseline/verification/supporting) + a `reproducible` flag (true only when it has proof + baseline + verification). Check this before submitting a report: a finding that is not `reproducible` is missing the trigger/differential/negative-control evidence a HackerOne-grade PoC needs.",
|
|
66796
|
+
inputSchema: {
|
|
66797
|
+
finding: string2().describe("JSON of the Finding object")
|
|
66798
|
+
}
|
|
66799
|
+
}, async ({ finding }) => {
|
|
66800
|
+
let f;
|
|
66801
|
+
try {
|
|
66802
|
+
f = JSON.parse(finding);
|
|
66803
|
+
} catch {
|
|
66804
|
+
return { content: [{ type: "text", text: JSON.stringify({ error: "invalid finding JSON" }) }] };
|
|
66805
|
+
}
|
|
66806
|
+
const roles = evidenceRoles(f.evidence ?? []);
|
|
66807
|
+
const missing = [
|
|
66808
|
+
!roles.proof ? "proof (trigger request/response)" : null,
|
|
66809
|
+
!roles.baseline ? "baseline (normal request)" : null,
|
|
66810
|
+
!roles.verification ? "verification (negative control/marker)" : null
|
|
66811
|
+
].filter(Boolean);
|
|
66812
|
+
return { content: [{ type: "text", text: JSON.stringify({ ...roles, missing: missing.length ? missing : undefined, hint: roles.reproducible ? "reproducible — evidence complete" : "NOT reproducible — attach the missing roles via finding_attach_evidence" }) }] };
|
|
66813
|
+
});
|
|
66814
|
+
server.registerTool("retest_context", {
|
|
66815
|
+
title: "Build the retest context for a confirmed finding",
|
|
66816
|
+
description: "RETEST: given a CONFIRMED (or still_vulnerable/inconclusive) finding, return everything needed to re-verify it in one shot: the finding's key fields (target/method/param/severity), its PoC evidence grouped by role (proof/baseline/verification) + reproducible flag, the active operation constraints (red lines), and the current goal state. Then re-run the proof request and record the verdict with retest_finding.",
|
|
66817
|
+
inputSchema: {
|
|
66818
|
+
finding: string2().describe("JSON of the Finding object to retest")
|
|
66819
|
+
}
|
|
66820
|
+
}, async ({ finding }) => {
|
|
66821
|
+
let f;
|
|
66822
|
+
try {
|
|
66823
|
+
f = JSON.parse(finding);
|
|
66824
|
+
} catch {
|
|
66825
|
+
return { content: [{ type: "text", text: JSON.stringify({ error: "invalid finding JSON" }) }] };
|
|
66826
|
+
}
|
|
66827
|
+
const ev = f.evidence ?? [];
|
|
66828
|
+
const roles = evidenceRoles(ev);
|
|
66829
|
+
const byRole = { proof: [], baseline: [], verification: [], supporting: [] };
|
|
66830
|
+
for (const e of ev)
|
|
66831
|
+
byRole[e.role].push({ evidence_id: e.evidence_id, type: e.type, description: e.description, artifacts: e.artifacts.map((a) => a.name) });
|
|
66832
|
+
const missing = ["proof", "baseline", "verification"].filter((r) => !roles[r]);
|
|
66833
|
+
const goals = goalStatus();
|
|
66834
|
+
return {
|
|
66835
|
+
content: [{
|
|
66836
|
+
type: "text",
|
|
66837
|
+
text: JSON.stringify({
|
|
66838
|
+
finding: {
|
|
66839
|
+
id: f.id,
|
|
66840
|
+
status: f.status,
|
|
66841
|
+
title: f.title,
|
|
66842
|
+
severity: f.classification?.severity,
|
|
66843
|
+
cwe: f.classification?.cwe,
|
|
66844
|
+
target: f.target,
|
|
66845
|
+
method: f.target?.method,
|
|
66846
|
+
param: f.target?.param
|
|
66847
|
+
},
|
|
66848
|
+
poc: { ...byRole, reproducible: roles.reproducible, missing: missing.length ? missing : undefined },
|
|
66849
|
+
constraints: listConstraints(),
|
|
66850
|
+
goals: { all_met: goals.all_met, met: goals.met, total: goals.total },
|
|
66851
|
+
retest_hint: "Re-run the proof request (or the original PoC path) against the CURRENT target. Still reproduces → retest_finding(verdict=still_vulnerable); no longer reproduces → fixed; a blocker (WAF/target down/missing login) prevents a verdict → inconclusive."
|
|
66852
|
+
})
|
|
66853
|
+
}]
|
|
66854
|
+
};
|
|
66778
66855
|
});
|
|
66779
66856
|
server.registerTool("redact", {
|
|
66780
66857
|
title: "Redact secrets from text",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "blitzstrike",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.176",
|
|
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": {
|