blitzstrike 2.4.176 → 2.4.178
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 +20 -0
- package/dist/index.js +128 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,26 @@ 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.178] — 2026-10-11
|
|
9
|
+
|
|
10
|
+
### Added — goal decomposition (six-phase plan)
|
|
11
|
+
|
|
12
|
+
- New `decompose_goal` tool: decompose a high-level goal into the standard
|
|
13
|
+
six-phase sub-goal plan (ENUMERATION → SURFACE → DISCOVERY → VERIFICATION →
|
|
14
|
+
ESCALATION → REPORT), each with its own quantitative condition. `goal_tree`
|
|
15
|
+
shows the parent → sub-goal hierarchy and per-parent progress.
|
|
16
|
+
|
|
17
|
+
## [2.4.177] — 2026-10-11
|
|
18
|
+
|
|
19
|
+
### Added — surface coverage tracker (quantitative progress)
|
|
20
|
+
|
|
21
|
+
- New `surface-coverage` engine + 3 tools: `surface_add` (register a discovered
|
|
22
|
+
endpoint/param/host/subdomain/route/class), `surface_verdict` (mark a terminal
|
|
23
|
+
verdict: confirmed/dead/partial/skipped), and `coverage` (total/terminal/pending
|
|
24
|
+
+ coverage % + by-kind/by-verdict breakdown).
|
|
25
|
+
- Gives the agent a measurable "how done are we" number — a goal like
|
|
26
|
+
"coverage >= 80%" is now verifiable against the measured pct before prove_goal.
|
|
27
|
+
|
|
8
28
|
## [2.4.176] — 2026-10-11
|
|
9
29
|
|
|
10
30
|
### Added — retest context (completes the retest loop)
|
package/dist/index.js
CHANGED
|
@@ -63938,15 +63938,36 @@ function nextId2() {
|
|
|
63938
63938
|
counter2 += 1;
|
|
63939
63939
|
return `G-${String(counter2).padStart(3, "0")}`;
|
|
63940
63940
|
}
|
|
63941
|
+
var STANDARD_SUBGOALS = [
|
|
63942
|
+
{ text: "ENUMERATION — discover every in-scope asset", condition: "every host/subdomain/endpoint enumerated (asset_discovery)" },
|
|
63943
|
+
{ text: "SURFACE — map every endpoint, parameter, and action", condition: "coverage >= 100% (every surface item has a terminal verdict)" },
|
|
63944
|
+
{ text: "DISCOVERY — find vulnerabilities across every class", condition: "each eligible class × shape carries a terminal verdict" },
|
|
63945
|
+
{ text: "VERIFICATION — verify each hypothesis live", condition: "every hypothesis verified (strike_verify/OOB) or refuted" },
|
|
63946
|
+
{ text: "ESCALATION — drive each finding to real impact", condition: "every foothold escalated to records/admin/PII or genuinely blocked" },
|
|
63947
|
+
{ text: "REPORT — write findings", condition: "generate_report run; zero open obligations" }
|
|
63948
|
+
];
|
|
63941
63949
|
function setGoals(texts) {
|
|
63942
63950
|
for (const t of texts) {
|
|
63943
63951
|
const text = typeof t === "string" ? t : t.text;
|
|
63944
63952
|
const condition = typeof t === "string" ? undefined : t.condition;
|
|
63953
|
+
const parent_id = typeof t === "string" ? undefined : t.parent_id;
|
|
63945
63954
|
const now = new Date().toISOString();
|
|
63946
|
-
goals.push({ id: nextId2(), text, condition, status: "pending", created: now, updated: now });
|
|
63955
|
+
goals.push({ id: nextId2(), text, condition, status: "pending", ...parent_id ? { parent_id } : {}, created: now, updated: now });
|
|
63947
63956
|
}
|
|
63948
63957
|
return [...goals];
|
|
63949
63958
|
}
|
|
63959
|
+
function decomposeGoal(text) {
|
|
63960
|
+
const now = new Date().toISOString();
|
|
63961
|
+
const parent = { id: nextId2(), text, status: "pending", created: now, updated: now };
|
|
63962
|
+
goals.push(parent);
|
|
63963
|
+
const sub_goals = [];
|
|
63964
|
+
for (const sg of STANDARD_SUBGOALS) {
|
|
63965
|
+
const g = { id: nextId2(), text: sg.text, condition: sg.condition, status: "pending", parent_id: parent.id, created: now, updated: now };
|
|
63966
|
+
goals.push(g);
|
|
63967
|
+
sub_goals.push(g);
|
|
63968
|
+
}
|
|
63969
|
+
return { parent, sub_goals };
|
|
63970
|
+
}
|
|
63950
63971
|
function proveGoal(id, evidence, reason) {
|
|
63951
63972
|
const g = goals.find((x) => x.id === id);
|
|
63952
63973
|
if (!g)
|
|
@@ -63961,6 +63982,13 @@ function goalStatus() {
|
|
|
63961
63982
|
const met = goals.filter((g) => g.status === "met").length;
|
|
63962
63983
|
return { goals: [...goals], all_met: goals.length > 0 && met === goals.length, met, total: goals.length };
|
|
63963
63984
|
}
|
|
63985
|
+
function goalTree() {
|
|
63986
|
+
const parents = goals.filter((g) => !g.parent_id);
|
|
63987
|
+
return parents.map((p) => {
|
|
63988
|
+
const children = goals.filter((g) => g.parent_id === p.id);
|
|
63989
|
+
return { parent: p, children, children_met: children.filter((c) => c.status === "met").length };
|
|
63990
|
+
});
|
|
63991
|
+
}
|
|
63964
63992
|
|
|
63965
63993
|
// src/facts.ts
|
|
63966
63994
|
var facts = [];
|
|
@@ -64006,6 +64034,59 @@ function lineage(id) {
|
|
|
64006
64034
|
return { fact, ancestors, descendants };
|
|
64007
64035
|
}
|
|
64008
64036
|
|
|
64037
|
+
// src/surface-coverage.ts
|
|
64038
|
+
var surface = [];
|
|
64039
|
+
var counter4 = 0;
|
|
64040
|
+
function nextId4() {
|
|
64041
|
+
counter4 += 1;
|
|
64042
|
+
return `SRF-${String(counter4).padStart(4, "0")}`;
|
|
64043
|
+
}
|
|
64044
|
+
function surfaceAdd(kind, ref) {
|
|
64045
|
+
const existing = surface.find((s) => s.kind === kind && s.ref === ref);
|
|
64046
|
+
if (existing)
|
|
64047
|
+
return existing;
|
|
64048
|
+
const item = { id: nextId4(), kind, ref, verdict: null, updated: new Date().toISOString() };
|
|
64049
|
+
surface.push(item);
|
|
64050
|
+
return item;
|
|
64051
|
+
}
|
|
64052
|
+
function surfaceVerdict(idOrRef, verdict) {
|
|
64053
|
+
const item = surface.find((s) => s.id === idOrRef || s.ref === idOrRef);
|
|
64054
|
+
if (!item)
|
|
64055
|
+
return { ok: false, error: `no surface item '${idOrRef}'` };
|
|
64056
|
+
item.verdict = verdict;
|
|
64057
|
+
item.updated = new Date().toISOString();
|
|
64058
|
+
return { ok: true, item: { ...item } };
|
|
64059
|
+
}
|
|
64060
|
+
function coverageSummary() {
|
|
64061
|
+
const by_kind = {
|
|
64062
|
+
endpoint: { total: 0, terminal: 0 },
|
|
64063
|
+
param: { total: 0, terminal: 0 },
|
|
64064
|
+
host: { total: 0, terminal: 0 },
|
|
64065
|
+
subdomain: { total: 0, terminal: 0 },
|
|
64066
|
+
route: { total: 0, terminal: 0 },
|
|
64067
|
+
class: { total: 0, terminal: 0 }
|
|
64068
|
+
};
|
|
64069
|
+
const by_verdict = { confirmed: 0, dead: 0, partial: 0, skipped: 0 };
|
|
64070
|
+
let terminal = 0;
|
|
64071
|
+
for (const s of surface) {
|
|
64072
|
+
by_kind[s.kind].total += 1;
|
|
64073
|
+
if (s.verdict) {
|
|
64074
|
+
terminal += 1;
|
|
64075
|
+
by_kind[s.kind].terminal += 1;
|
|
64076
|
+
by_verdict[s.verdict] += 1;
|
|
64077
|
+
}
|
|
64078
|
+
}
|
|
64079
|
+
const total = surface.length;
|
|
64080
|
+
return {
|
|
64081
|
+
total,
|
|
64082
|
+
terminal,
|
|
64083
|
+
pending: total - terminal,
|
|
64084
|
+
pct: total === 0 ? 0 : Math.round(terminal / total * 1000) / 10,
|
|
64085
|
+
by_kind,
|
|
64086
|
+
by_verdict
|
|
64087
|
+
};
|
|
64088
|
+
}
|
|
64089
|
+
|
|
64009
64090
|
// src/sibling-scan.ts
|
|
64010
64091
|
var SIBLING_SUFFIXES = [
|
|
64011
64092
|
"export",
|
|
@@ -65971,6 +66052,23 @@ ${statusLine}` : statusLine },
|
|
|
65971
66052
|
}, async () => {
|
|
65972
66053
|
return { content: [{ type: "text", text: JSON.stringify(goalStatus()) }] };
|
|
65973
66054
|
});
|
|
66055
|
+
server.registerTool("decompose_goal", {
|
|
66056
|
+
title: "Decompose a high-level goal into the six-phase plan",
|
|
66057
|
+
description: "GOALS: decompose a high-level goal (e.g. 'audit app.example.com') into the standard six-phase sub-goal plan — ENUMERATION → SURFACE → DISCOVERY → VERIFICATION → ESCALATION → REPORT — each registered in the ledger with its own condition (pending). Returns the parent + sub-goals. Then prove each sub-goal with prove_goal as it completes; the task is done only when all are met.",
|
|
66058
|
+
inputSchema: {
|
|
66059
|
+
goal: string2().describe("The high-level goal to decompose")
|
|
66060
|
+
}
|
|
66061
|
+
}, async ({ goal }) => {
|
|
66062
|
+
const r = decomposeGoal(goal);
|
|
66063
|
+
return { content: [{ type: "text", text: JSON.stringify({ ...r, ...goalStatus() }) }] };
|
|
66064
|
+
});
|
|
66065
|
+
server.registerTool("goal_tree", {
|
|
66066
|
+
title: "View the goal hierarchy (parents + sub-goals)",
|
|
66067
|
+
description: "GOALS: return the goal tree — each top-level goal with its sub-goals and how many of each are met. Use to see progress through a decomposed plan.",
|
|
66068
|
+
inputSchema: {}
|
|
66069
|
+
}, async () => {
|
|
66070
|
+
return { content: [{ type: "text", text: JSON.stringify(goalTree()) }] };
|
|
66071
|
+
});
|
|
65974
66072
|
server.registerTool("record_fact", {
|
|
65975
66073
|
title: "Record an exploration observation (fact)",
|
|
65976
66074
|
description: "FACTS: record an observation/conclusion that is NOT a vuln (finding_create) and NOT an asset (asset_discovery) — e.g. 'admin panel is behind SSO', 'upload strips .php', 'param id is reflected'. Pass text, confidence (observed = you triggered it; inferred = deduced from a fingerprint/diff — never report inferred as confirmed), optional target, and optional parent_ids (facts this derives from). Use this so negative/neutral observations are written down instead of lost.",
|
|
@@ -66000,6 +66098,35 @@ ${statusLine}` : statusLine },
|
|
|
66000
66098
|
}, async ({ id }) => {
|
|
66001
66099
|
return { content: [{ type: "text", text: JSON.stringify(lineage(id)) }] };
|
|
66002
66100
|
});
|
|
66101
|
+
server.registerTool("surface_add", {
|
|
66102
|
+
title: "Register a discovered attack-surface item",
|
|
66103
|
+
description: "COVERAGE: register a discovered surface item (endpoint/param/host/subdomain/route/class) so the coverage tracker can measure progress. Deduped by kind+ref. Pair with surface_verdict (mark terminal verdict) and coverage (the % done). Use every time recon/param_surface/asset_discovery surfaces a new endpoint, param, host, or class.",
|
|
66104
|
+
inputSchema: {
|
|
66105
|
+
kind: _enum(["endpoint", "param", "host", "subdomain", "route", "class"]).describe("What kind of surface item"),
|
|
66106
|
+
ref: string2().describe("The endpoint/param/host/etc. (e.g. '/api/users', 'id', 'app.example.com')")
|
|
66107
|
+
}
|
|
66108
|
+
}, async ({ kind, ref }) => {
|
|
66109
|
+
const item = surfaceAdd(kind, ref);
|
|
66110
|
+
return { content: [{ type: "text", text: JSON.stringify({ ...item, ...coverageSummary() }) }] };
|
|
66111
|
+
});
|
|
66112
|
+
server.registerTool("surface_verdict", {
|
|
66113
|
+
title: "Mark a terminal verdict on a surface item",
|
|
66114
|
+
description: "COVERAGE: mark a surface item's terminal verdict — confirmed (a verified finding), dead (tested + disproved/blocked), partial (tested, some shapes remain), or skipped (out of scope / tool blocked). An item stays PENDING until it has a verdict; pending items drag the coverage % down. Accepts the item id (SRF-XXXX) or its ref.",
|
|
66115
|
+
inputSchema: {
|
|
66116
|
+
id_or_ref: string2().describe("Surface item id (SRF-XXXX) or its ref"),
|
|
66117
|
+
verdict: _enum(["confirmed", "dead", "partial", "skipped"]).describe("Terminal verdict")
|
|
66118
|
+
}
|
|
66119
|
+
}, async ({ id_or_ref, verdict }) => {
|
|
66120
|
+
const r = surfaceVerdict(id_or_ref, verdict);
|
|
66121
|
+
return { content: [{ type: "text", text: JSON.stringify({ ...r, ...coverageSummary() }) }] };
|
|
66122
|
+
});
|
|
66123
|
+
server.registerTool("coverage", {
|
|
66124
|
+
title: "Coverage % of the discovered attack surface",
|
|
66125
|
+
description: "COVERAGE: return the quantitative progress — total surface items, how many have a terminal verdict, coverage % (terminal/total), pending count, and the breakdown by kind and by verdict. Check this before proving a goal like 'coverage >= 80%'; a goal with a quantitative condition must be checked against this measured pct before prove_goal.",
|
|
66126
|
+
inputSchema: {}
|
|
66127
|
+
}, async () => {
|
|
66128
|
+
return { content: [{ type: "text", text: JSON.stringify(coverageSummary()) }] };
|
|
66129
|
+
});
|
|
66003
66130
|
server.registerTool("hunting_doctrine", {
|
|
66004
66131
|
title: "High-ROI hunting doctrine (sibling rule, A→B, follow-the-money)",
|
|
66005
66132
|
description: "Return the hunting doctrine — the high-ROI heuristics the agent applies while selecting targets/endpoints/classes: the Sibling Rule (check every sibling endpoint — ~30% of paid IDOR/auth bugs), A→B Signal Method, impact-first, follow-the-money, less-saturated classes, new==unreviewed, two-account IDOR test, PoC escalation, credential-proof, CI/CD + SAML/SSO attack surface, 20-minute rotation, plus the always-rejected kill-list. Use when deciding WHAT to hunt next.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "blitzstrike",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.178",
|
|
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": {
|