blitzstrike 2.4.69 → 2.4.70
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 +134 -3
- 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.70] — 2026-09-14
|
|
9
|
+
|
|
10
|
+
### Added — Per-finding per-scope reports (HackerOne-grade)
|
|
11
|
+
|
|
12
|
+
- `generate_report` gains `mode=per_finding`: writes ONE HackerOne-grade report
|
|
13
|
+
PER finding into a per-scope directory (bug-bounty convention — one submission
|
|
14
|
+
per vulnerability):
|
|
15
|
+
```
|
|
16
|
+
reports/<scope_slug>/
|
|
17
|
+
findings/<severity>_<vuln_slug>.md (Summary / Root Cause / Steps to
|
|
18
|
+
Reproduce / Impact / Remediation /
|
|
19
|
+
References / Evidence + severity tier)
|
|
20
|
+
SUMMARY.md (index + severity counts)
|
|
21
|
+
metadata.json (structured, automation-friendly)
|
|
22
|
+
```
|
|
23
|
+
- `findingReport(f)` + `perFindingReports(findings, opts)` exported from report.ts;
|
|
24
|
+
the aggregate mode stays the default. Each per-finding report carries the
|
|
25
|
+
severity→priority tier (critical=P1 … informational=P5), CWE, status, target, and
|
|
26
|
+
attack chain in a metadata table.
|
|
27
|
+
|
|
8
28
|
## [2.4.69] — 2026-09-14
|
|
9
29
|
|
|
10
30
|
### Added — Supply-chain detectors (dependency confusion + ML model loading)
|
package/dist/index.js
CHANGED
|
@@ -35185,6 +35185,129 @@ function saveReport(content, opts = {}) {
|
|
|
35185
35185
|
writeFileSync2(path, content, "utf8");
|
|
35186
35186
|
return { path, dir: REPORT_DIR, filename };
|
|
35187
35187
|
}
|
|
35188
|
+
var PRIORITY = { critical: "P1", high: "P2", medium: "P3", low: "P4", informational: "P5" };
|
|
35189
|
+
function findingSlug(title) {
|
|
35190
|
+
return title.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 60) || "finding";
|
|
35191
|
+
}
|
|
35192
|
+
function findingReport(f) {
|
|
35193
|
+
const w = findingWriteup(f);
|
|
35194
|
+
const sev = f.classification?.severity ?? "informational";
|
|
35195
|
+
const cwe = f.classification?.cwe ?? "";
|
|
35196
|
+
const cweName = f.classification?.cwe_name ?? "";
|
|
35197
|
+
const target = [f.target?.host, f.target?.endpoint].filter(Boolean).join("");
|
|
35198
|
+
const cvss = f.classification?.cvss_score != null ? ` — CVSS ${f.classification.cvss_score}` : "";
|
|
35199
|
+
const lines = [];
|
|
35200
|
+
lines.push(`# ${f.title}`);
|
|
35201
|
+
lines.push("");
|
|
35202
|
+
lines.push("| Field | Value |");
|
|
35203
|
+
lines.push("|-------|-------|");
|
|
35204
|
+
lines.push(`| **Severity** | ${sev} (${PRIORITY[sev] ?? "P4"})${cvss} |`);
|
|
35205
|
+
if (cwe)
|
|
35206
|
+
lines.push(`| **CWE** | ${cwe}${cweName ? ` — ${cweName}` : ""} |`);
|
|
35207
|
+
lines.push(`| **Status** | ${f.status} |`);
|
|
35208
|
+
if (target)
|
|
35209
|
+
lines.push(`| **Target** | ${target} |`);
|
|
35210
|
+
if (f.chain?.name)
|
|
35211
|
+
lines.push(`| **Attack chain** | ${f.chain.name} |`);
|
|
35212
|
+
lines.push("");
|
|
35213
|
+
lines.push("## Summary");
|
|
35214
|
+
lines.push("");
|
|
35215
|
+
lines.push(w.description);
|
|
35216
|
+
lines.push("");
|
|
35217
|
+
lines.push("## Root Cause");
|
|
35218
|
+
lines.push("");
|
|
35219
|
+
lines.push(w.root_cause);
|
|
35220
|
+
lines.push("");
|
|
35221
|
+
lines.push("## Steps to Reproduce");
|
|
35222
|
+
lines.push("");
|
|
35223
|
+
for (const step of w.reproduction)
|
|
35224
|
+
lines.push(`1. ${step}`);
|
|
35225
|
+
lines.push("");
|
|
35226
|
+
lines.push("## Impact");
|
|
35227
|
+
lines.push("");
|
|
35228
|
+
lines.push(w.impact);
|
|
35229
|
+
lines.push("");
|
|
35230
|
+
lines.push("## Remediation");
|
|
35231
|
+
lines.push("");
|
|
35232
|
+
lines.push(w.remediation);
|
|
35233
|
+
lines.push("");
|
|
35234
|
+
lines.push("## References");
|
|
35235
|
+
lines.push("");
|
|
35236
|
+
for (const ref of w.references)
|
|
35237
|
+
lines.push(`- ${ref}`);
|
|
35238
|
+
lines.push("");
|
|
35239
|
+
if ((f.evidence?.length ?? 0) > 0) {
|
|
35240
|
+
lines.push("## Evidence");
|
|
35241
|
+
lines.push("");
|
|
35242
|
+
for (const ev of f.evidence) {
|
|
35243
|
+
const desc = ev.description ?? ev.type ?? "evidence";
|
|
35244
|
+
lines.push(`- [${ev.type ?? "record"}] ${desc}`);
|
|
35245
|
+
}
|
|
35246
|
+
lines.push("");
|
|
35247
|
+
}
|
|
35248
|
+
return lines.join(`
|
|
35249
|
+
`);
|
|
35250
|
+
}
|
|
35251
|
+
function perFindingReports(findings, opts = {}) {
|
|
35252
|
+
const slug = slugify2(opts.scope ?? opts.title ?? "engagement");
|
|
35253
|
+
const dir = join10(REPORT_DIR, slug);
|
|
35254
|
+
const findingsDir = join10(dir, "findings");
|
|
35255
|
+
mkdirSync5(findingsDir, { recursive: true });
|
|
35256
|
+
const files = [];
|
|
35257
|
+
for (const f of findings) {
|
|
35258
|
+
const sev = f.classification?.severity ?? "informational";
|
|
35259
|
+
const filename = `${sev}_${findingSlug(f.title)}.md`;
|
|
35260
|
+
const path = join10(findingsDir, filename);
|
|
35261
|
+
writeFileSync2(path, findingReport(f), "utf8");
|
|
35262
|
+
files.push({ path, filename, severity: sev, title: f.title });
|
|
35263
|
+
}
|
|
35264
|
+
const bySeverity = {};
|
|
35265
|
+
for (const f of findings) {
|
|
35266
|
+
const s = f.classification?.severity ?? "informational";
|
|
35267
|
+
bySeverity[s] = (bySeverity[s] ?? 0) + 1;
|
|
35268
|
+
}
|
|
35269
|
+
const summaryLines = [];
|
|
35270
|
+
summaryLines.push(`# ${opts.title ?? "Engagement"} — Findings Summary`);
|
|
35271
|
+
summaryLines.push("");
|
|
35272
|
+
if (opts.scope)
|
|
35273
|
+
summaryLines.push(`**Scope:** ${opts.scope}`);
|
|
35274
|
+
summaryLines.push(`**Total findings:** ${findings.length}`);
|
|
35275
|
+
summaryLines.push("");
|
|
35276
|
+
summaryLines.push("| Severity | Count |");
|
|
35277
|
+
summaryLines.push("|----------|-------|");
|
|
35278
|
+
for (const [s, n] of Object.entries(bySeverity).sort((a, b) => (PRIORITY[a[0]] ?? "P9") < (PRIORITY[b[0]] ?? "P9") ? -1 : 1)) {
|
|
35279
|
+
summaryLines.push(`| ${s} | ${n} |`);
|
|
35280
|
+
}
|
|
35281
|
+
summaryLines.push("");
|
|
35282
|
+
summaryLines.push("| # | Finding | Severity | File |");
|
|
35283
|
+
summaryLines.push("|---|---------|----------|------|");
|
|
35284
|
+
files.forEach((fl, i) => {
|
|
35285
|
+
summaryLines.push(`| ${i + 1} | ${fl.title} | ${fl.severity} | [${fl.filename}](findings/${fl.filename}) |`);
|
|
35286
|
+
});
|
|
35287
|
+
summaryLines.push("");
|
|
35288
|
+
const summaryPath = join10(dir, "SUMMARY.md");
|
|
35289
|
+
writeFileSync2(summaryPath, summaryLines.join(`
|
|
35290
|
+
`), "utf8");
|
|
35291
|
+
const meta = {
|
|
35292
|
+
title: opts.title ?? "Engagement",
|
|
35293
|
+
scope: opts.scope ?? null,
|
|
35294
|
+
version: opts.version ?? null,
|
|
35295
|
+
total_findings: findings.length,
|
|
35296
|
+
by_severity: bySeverity,
|
|
35297
|
+
findings: files.map((fl) => ({ title: fl.title, severity: fl.severity, file: join10("findings", fl.filename) }))
|
|
35298
|
+
};
|
|
35299
|
+
const metadataPath = join10(dir, "metadata.json");
|
|
35300
|
+
writeFileSync2(metadataPath, JSON.stringify(meta, null, 2) + `
|
|
35301
|
+
`, "utf8");
|
|
35302
|
+
return {
|
|
35303
|
+
dir,
|
|
35304
|
+
findings_dir: findingsDir,
|
|
35305
|
+
summary_path: summaryPath,
|
|
35306
|
+
metadata_path: metadataPath,
|
|
35307
|
+
total: findings.length,
|
|
35308
|
+
files
|
|
35309
|
+
};
|
|
35310
|
+
}
|
|
35188
35311
|
|
|
35189
35312
|
// src/sarif.ts
|
|
35190
35313
|
init_version();
|
|
@@ -59694,7 +59817,7 @@ function createServer() {
|
|
|
59694
59817
|
instructions: "Blitz Strike — deterministic security-audit toolbelt. You reason; its tools do the deterministic work (scan, taint, verify, evidence).\\n\\n" + "FIRST ACTION (when the user says test / scan / audit / engagement / pentest <URL or path>):\\n" + "- Call run_engagement(target) — or run_autonomous(target) to also get escalation paths. ONE call runs the whole engagement (recon -> sweep -> checks -> report).\\n" + "- NEVER do manual live_recon / blitz_scan first, and never fall back to manual probing. Manual tools are ONLY for follow-up AFTER run_engagement, or when the user names a specific sub-step.\\n\\n" + "RULES (never violate):\\n" + `- A hit is a HYPOTHESIS; live verification (marker + negative control) is the verdict. Never report unverified.
|
|
59695
59818
|
` + `- run_engagement / run_autonomous return status DETECTED (NOT "complete") — that is the signal to VERIFY. After detection you MUST strike_verify (or verify_file_read for CWE-22, drive_devtools for DOM/JS precision) on each finding, then generate_report. Detection without verification is NOT a deliverable.
|
|
59696
59819
|
` + "- scope_check is intel-only, never gates. No scope = proceed (repo disclaimer carries responsibility). No authorization gate — hunt the target you are given.\\n" + "- strike_verify + live checks AUTO-attempt WAF bypass. Don't report 'needs bypass' without re-probing.\\n" + "- NEVER ask 'should I continue?' / 'say the word' / 'want me to pursue' / 'next?' — that is a hard violation. Execute the full chain autonomously until COMPLETE. COMPLETE means every lead verified/blocked AND every reachable chain step executed or blocked (no deferred escalations). Pause only: destructive/DoS consent, external block (OTP/cred), or genuine COMPLETE.\\n" + "- One hard stop: malicious/third-party infra ('find the actor') -> static + takedown only.\\n" + "- FINDING LIFECYCLE (stateful — never loop stateless tools): advance findings via finding_create -> strike_verify -> strike_resolve. finding_transition now takes a FULL finding JSON + target status and RETURNS the updated finding (pass the object, never a status string); a bad move returns 'illegal transition' + the legal next states. confidence_score is DETERMINISTIC (same factors -> same score) — call it ONCE, never retry; it changes nothing. SELF-HARDENING: when a finding is verified false_positive, call capture_false_positive(code, language, detector, note) with the triggering code so the detector gets more precise every engagement. PROOF-OBLIGATION LOOP (the structure, not a prompt): every pending hypothesis is an OPEN obligation. Drive the engagement as a single-decision loop — next_obligation() -> run the ONE test it names -> discharge_obligation(id, status=verified|refuted|blocked). COMPLETE is gated on zero open obligations (obligations().complete); generate_report warns while any remain. You hold NO plan in your head — the ledger is the single source of truth for what work remains.\\n\\n" + "CHAIN DECISIONS (a confirmed finding is the START, not the end):\\n" + "- For each confirmed finding, enumerate follow-ups with list_chains + chain_links: ESCALATE (what it becomes), CHAIN (compose with other findings), BYPASS, PIVOT (new surface now reachable).\\n" + "- Ask the chain-aware question: 'I found X -> what can I NOW read / do / access?' e.g. SQLi -> query the DB for credentials AND for the Werkzeug console PIN / secrets / source; LFI -> read configs, keys, PIN inputs; cred dump -> crack offline -> authenticate -> privileged actions.\\n" + "- Every follow-up is a HYPOTHESIS — verify each before it enters the report. Don't stop at 'found SQLi'; follow where the chain leads.\\n" + "- EXECUTE follow-ups NOW, not as 'next phase': any leaked source/error -> scan_leaked_source(text) to enumerate sinks (eval/exec/SECRET_KEY/creds) then exploit each; dumped hashes -> crack_hash(hash) now; hidden-content IDOR -> test the direct route. A 'next chain' you write is a TODO — run it, never leave it as a recommendation.\\n\\n" + "- DOCTRINE — 'if you can continue, why not? if possible, why not try?': a chain step you CAN execute is one you MUST execute. A PREREQUISITE is a chain step, NOT a separate engagement — e.g. a CORS->session-theft chain needing 'a foothold on any subdomain (XSS / dangling-DNS takeover)' means CHECK for it NOW: resolve every allowlisted subdomain and test each for dangling delegation (NXDOMAIN, unclaimed S3/bucket, dangling SaaS CNAME) + probe for XSS — do NOT write 'dangling-DNS audit is the next engagement'. Declaring COMPLETE while a reachable chain step is deferred is a violation.\\n\\n" + `DELIVERABLE + PERSISTENCE (recon is INPUT, not output):
|
|
59697
|
-
` + `- The deliverable is a HackerOne-grade FINDING report via generate_report, NEVER a hand-written recon/surface map. Recon is input; confirmed findings are the output.
|
|
59820
|
+
` + `- The deliverable is a HackerOne-grade FINDING report via generate_report, NEVER a hand-written recon/surface map. Recon is input; confirmed findings are the output. For one report PER finding under a per-scope directory (bug-bounty convention: one submission per vulnerability), call generate_report with mode=per_finding — it writes reports/<scope_slug>/findings/<severity>_<vuln>.md (one HackerOne-grade report each) plus SUMMARY.md + metadata.json.
|
|
59698
59821
|
` + `- After recon, VERIFY every lead before it enters the report: strike_verify (marker + negative control) for HTTP, browser_validate for DOM/JS. A lead is a HYPOTHESIS until verified.
|
|
59699
59822
|
` + `- A hard block (Cloudflare/WAF/IP-block/captcha) is NOT the end: mark the finding blocked + note the required vantage (residential / authorized / correct-SNI / --resolve direct-to-origin), then CONTINUE to the next lead (origin bypass, non-prod cluster, mobile APK, subdomain).
|
|
59700
59823
|
` + `- Keep trying every lead AND every chain step until each is verified/executed or blocked, THEN generate_report. Never deliver a bare surface map, and never stop at 'found X' when X enables more.
|
|
@@ -61452,9 +61575,10 @@ ${statusLine}` : statusLine },
|
|
|
61452
61575
|
findings: string2().describe("JSON array of Finding objects"),
|
|
61453
61576
|
format: _enum(["markdown", "json"]).optional().describe("Report format"),
|
|
61454
61577
|
title: string2().optional().describe("Report title"),
|
|
61455
|
-
scope: string2().optional().describe("Scope description")
|
|
61578
|
+
scope: string2().optional().describe("Scope description (also the per-scope directory slug in per_finding mode)"),
|
|
61579
|
+
mode: _enum(["aggregate", "per_finding"]).optional().describe("aggregate (single report, default) / per_finding (one HackerOne-grade report PER finding into a per-scope directory)")
|
|
61456
61580
|
}
|
|
61457
|
-
}, async ({ findings, format, title, scope }) => {
|
|
61581
|
+
}, async ({ findings, format, title, scope, mode }) => {
|
|
61458
61582
|
let list;
|
|
61459
61583
|
try {
|
|
61460
61584
|
list = JSON.parse(findings);
|
|
@@ -61463,6 +61587,13 @@ ${statusLine}` : statusLine },
|
|
|
61463
61587
|
}
|
|
61464
61588
|
const fmt = format ?? "markdown";
|
|
61465
61589
|
const opts = { title, scope, version: VERSION };
|
|
61590
|
+
if (mode === "per_finding") {
|
|
61591
|
+
const layout = perFindingReports(list, opts);
|
|
61592
|
+
const open = openCount();
|
|
61593
|
+
const gate = open > 0 ? `
|
|
61594
|
+
⚠ PROOF-OBLIGATION GATE: ${open} open obligation(s) remain. Discharge them before declaring complete.` : "";
|
|
61595
|
+
return { content: [{ type: "text", text: JSON.stringify({ ...layout, note: "One HackerOne-grade report per finding, under a per-scope directory (findings/ + SUMMARY.md + metadata.json)." + gate }) }] };
|
|
61596
|
+
}
|
|
61466
61597
|
const out = fmt === "json" ? reportJson(list, opts) : reportMarkdown(list, opts);
|
|
61467
61598
|
const saved = saveReport(out, { title, scope, version: VERSION, format: fmt });
|
|
61468
61599
|
const open = openCount();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "blitzstrike",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.70",
|
|
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": {
|