blitzstrike 2.4.8 → 2.4.9

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,18 @@ 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.9] — 2026-09-14
9
+
10
+ ### Added — evidence-first enforcement (findings are never born empty)
11
+
12
+ - `makeFinding` + `finding_create` now accept `evidence` at creation — a finding
13
+ can carry its observed artifact (headers/URL/response) the moment it is
14
+ created, instead of relying on a separate attach call that gets skipped.
15
+ - `finding_create` warns when a finding is created with no evidence.
16
+ - `reportMarkdown` now flags evidence-less findings with an explicit
17
+ "Evidence-first violation" block (ids listed) — detection without proof is
18
+ surfaced instead of silently shipped.
19
+
8
20
  ## [2.4.8] — 2026-09-14
9
21
 
10
22
  ### Added — MCP integration health checks
package/dist/index.js CHANGED
@@ -31064,7 +31064,7 @@ function makeFinding(input) {
31064
31064
  const status = input.status ?? "detected";
31065
31065
  const factors = confidenceFactorsFor(input);
31066
31066
  const confidence = computeConfidence(factors);
31067
- const finding = {
31067
+ let finding = {
31068
31068
  id: nextFindingId(),
31069
31069
  status,
31070
31070
  title: input.title,
@@ -31087,6 +31087,16 @@ function makeFinding(input) {
31087
31087
  remediation: {},
31088
31088
  timestamps: { created: now, updated: now }
31089
31089
  };
31090
+ if (input.evidence?.length) {
31091
+ for (const e of input.evidence) {
31092
+ const ev = makeEvidence({
31093
+ type: e.type,
31094
+ description: e.description,
31095
+ artifacts: e.content ? [{ name: "artifact", kind: "evidence", content: e.content }] : []
31096
+ });
31097
+ finding = attachEvidence(finding, ev);
31098
+ }
31099
+ }
31090
31100
  recordAudit("finding_created", { tool: "eagle-eye", target: input.target.host ?? input.target.endpoint, result: status, correlationId: finding.id });
31091
31101
  return finding;
31092
31102
  }
@@ -33009,11 +33019,15 @@ function summarize(findings) {
33009
33019
  const byStatus = {};
33010
33020
  const bySeverity = {};
33011
33021
  let evidenceArtifacts = 0;
33022
+ let evidenceLess = 0;
33012
33023
  for (const f of findings) {
33013
33024
  byStatus[f.status ?? "detected"] = (byStatus[f.status ?? "detected"] ?? 0) + 1;
33014
33025
  const sev = f.classification?.severity ?? "informational";
33015
33026
  bySeverity[sev] = (bySeverity[sev] ?? 0) + 1;
33016
- evidenceArtifacts += f.evidence?.reduce((n, e) => n + (e.artifacts?.length ?? 0), 0) ?? 0;
33027
+ const arts = f.evidence?.reduce((n, e) => n + (e.artifacts?.length ?? 0), 0) ?? 0;
33028
+ evidenceArtifacts += arts;
33029
+ if ((f.evidence ?? []).length === 0)
33030
+ evidenceLess += 1;
33017
33031
  }
33018
33032
  const groups = dedupFindings(findings);
33019
33033
  return {
@@ -33023,7 +33037,8 @@ function summarize(findings) {
33023
33037
  by_severity: bySeverity,
33024
33038
  confirmed: byStatus["confirmed"] ?? 0,
33025
33039
  false_positives: byStatus["false_positive"] ?? 0,
33026
- evidence_artifacts: evidenceArtifacts
33040
+ evidence_artifacts: evidenceArtifacts,
33041
+ evidence_less_findings: evidenceLess
33027
33042
  };
33028
33043
  }
33029
33044
  function reportMarkdown(findings, opts = {}) {
@@ -33047,6 +33062,11 @@ function reportMarkdown(findings, opts = {}) {
33047
33062
  }
33048
33063
  lines.push(`Detailed findings, reproduction steps, impact, and remediation follow in section 5.`);
33049
33064
  lines.push("");
33065
+ if (summary.evidence_less_findings > 0) {
33066
+ const evLess = findings.filter((f) => (f.evidence ?? []).length === 0).map((f) => f.id).join(", ");
33067
+ lines.push(`> ⚠️ **Evidence-first violation:** **${summary.evidence_less_findings}** finding(s) carry NO evidence artifacts (${evLess}). ` + `Detection is not proof — every finding must carry the observed artifact (headers, URL, response body). Attach evidence via finding_attach_evidence before finalizing.`);
33068
+ lines.push("");
33069
+ }
33050
33070
  lines.push("## 2. Scope");
33051
33071
  lines.push("");
33052
33072
  lines.push(`- **Target(s):** ${scope}`);
@@ -57170,7 +57190,7 @@ ${statusLine}` : statusLine },
57170
57190
  });
57171
57191
  server.registerTool("finding_create", {
57172
57192
  title: "Create a canonical finding",
57173
- description: "FINDINGS: create a canonical, evidence-first finding. Severity describes impact; confidence (deterministic) describes certainty. Default status=detected (hypothesis-pending).",
57193
+ description: "FINDINGS: create a canonical, evidence-first finding. Severity describes impact; confidence (deterministic) describes certainty. Default status=detected (hypothesis-pending). Pass `evidence` (JSON array of {type, description, content}) to attach observed artifacts AT CREATION — a finding must never be born empty when you already hold the artifact (headers, URL, response body).",
57174
57194
  inputSchema: {
57175
57195
  title: string2().describe("Finding title"),
57176
57196
  target_type: string2().optional().describe("Target type (web/api/source/mobile/network/other)"),
@@ -57182,9 +57202,18 @@ ${statusLine}` : statusLine },
57182
57202
  source_name: string2().describe("Source name"),
57183
57203
  sink_type: string2().describe("Sink type (e.g. sql_execution, command_execution, file_operations)"),
57184
57204
  sink_symbol: string2().optional().describe("Sink symbol (e.g. '->query(')"),
57185
- chain_id: string2().optional().describe("Escalation chain id")
57205
+ chain_id: string2().optional().describe("Escalation chain id"),
57206
+ evidence: string2().optional().describe("JSON array of evidence entries: [{type, description, content?}] — attached at creation (redacted + SHA-256 tagged)")
57207
+ }
57208
+ }, async ({ title, target_type, host, endpoint, severity, cwe, source_type, source_name, sink_type, sink_symbol, chain_id, evidence }) => {
57209
+ let evs = [];
57210
+ if (evidence) {
57211
+ try {
57212
+ evs = JSON.parse(evidence);
57213
+ } catch {
57214
+ return { content: [{ type: "text", text: JSON.stringify({ error: "invalid evidence JSON" }) }] };
57215
+ }
57186
57216
  }
57187
- }, async ({ title, target_type, host, endpoint, severity, cwe, source_type, source_name, sink_type, sink_symbol, chain_id }) => {
57188
57217
  const f = makeFinding({
57189
57218
  title,
57190
57219
  target: { type: target_type ?? "web", host, endpoint },
@@ -57193,9 +57222,19 @@ ${statusLine}` : statusLine },
57193
57222
  source: { type: source_type, name: source_name },
57194
57223
  sink: { type: sink_type, symbol: sink_symbol },
57195
57224
  chainId: chain_id ?? null,
57196
- status: "detected"
57225
+ status: "detected",
57226
+ evidence: evs
57197
57227
  });
57198
- return { content: [{ type: "text", text: JSON.stringify(f) }] };
57228
+ const empty = (f.evidence ?? []).length === 0;
57229
+ return {
57230
+ content: [{
57231
+ type: "text",
57232
+ text: JSON.stringify({
57233
+ ...f,
57234
+ _warning: empty ? "finding created with NO evidence — if you hold the observed artifact (headers/URL/body), attach it now via `evidence` or finding_attach_evidence" : undefined
57235
+ })
57236
+ }]
57237
+ };
57199
57238
  });
57200
57239
  server.registerTool("finding_transition", {
57201
57240
  title: "Advance a finding lifecycle",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blitzstrike",
3
- "version": "2.4.8",
3
+ "version": "2.4.9",
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": {