blitzstrike 1.0.10 → 1.0.12
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/dist/index.js +249 -8
- package/docs/findings.md +95 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -22225,6 +22225,159 @@ function manualForTool(toolName) {
|
|
|
22225
22225
|
return null;
|
|
22226
22226
|
}
|
|
22227
22227
|
|
|
22228
|
+
// src/evidence.ts
|
|
22229
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
22230
|
+
var REDACTION_PATTERNS = [
|
|
22231
|
+
[/(authorization\s*[:=]\s*)(bearer\s+)?[A-Za-z0-9._~+/=-]{8,}/gi, "$1$2[REDACTED]"],
|
|
22232
|
+
[/(api[_-]?key\s*[:=]\s*)["']?[A-Za-z0-9._-]{16,}["']?/gi, "$1[REDACTED]"],
|
|
22233
|
+
[/(access[_-]?token\s*[:=]\s*)["']?[A-Za-z0-9._-]{16,}["']?/gi, "$1[REDACTED]"],
|
|
22234
|
+
[/(secret\s*[:=]\s*)["']?[A-Za-z0-9._/-]{16,}["']?/gi, "$1[REDACTED]"],
|
|
22235
|
+
[/(password\s*[:=]\s*)["']?[^"'\s,}&]{4,}["']?/gi, "$1[REDACTED]"],
|
|
22236
|
+
[/(passwd\s*[:=]\s*)["']?[^"'\s,}&]{4,}["']?/gi, "$1[REDACTED]"],
|
|
22237
|
+
[/(private[_-]?key\s*[:=]\s*)["']?[A-Za-z0-9+/=_-]{16,}["']?/gi, "$1[REDACTED]"],
|
|
22238
|
+
[/(session\s*[:=]\s*)["']?[A-Za-z0-9._-]{12,}["']?/gi, "$1[REDACTED]"],
|
|
22239
|
+
[/(cookie\s*[:=]\s*)["']?[A-Za-z0-9._-]{12,}["']?/gi, "$1[REDACTED]"],
|
|
22240
|
+
[/(set-cookie\s*:\s*)[^\r\n]+/gi, "$1[REDACTED]"],
|
|
22241
|
+
[/AKIA[0-9A-Z]{16}/g, "[REDACTED]"],
|
|
22242
|
+
[/ghp_[A-Za-z0-9]{20,}/g, "[REDACTED]"],
|
|
22243
|
+
[/github_pat_[A-Za-z0-9_]{20,}/g, "[REDACTED]"],
|
|
22244
|
+
[/sk-[A-Za-z0-9]{20,}/g, "[REDACTED]"],
|
|
22245
|
+
[/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g, "[REDACTED]"]
|
|
22246
|
+
];
|
|
22247
|
+
function redactSecrets(text) {
|
|
22248
|
+
let out = text;
|
|
22249
|
+
for (const [re, repl] of REDACTION_PATTERNS) {
|
|
22250
|
+
out = out.replace(re, repl);
|
|
22251
|
+
}
|
|
22252
|
+
return out;
|
|
22253
|
+
}
|
|
22254
|
+
function redactObject(value) {
|
|
22255
|
+
if (typeof value === "string")
|
|
22256
|
+
return redactSecrets(value);
|
|
22257
|
+
if (Array.isArray(value))
|
|
22258
|
+
return value.map((v) => redactObject(v));
|
|
22259
|
+
if (value && typeof value === "object") {
|
|
22260
|
+
const out = {};
|
|
22261
|
+
for (const [k, v] of Object.entries(value)) {
|
|
22262
|
+
out[k] = redactObject(v);
|
|
22263
|
+
}
|
|
22264
|
+
return out;
|
|
22265
|
+
}
|
|
22266
|
+
return value;
|
|
22267
|
+
}
|
|
22268
|
+
function sha256(text) {
|
|
22269
|
+
return createHash2("sha256").update(text).digest("hex");
|
|
22270
|
+
}
|
|
22271
|
+
var evidenceCounter = 0;
|
|
22272
|
+
function nextEvidenceId() {
|
|
22273
|
+
evidenceCounter += 1;
|
|
22274
|
+
return `EV-${String(evidenceCounter).padStart(6, "0")}`;
|
|
22275
|
+
}
|
|
22276
|
+
function makeEvidence(input) {
|
|
22277
|
+
const artifacts = (input.artifacts ?? []).map((a) => {
|
|
22278
|
+
const content = redactSecrets(a.content);
|
|
22279
|
+
return { name: a.name, kind: a.kind, content, sha256: sha256(content) };
|
|
22280
|
+
});
|
|
22281
|
+
return {
|
|
22282
|
+
evidence_id: nextEvidenceId(),
|
|
22283
|
+
type: input.type,
|
|
22284
|
+
description: redactSecrets(input.description),
|
|
22285
|
+
source: input.source ? redactObject(input.source) : undefined,
|
|
22286
|
+
sink: input.sink ? redactObject(input.sink) : undefined,
|
|
22287
|
+
artifacts,
|
|
22288
|
+
recorded: new Date().toISOString()
|
|
22289
|
+
};
|
|
22290
|
+
}
|
|
22291
|
+
|
|
22292
|
+
// src/finding.ts
|
|
22293
|
+
var LIFECYCLE_TRANSITIONS = {
|
|
22294
|
+
detected: ["triaged", "rejected"],
|
|
22295
|
+
triaged: ["hypothesis", "rejected", "out_of_scope"],
|
|
22296
|
+
hypothesis: ["validating", "false_positive", "rejected", "blocked"],
|
|
22297
|
+
validating: ["confirmed", "likely", "unconfirmed", "false_positive", "blocked", "out_of_scope"],
|
|
22298
|
+
confirmed: [],
|
|
22299
|
+
false_positive: [],
|
|
22300
|
+
rejected: [],
|
|
22301
|
+
blocked: [],
|
|
22302
|
+
out_of_scope: []
|
|
22303
|
+
};
|
|
22304
|
+
function canTransition(from, to) {
|
|
22305
|
+
const allowed = LIFECYCLE_TRANSITIONS[from] ?? [];
|
|
22306
|
+
return allowed.includes(to);
|
|
22307
|
+
}
|
|
22308
|
+
var DEFAULT_WEIGHTS = {
|
|
22309
|
+
static_analysis: 0.2,
|
|
22310
|
+
data_flow: 0.25,
|
|
22311
|
+
reachability: 0.15,
|
|
22312
|
+
preconditions: 0.1,
|
|
22313
|
+
runtime_validation: 0.2,
|
|
22314
|
+
negative_control: 0.1
|
|
22315
|
+
};
|
|
22316
|
+
var confidenceWeights = { ...DEFAULT_WEIGHTS };
|
|
22317
|
+
function computeConfidence(factors) {
|
|
22318
|
+
let score = 0;
|
|
22319
|
+
for (const [key, weight] of Object.entries(confidenceWeights)) {
|
|
22320
|
+
if (factors[key] === true)
|
|
22321
|
+
score += weight;
|
|
22322
|
+
}
|
|
22323
|
+
return Math.round(score * 100) / 100;
|
|
22324
|
+
}
|
|
22325
|
+
function confidenceLevel(score) {
|
|
22326
|
+
if (score >= 0.9)
|
|
22327
|
+
return "confirmed";
|
|
22328
|
+
if (score >= 0.7)
|
|
22329
|
+
return "high_confidence";
|
|
22330
|
+
if (score >= 0.5)
|
|
22331
|
+
return "likely";
|
|
22332
|
+
if (score >= 0.3)
|
|
22333
|
+
return "suspected";
|
|
22334
|
+
return "informational";
|
|
22335
|
+
}
|
|
22336
|
+
var findingCounter = 0;
|
|
22337
|
+
function nextFindingId() {
|
|
22338
|
+
findingCounter += 1;
|
|
22339
|
+
return `BS-${new Date().getUTCFullYear()}-${String(findingCounter).padStart(6, "0")}`;
|
|
22340
|
+
}
|
|
22341
|
+
function makeFinding(input) {
|
|
22342
|
+
const now = new Date().toISOString();
|
|
22343
|
+
const status = input.status ?? "detected";
|
|
22344
|
+
const factors = confidenceFactorsFor(input);
|
|
22345
|
+
const confidence = computeConfidence(factors);
|
|
22346
|
+
return {
|
|
22347
|
+
id: nextFindingId(),
|
|
22348
|
+
status,
|
|
22349
|
+
title: input.title,
|
|
22350
|
+
target: input.target,
|
|
22351
|
+
classification: {
|
|
22352
|
+
severity: input.severity,
|
|
22353
|
+
cwe: input.cwe,
|
|
22354
|
+
cwe_name: input.cweName,
|
|
22355
|
+
cwe_confidence: input.cweConfidence
|
|
22356
|
+
},
|
|
22357
|
+
confidence,
|
|
22358
|
+
confidence_level: confidenceLevel(confidence),
|
|
22359
|
+
source: input.source,
|
|
22360
|
+
flow: input.flow ?? [],
|
|
22361
|
+
sink: input.sink,
|
|
22362
|
+
validation: { performed: false },
|
|
22363
|
+
evidence: [],
|
|
22364
|
+
chain: { id: input.chainId ?? null, name: input.chainName },
|
|
22365
|
+
impact: {},
|
|
22366
|
+
remediation: {},
|
|
22367
|
+
timestamps: { created: now, updated: now }
|
|
22368
|
+
};
|
|
22369
|
+
}
|
|
22370
|
+
function confidenceFactorsFor(_input) {
|
|
22371
|
+
return {
|
|
22372
|
+
static_analysis: true,
|
|
22373
|
+
data_flow: false,
|
|
22374
|
+
reachability: false,
|
|
22375
|
+
preconditions: false,
|
|
22376
|
+
runtime_validation: false,
|
|
22377
|
+
negative_control: false
|
|
22378
|
+
};
|
|
22379
|
+
}
|
|
22380
|
+
|
|
22228
22381
|
// src/orchestrator.ts
|
|
22229
22382
|
var _chainsCache = null;
|
|
22230
22383
|
function loadChains() {
|
|
@@ -22393,15 +22546,41 @@ function runEngagement(target, scope = "", mode = "bug-bounty", maxFiles = 2000,
|
|
|
22393
22546
|
}
|
|
22394
22547
|
report.tiers = { ...report.tiers, eagle_eye: { traced_chains: eagle } };
|
|
22395
22548
|
const rank = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
22396
|
-
const
|
|
22549
|
+
const matchedSorted = [...blitz.matched_chains].sort((a, b) => (rank[a.severity] ?? 99) - (rank[b.severity] ?? 99));
|
|
22550
|
+
const findings = matchedSorted.map((f) => {
|
|
22551
|
+
const chain = chainById.get(f.chain_id);
|
|
22552
|
+
const severity = f.severity ?? "medium";
|
|
22553
|
+
const finding = makeFinding({
|
|
22554
|
+
title: f.name,
|
|
22555
|
+
target: { type: "source", path: target },
|
|
22556
|
+
severity,
|
|
22557
|
+
source: { type: "static_sink_signal", name: f.chain_id },
|
|
22558
|
+
sink: { type: f.chain_id, symbol: f.name },
|
|
22559
|
+
chainId: f.chain_id,
|
|
22560
|
+
chainName: f.name,
|
|
22561
|
+
status: "hypothesis"
|
|
22562
|
+
});
|
|
22563
|
+
const ev = makeEvidence({
|
|
22564
|
+
type: "sink_location",
|
|
22565
|
+
description: `Static sink signal matched escalation chain '${f.chain_id}' (${severity}). Hypothesis only — not yet validated.`,
|
|
22566
|
+
sink: { chain_id: f.chain_id, name: f.name, severity },
|
|
22567
|
+
artifacts: [{ name: "chain_match", kind: "json", content: JSON.stringify({ chain_id: f.chain_id, severity, steps: chain?.steps.length ?? 0 }) }]
|
|
22568
|
+
});
|
|
22569
|
+
finding.evidence.push(ev);
|
|
22570
|
+
return finding;
|
|
22571
|
+
});
|
|
22397
22572
|
report.findings = findings.map((f) => ({
|
|
22398
|
-
|
|
22399
|
-
|
|
22400
|
-
|
|
22401
|
-
|
|
22573
|
+
id: f.id,
|
|
22574
|
+
status: f.status,
|
|
22575
|
+
title: f.title,
|
|
22576
|
+
severity: f.classification.severity,
|
|
22577
|
+
confidence: f.confidence,
|
|
22578
|
+
confidence_level: f.confidence_level,
|
|
22579
|
+
chain_id: f.chain.id,
|
|
22580
|
+
evidence_count: f.evidence.length
|
|
22402
22581
|
}));
|
|
22403
22582
|
report.status = "COMPLETE";
|
|
22404
|
-
report.note = "All findings are HYPOTHESES until verified live with strike_verify. " + "Apply each chain's negative_control before reporting.";
|
|
22583
|
+
report.note = "All findings are HYPOTHESES until verified live with strike_verify. " + "Apply each chain's negative_control before reporting. Confidence reflects static evidence only.";
|
|
22405
22584
|
if (remember) {
|
|
22406
22585
|
let captured = 0;
|
|
22407
22586
|
for (const mc of blitz.matched_chains) {
|
|
@@ -23424,6 +23603,68 @@ function createServer() {
|
|
|
23424
23603
|
}, async ({ topic, limit }) => {
|
|
23425
23604
|
return { content: [{ type: "text", text: JSON.stringify(templateLookup(topic, limit ?? 10)) }] };
|
|
23426
23605
|
});
|
|
23606
|
+
server.registerTool("finding_create", {
|
|
23607
|
+
title: "Create a canonical finding",
|
|
23608
|
+
description: "FINDINGS: create a canonical, evidence-first finding. Severity describes impact; confidence (deterministic) describes certainty. Default status=detected (hypothesis-pending).",
|
|
23609
|
+
inputSchema: {
|
|
23610
|
+
title: string2().describe("Finding title"),
|
|
23611
|
+
target_type: string2().optional().describe("Target type (web/api/source/mobile/network/other)"),
|
|
23612
|
+
host: string2().optional().describe("Target host"),
|
|
23613
|
+
endpoint: string2().optional().describe("Target endpoint/path"),
|
|
23614
|
+
severity: string2().describe("Severity: critical/high/medium/low/informational"),
|
|
23615
|
+
cwe: string2().optional().describe("CWE id (e.g. CWE-89)"),
|
|
23616
|
+
source_type: string2().describe("Source type (e.g. request_parameter, post_body, header, cookie, file)"),
|
|
23617
|
+
source_name: string2().describe("Source name"),
|
|
23618
|
+
sink_type: string2().describe("Sink type (e.g. sql_execution, command_execution, file_operations)"),
|
|
23619
|
+
sink_symbol: string2().optional().describe("Sink symbol (e.g. '->query(')"),
|
|
23620
|
+
chain_id: string2().optional().describe("Escalation chain id")
|
|
23621
|
+
}
|
|
23622
|
+
}, async ({ title, target_type, host, endpoint, severity, cwe, source_type, source_name, sink_type, sink_symbol, chain_id }) => {
|
|
23623
|
+
const f = makeFinding({
|
|
23624
|
+
title,
|
|
23625
|
+
target: { type: target_type ?? "web", host, endpoint },
|
|
23626
|
+
severity: severity ?? "medium",
|
|
23627
|
+
cwe,
|
|
23628
|
+
source: { type: source_type, name: source_name },
|
|
23629
|
+
sink: { type: sink_type, symbol: sink_symbol },
|
|
23630
|
+
chainId: chain_id ?? null,
|
|
23631
|
+
status: "detected"
|
|
23632
|
+
});
|
|
23633
|
+
return { content: [{ type: "text", text: JSON.stringify(f) }] };
|
|
23634
|
+
});
|
|
23635
|
+
server.registerTool("finding_transition", {
|
|
23636
|
+
title: "Advance a finding lifecycle",
|
|
23637
|
+
description: "FINDINGS: advance a finding through its strict lifecycle (detected->triaged->hypothesis->validating->confirmed). Rejects illegal transitions.",
|
|
23638
|
+
inputSchema: {
|
|
23639
|
+
status: string2().describe("Current status"),
|
|
23640
|
+
to: string2().describe("Target status (triaged/hypothesis/validating/confirmed/false_positive/rejected/blocked/out_of_scope)")
|
|
23641
|
+
}
|
|
23642
|
+
}, async ({ status, to }) => {
|
|
23643
|
+
const ok = canTransition(status, to);
|
|
23644
|
+
return { content: [{ type: "text", text: JSON.stringify({ from: status, to, legal: ok }) }] };
|
|
23645
|
+
});
|
|
23646
|
+
server.registerTool("confidence_score", {
|
|
23647
|
+
title: "Compute deterministic confidence",
|
|
23648
|
+
description: "FINDINGS: compute a deterministic weighted confidence score (static/data-flow/reachability/preconditions/validation/negative-control). Never an AI opinion.",
|
|
23649
|
+
inputSchema: {
|
|
23650
|
+
static_analysis: boolean2().optional(),
|
|
23651
|
+
data_flow: boolean2().optional(),
|
|
23652
|
+
reachability: boolean2().optional(),
|
|
23653
|
+
preconditions: boolean2().optional(),
|
|
23654
|
+
runtime_validation: boolean2().optional(),
|
|
23655
|
+
negative_control: boolean2().optional()
|
|
23656
|
+
}
|
|
23657
|
+
}, async (factors) => {
|
|
23658
|
+
const score = computeConfidence(factors);
|
|
23659
|
+
return { content: [{ type: "text", text: JSON.stringify({ score, level: confidenceLevel(score) }) }] };
|
|
23660
|
+
});
|
|
23661
|
+
server.registerTool("redact", {
|
|
23662
|
+
title: "Redact secrets from text",
|
|
23663
|
+
description: "EVIDENCE: redact passwords/API keys/tokens/cookies/private keys from text before persisting evidence or reporting.",
|
|
23664
|
+
inputSchema: { text: string2().describe("Text to redact") }
|
|
23665
|
+
}, async ({ text }) => {
|
|
23666
|
+
return { content: [{ type: "text", text: JSON.stringify({ redacted: redactSecrets(text) }) }] };
|
|
23667
|
+
});
|
|
23427
23668
|
return server;
|
|
23428
23669
|
}
|
|
23429
23670
|
async function serve() {
|
|
@@ -23534,14 +23775,14 @@ function jsonMcpServersWrite(p) {
|
|
|
23534
23775
|
};
|
|
23535
23776
|
}
|
|
23536
23777
|
function opencodeWrite(p) {
|
|
23537
|
-
return (
|
|
23778
|
+
return (_command, _args) => {
|
|
23538
23779
|
const dir = dirname(p);
|
|
23539
23780
|
if (!existsSync6(dir))
|
|
23540
23781
|
mkdirSync2(dir, { recursive: true });
|
|
23541
23782
|
const existing = readJson(p) ?? {};
|
|
23542
23783
|
existing.mcp = {
|
|
23543
23784
|
...existing.mcp ?? {},
|
|
23544
|
-
blitzstrike: { type: "local", command: [
|
|
23785
|
+
blitzstrike: { type: "local", command: ["npx", "-y", "blitzstrike", "serve", "--mcp"], enabled: true }
|
|
23545
23786
|
};
|
|
23546
23787
|
writeFileSync(p, JSON.stringify(existing, null, 2));
|
|
23547
23788
|
copyOpenCodeAgents();
|
package/docs/findings.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Findings & Evidence Engine
|
|
2
|
+
|
|
3
|
+
Blitz Strike follows one principle: **a scanner hit is a hypothesis; evidence is
|
|
4
|
+
the verdict.**
|
|
5
|
+
|
|
6
|
+
This document describes the canonical finding model, the strict lifecycle, and
|
|
7
|
+
the deterministic confidence engine. No other part of the codebase invents its
|
|
8
|
+
own finding shape — every producer funnels into these modules.
|
|
9
|
+
|
|
10
|
+
## Finding schema
|
|
11
|
+
|
|
12
|
+
`src/finding.ts` defines the single `Finding` model:
|
|
13
|
+
|
|
14
|
+
| Field | Meaning |
|
|
15
|
+
| :--- | :--- |
|
|
16
|
+
| `id` | Canonical id, `BS-YYYY-NNNNNN` |
|
|
17
|
+
| `status` | Lifecycle state (see below) |
|
|
18
|
+
| `title` | Human-readable title |
|
|
19
|
+
| `target` | `type` (web/api/source/mobile/network/other) + host/endpoint/path |
|
|
20
|
+
| `classification` | severity, CWE id/name/confidence, CVSS (evidence-based) |
|
|
21
|
+
| `confidence` | 0.0–1.0 deterministic score (NOT an AI opinion) |
|
|
22
|
+
| `confidence_level` | informational / suspected / likely / high_confidence / confirmed |
|
|
23
|
+
| `source` | attacker-controlled source (type + name + location) |
|
|
24
|
+
| `flow` | data-flow path (source → transforms → sink) |
|
|
25
|
+
| `sink` | security-sensitive operation (type + symbol + location) |
|
|
26
|
+
| `validation` | performed + baseline + negative_control |
|
|
27
|
+
| `evidence` | array of integrity-tagged evidence records |
|
|
28
|
+
| `chain` | escalation chain id/name |
|
|
29
|
+
| `impact` / `remediation` | impact + fix |
|
|
30
|
+
| `timestamps` | created / updated |
|
|
31
|
+
|
|
32
|
+
## Lifecycle
|
|
33
|
+
|
|
34
|
+
Strict, machine-readable state machine (`transition()` rejects illegal moves):
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
detected → triaged → hypothesis → validating → confirmed
|
|
38
|
+
↘ rejected ↘ false_positive
|
|
39
|
+
↘ out_of_scope ↘ blocked
|
|
40
|
+
↘ out_of_scope
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
`confirmed`, `false_positive`, `rejected`, `blocked`, `out_of_scope` are
|
|
44
|
+
terminal.
|
|
45
|
+
|
|
46
|
+
## Severity vs confidence
|
|
47
|
+
|
|
48
|
+
- **Severity** = impact (`critical` / `high` / `medium` / `low` / `informational`).
|
|
49
|
+
- **Confidence** = certainty (deterministic 0.0–1.0).
|
|
50
|
+
|
|
51
|
+
They are never combined. "Severity CRITICAL + confidence 0.41" = *potentially
|
|
52
|
+
critical, insufficient evidence*. "Severity MEDIUM + confidence 0.98" = *medium
|
|
53
|
+
impact, highly reliable*.
|
|
54
|
+
|
|
55
|
+
## Confidence engine
|
|
56
|
+
|
|
57
|
+
`computeConfidence()` is deterministic and weighted (configurable via
|
|
58
|
+
`setConfidenceWeights()`):
|
|
59
|
+
|
|
60
|
+
| Factor | Default weight |
|
|
61
|
+
| :--- | :--- |
|
|
62
|
+
| static_analysis | 0.20 |
|
|
63
|
+
| data_flow | 0.25 |
|
|
64
|
+
| reachability | 0.15 |
|
|
65
|
+
| preconditions | 0.10 |
|
|
66
|
+
| runtime_validation | 0.20 |
|
|
67
|
+
| negative_control | 0.10 |
|
|
68
|
+
|
|
69
|
+
Levels: `0.00–0.29` informational · `0.30–0.49` suspected · `0.50–0.69` likely ·
|
|
70
|
+
`0.70–0.89` high_confidence · `0.90–1.00` confirmed.
|
|
71
|
+
|
|
72
|
+
A high confidence score is **never** proof by itself — confirmation requires
|
|
73
|
+
validation + evidence.
|
|
74
|
+
|
|
75
|
+
## Evidence engine
|
|
76
|
+
|
|
77
|
+
`src/evidence.ts`:
|
|
78
|
+
|
|
79
|
+
- **Schema** — `evidence_id`, `type`, `description`, `source`, `sink`, `artifacts[]`, `recorded`.
|
|
80
|
+
- **Integrity** — every artifact carries a SHA-256 (`sha256()`), verified by `verifyEvidence()`.
|
|
81
|
+
- **Secret redaction** — `redactSecrets()` strips passwords, API keys, tokens,
|
|
82
|
+
cookies, `Authorization` headers, private keys before persistence/report/log/context.
|
|
83
|
+
- **Append-only** — confirmed evidence is never silently rewritten.
|
|
84
|
+
|
|
85
|
+
## MCP tools
|
|
86
|
+
|
|
87
|
+
| Tool | Purpose |
|
|
88
|
+
| :--- | :--- |
|
|
89
|
+
| `finding_create` | create a canonical finding (default `detected`) |
|
|
90
|
+
| `finding_transition` | advance lifecycle (rejects illegal moves) |
|
|
91
|
+
| `confidence_score` | deterministic weighted confidence |
|
|
92
|
+
| `redact` | redact secrets from arbitrary text |
|
|
93
|
+
|
|
94
|
+
`run_engagement` now emits canonical findings (status `hypothesis`, carrying
|
|
95
|
+
static + sink evidence) instead of ad-hoc `{chain_id, name, severity}` tuples.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "blitzstrike",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.12",
|
|
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": {
|