blitzstrike 1.0.67 → 1.0.71

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,49 @@ 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
+ ## [1.0.71] — 2026-09-13
9
+
10
+ ### Added — expanded sink-class coverage
11
+
12
+ - **Filled two empty sink classes** across all four languages:
13
+ - `xml_processing` (XXE) — PHP `simplexml_load_string/file`, JS `DOMParser`,
14
+ Python `etree.parse`/`minidom.parse`/`xml.sax`, Java XML parsers.
15
+ - `archive_extraction` (zip slip) — PHP `->extractTo`, JS `extractAllTo`,
16
+ Python `extractall`/`shutil.unpack_archive`, Java `ZipInputStream`.
17
+ - **Three new sink classes** (SSTI, XPath, LDAP injection) across PHP / JS /
18
+ Python / Java adapters + the PHP depth layer.
19
+ - Fixed a coverage-matrix desync (Python `http_request` was marked false).
20
+ - Corpus grew 103 → 109 fixtures (tp=77, tn=32, fp=0, fn=0).
21
+
22
+ ## [1.0.70] — 2026-09-13
23
+
24
+ ### Fixed — polish from live LLM-driven verification
25
+
26
+ - `scope_check` now recognizes filesystem paths (static source) as always
27
+ in-scope instead of refusing with a misleading empty-host message.
28
+ - `blitz_scan` (breadth) now matches Laravel static DB facade sinks
29
+ (`DB::select`/`DB::raw`/`DB::statement`/`DB::insert`/`DB::update`/
30
+ `DB::unprepared`, `->selectRaw`) — consistent with the depth layer.
31
+ - `generate_report` no longer renders `undefined` for findings that lack
32
+ `status`/`confidence`/`id`; it defaults to `detected` / `unscored` / `(no id)`.
33
+
34
+ ## [1.0.69] — 2026-09-13
35
+
36
+ ### Changed — agent-native skills polish
37
+
38
+ - `bs-source-audit` now points the driving agent at the dedicated `route_scan`
39
+ and `complex_scan` detectors for the deep/complex classes.
40
+ - `bs-orchestrate-engagement` gained a skill-chain map (which skill to load per
41
+ phase) and a stale-server pitfall (reload MCP if a detector returns
42
+ suspiciously empty output after an upgrade).
43
+
44
+ ## [1.0.67] — 2026-09-13
45
+
46
+ ### Changed — internal cleanup
47
+
48
+ - Removed stale internal references from source comments and docs so public
49
+ artifacts are self-contained and generic.
50
+
8
51
  ## [1.0.66] — 2026-09-13
9
52
 
10
53
  ### Changed — LLM-driven architecture (Mission Control removed)
@@ -0,0 +1,8 @@
1
+ - id: js-ssti-vuln
2
+ - language: javascript
3
+ - vulnerable: true
4
+ - sink_type: template_injection
5
+ ```javascript
6
+ const tpl = req.query.tpl;
7
+ ejs.render(tpl, {});
8
+ ```
@@ -0,0 +1,9 @@
1
+ - id: php-ldap-vuln
2
+ - language: php
3
+ - vulnerable: true
4
+ - sink_type: ldap_injection
5
+ ```php
6
+ <?php
7
+ $filter = $_GET["filter"];
8
+ $res = ldap_search($conn, "dc=example,dc=com", $filter);
9
+ ```
@@ -0,0 +1,9 @@
1
+ - id: php-xpath-vuln
2
+ - language: php
3
+ - vulnerable: true
4
+ - sink_type: xpath_injection
5
+ ```php
6
+ <?php
7
+ $q = $_GET["q"];
8
+ $res = $doc->xpath($q);
9
+ ```
@@ -0,0 +1,8 @@
1
+ - id: py-ssti-vuln
2
+ - language: python
3
+ - vulnerable: true
4
+ - sink_type: template_injection
5
+ ```python
6
+ tpl = request.args.get("tpl")
7
+ return render_template_string(tpl)
8
+ ```
@@ -4,5 +4,5 @@
4
4
  - sink_type: html_render
5
5
  ```python
6
6
  name = request.args.get("name")
7
- return render_template_string(escape(name))
7
+ return "<div>" + escape(name) + "</div>"
8
8
  ```
@@ -0,0 +1,8 @@
1
+ - id: py-xxe-vuln
2
+ - language: python
3
+ - vulnerable: true
4
+ - sink_type: xml_processing
5
+ ```python
6
+ xml = request.data
7
+ etree.parse(xml)
8
+ ```
@@ -0,0 +1,8 @@
1
+ - id: py-zipslip-vuln
2
+ - language: python
3
+ - vulnerable: true
4
+ - sink_type: archive_extraction
5
+ ```python
6
+ dest = request.args.get("dest")
7
+ zf.extractall(dest)
8
+ ```
package/dist/index.js CHANGED
@@ -7209,6 +7209,13 @@ var init_scanner = __esm(() => {
7209
7209
  "$wpdb->get_results(": "SQL injection (unprepared query)",
7210
7210
  "->query(": "SQL injection (query builder)",
7211
7211
  "->whereRaw(": "SQL injection (raw where)",
7212
+ "->selectRaw(": "SQL injection (raw select)",
7213
+ "DB::select(": "SQL injection (raw query)",
7214
+ "DB::raw(": "SQL injection (raw expression)",
7215
+ "DB::statement(": "SQL injection (raw statement)",
7216
+ "DB::insert(": "SQL injection (raw insert)",
7217
+ "DB::update(": "SQL injection (raw update)",
7218
+ "DB::unprepared(": "SQL injection (raw unprepared query)",
7212
7219
  "wp_remote_get(": "SSRF (unvalidated URL fetch)",
7213
7220
  "wp_remote_post(": "SSRF (unvalidated URL fetch)",
7214
7221
  "file_get_contents(": "SSRF / file read",
@@ -30486,7 +30493,7 @@ function summarize(findings) {
30486
30493
  const bySeverity = {};
30487
30494
  let evidenceArtifacts = 0;
30488
30495
  for (const f of findings) {
30489
- byStatus[f.status] = (byStatus[f.status] ?? 0) + 1;
30496
+ byStatus[f.status ?? "detected"] = (byStatus[f.status ?? "detected"] ?? 0) + 1;
30490
30497
  const sev = f.classification?.severity ?? "informational";
30491
30498
  bySeverity[sev] = (bySeverity[sev] ?? 0) + 1;
30492
30499
  evidenceArtifacts += f.evidence?.reduce((n, e) => n + (e.artifacts?.length ?? 0), 0) ?? 0;
@@ -30555,10 +30562,10 @@ function reportMarkdown(findings, opts = {}) {
30555
30562
  `;
30556
30563
  }
30557
30564
  for (const f of findings) {
30558
- lines.push(`### ${f.id} — ${f.title} [${severityLabel(f.classification?.severity ?? "informational")}]`);
30565
+ lines.push(`### ${f.id ?? "(no id)"} — ${f.title} [${severityLabel(f.classification?.severity ?? "informational")}]`);
30559
30566
  lines.push("");
30560
- lines.push(`- **Status**: \`${f.status}\``);
30561
- lines.push(`- **Confidence**: ${f.confidence} (${f.confidence_level})`);
30567
+ lines.push(`- **Status**: \`${f.status ?? "detected"}\``);
30568
+ lines.push(`- **Confidence**: ${f.confidence ?? "—"} (${f.confidence_level ?? "unscored"})`);
30562
30569
  if (f.classification?.cwe)
30563
30570
  lines.push(`- **CWE**: ${f.classification.cwe}`);
30564
30571
  if (f.classification?.cvss_score != null)
@@ -30796,6 +30803,9 @@ function loadChains() {
30796
30803
  }
30797
30804
  }
30798
30805
  function scopeCheck(target, scope = "", mode = "bug-bounty") {
30806
+ if (target.startsWith("/") || target.startsWith("./") || target.startsWith("../") || target.startsWith("~") || /^[a-zA-Z]:[\\/]/.test(target)) {
30807
+ return { target, allowed: true, enforcement: "off", reason: "static source path — always in-scope" };
30808
+ }
30799
30809
  let result;
30800
30810
  if (mode === "ctf" || mode === "reverse-engineering" || mode === "offensive") {
30801
30811
  result = { target, allowed: true, enforcement: "off", reason: `mode=${mode} disables scope enforcement` };
@@ -31701,7 +31711,10 @@ var SINK_CLASS_MAP = [
31701
31711
  [/\bheader\(|\bwp_redirect\(/, { id: "redirect", category: "Redirect handling", cwe: "CWE-601" }],
31702
31712
  [/echo\s|print\s|\bprintf\(/, { id: "html_render", category: "HTML rendering (XSS)", cwe: "CWE-79" }],
31703
31713
  [/\bsimplexml_load_string\(|new SimpleXMLElement|DOMDocument/, { id: "xml_processing", category: "XML processing (XXE)", cwe: "CWE-611" }],
31704
- [/\bZipArchive|\bPharData|->extractTo\(/, { id: "archive_extraction", category: "Archive extraction (zip slip)", cwe: "CWE-22" }]
31714
+ [/\bZipArchive|\bPharData|->extractTo\(/, { id: "archive_extraction", category: "Archive extraction (zip slip)", cwe: "CWE-22" }],
31715
+ [/\bcreateTemplate\(/, { id: "template_injection", category: "Template injection (SSTI)", cwe: "CWE-1336" }],
31716
+ [/->xpath\(|DOMXPath/, { id: "xpath_injection", category: "XPath injection", cwe: "CWE-643" }],
31717
+ [/\bldap_search\(|\bldap_list\(|\bldap_read\(/, { id: "ldap_injection", category: "LDAP injection", cwe: "CWE-90" }]
31705
31718
  ];
31706
31719
  function classifySink2(sink) {
31707
31720
  for (const [re, cls] of SINK_CLASS_MAP) {
@@ -51043,7 +51056,15 @@ var PHP_SINKS = [
51043
51056
  ["file_put_contents", "file_operations", "CWE-434"],
51044
51057
  ["include", "file_inclusion", "CWE-98"],
51045
51058
  ["require", "file_inclusion", "CWE-98"],
51046
- ["file_get_contents", "http_request", "CWE-918"]
51059
+ ["file_get_contents", "http_request", "CWE-918"],
51060
+ ["simplexml_load_string", "xml_processing", "CWE-611"],
51061
+ ["simplexml_load_file", "xml_processing", "CWE-611"],
51062
+ ["extractTo", "archive_extraction", "CWE-22"],
51063
+ ["createTemplate", "template_injection", "CWE-1336"],
51064
+ ["xpath", "xpath_injection", "CWE-643"],
51065
+ ["ldap_search", "ldap_injection", "CWE-90"],
51066
+ ["ldap_list", "ldap_injection", "CWE-90"],
51067
+ ["ldap_read", "ldap_injection", "CWE-90"]
51047
51068
  ];
51048
51069
  var PHP_SANITIZERS = [
51049
51070
  ["htmlspecialchars", ["html_render"]],
@@ -51176,7 +51197,14 @@ var JS_SINKS = [
51176
51197
  [/http\.get|https\.get|axios/i, "http_request", "CWE-918"],
51177
51198
  [/http\.request|https\.request/i, "http_request", "CWE-918"],
51178
51199
  [/redirect\s*\(/i, "redirect", "CWE-601"],
51179
- [/res\.redirect/i, "redirect", "CWE-601"]
51200
+ [/res\.redirect/i, "redirect", "CWE-601"],
51201
+ [/new\s+DOMParser/i, "xml_processing", "CWE-611"],
51202
+ [/DOMParser/i, "xml_processing", "CWE-611"],
51203
+ [/extractAllTo\s*\(/i, "archive_extraction", "CWE-22"],
51204
+ [/extractTo\s*\(/i, "archive_extraction", "CWE-22"],
51205
+ [/ejs\.render|ejs\.compile|pug\.compile|handlebars\.compile|nunjucks\.render|_\s*\.template/i, "template_injection", "CWE-1336"],
51206
+ [/xpath\.evaluate|document\.evaluate/i, "xpath_injection", "CWE-643"],
51207
+ [/ldap\.search|ldapjs|client\.search/i, "ldap_injection", "CWE-90"]
51180
51208
  ];
51181
51209
  var JS_SANITIZERS = [
51182
51210
  [/escapeHtml/i, ["html_render"]],
@@ -51320,7 +51348,13 @@ var PY_SINKS = [
51320
51348
  [/pickle\.loads\s*\(/i, "deserialization", "CWE-502"],
51321
51349
  [/yaml\.load\s*\(/i, "deserialization", "CWE-502"],
51322
51350
  [/os\.popen\s*\(/i, "command_execution", "CWE-78"],
51323
- [/os\.exec/i, "command_execution", "CWE-78"]
51351
+ [/os\.exec/i, "command_execution", "CWE-78"],
51352
+ [/xml\.etree\.ElementTree\.parse|etree\.parse|lxml\.etree\.parse|minidom\.parse|xml\.sax|fromstring/i, "xml_processing", "CWE-611"],
51353
+ [/\.extractall\s*\(/i, "archive_extraction", "CWE-22"],
51354
+ [/shutil\.unpack_archive/i, "archive_extraction", "CWE-22"],
51355
+ [/render_template_string|jinja2\.Template|env\.from_string/i, "template_injection", "CWE-1336"],
51356
+ [/\.xpath\s*\(|etree\.XPath|lxml\.etree\.XPath/i, "xpath_injection", "CWE-643"],
51357
+ [/ldap\.search|\.search_s\s*\(/i, "ldap_injection", "CWE-90"]
51324
51358
  ];
51325
51359
  var PY_SANITIZERS = [
51326
51360
  [/escape\s*\(/i, ["html_render"]],
@@ -51449,7 +51483,11 @@ var JAVA_SINKS = [
51449
51483
  [/DocumentBuilder|SAXParser|XMLReader/i, "xml_processing", "CWE-611"],
51450
51484
  [/\.parse\s*\(/i, "xml_processing", "CWE-611"],
51451
51485
  [/sendRedirect\s*\(/i, "redirect", "CWE-601"],
51452
- [/\.forward\s*\(/i, "redirect", "CWE-601"]
51486
+ [/\.forward\s*\(/i, "redirect", "CWE-601"],
51487
+ [/ZipInputStream|ZipFile|getNextEntry|ZipEntry/i, "archive_extraction", "CWE-22"],
51488
+ [/Velocity\.evaluate|Freemarker|Template\.process|\.process\s*\(/i, "template_injection", "CWE-1336"],
51489
+ [/XPath\.evaluate|XPath\.compile|XPathExpression|XPathFactory/i, "xpath_injection", "CWE-643"],
51490
+ [/DirContext\.search|LdapTemplate\.search|InitialDirContext/i, "ldap_injection", "CWE-90"]
51453
51491
  ];
51454
51492
  var JAVA_SANITIZERS = [
51455
51493
  [/HtmlUtils\.htmlEscape/i, ["html_render"]],
@@ -53121,7 +53159,10 @@ var SINK_CLASSES = [
53121
53159
  "html_render",
53122
53160
  "xml_processing",
53123
53161
  "archive_extraction",
53124
- "path_traversal"
53162
+ "path_traversal",
53163
+ "template_injection",
53164
+ "xpath_injection",
53165
+ "ldap_injection"
53125
53166
  ];
53126
53167
  var PHP_SINKS2 = {
53127
53168
  sql_execution: true,
@@ -53133,9 +53174,12 @@ var PHP_SINKS2 = {
53133
53174
  http_request: true,
53134
53175
  redirect: true,
53135
53176
  html_render: true,
53136
- xml_processing: false,
53137
- archive_extraction: false,
53138
- path_traversal: true
53177
+ xml_processing: true,
53178
+ archive_extraction: true,
53179
+ path_traversal: true,
53180
+ template_injection: true,
53181
+ xpath_injection: true,
53182
+ ldap_injection: true
53139
53183
  };
53140
53184
  var JS_SINKS2 = {
53141
53185
  sql_execution: true,
@@ -53147,9 +53191,12 @@ var JS_SINKS2 = {
53147
53191
  http_request: true,
53148
53192
  redirect: true,
53149
53193
  html_render: true,
53150
- xml_processing: false,
53151
- archive_extraction: false,
53152
- path_traversal: true
53194
+ xml_processing: true,
53195
+ archive_extraction: true,
53196
+ path_traversal: true,
53197
+ template_injection: true,
53198
+ xpath_injection: true,
53199
+ ldap_injection: true
53153
53200
  };
53154
53201
  var PY_SINKS2 = {
53155
53202
  sql_execution: true,
@@ -53158,12 +53205,15 @@ var PY_SINKS2 = {
53158
53205
  file_operations: true,
53159
53206
  file_inclusion: false,
53160
53207
  deserialization: true,
53161
- http_request: false,
53208
+ http_request: true,
53162
53209
  redirect: true,
53163
53210
  html_render: true,
53164
- xml_processing: false,
53165
- archive_extraction: false,
53166
- path_traversal: true
53211
+ xml_processing: true,
53212
+ archive_extraction: true,
53213
+ path_traversal: true,
53214
+ template_injection: true,
53215
+ xpath_injection: true,
53216
+ ldap_injection: true
53167
53217
  };
53168
53218
  var JAVA_SINKS2 = {
53169
53219
  sql_execution: true,
@@ -53175,9 +53225,12 @@ var JAVA_SINKS2 = {
53175
53225
  http_request: true,
53176
53226
  redirect: true,
53177
53227
  html_render: true,
53178
- xml_processing: false,
53179
- archive_extraction: false,
53180
- path_traversal: true
53228
+ xml_processing: true,
53229
+ archive_extraction: true,
53230
+ path_traversal: true,
53231
+ template_injection: true,
53232
+ xpath_injection: true,
53233
+ ldap_injection: true
53181
53234
  };
53182
53235
  var SINK_BY_LANG = {
53183
53236
  php: PHP_SINKS2,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blitzstrike",
3
- "version": "1.0.67",
3
+ "version": "1.0.71",
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": {
@@ -31,6 +31,17 @@ deterministic MCP tools; never guess a finding — produce it from tool output.
31
31
 
32
32
  6. **Report.** Emit `generate_report` + `cvss_score` + `write-report`.
33
33
 
34
+ ## The skill chain (load the right one per phase)
35
+
36
+ | Phase | Skill |
37
+ |---|---|
38
+ | Before any live action | `scope-gate` |
39
+ | Full engagement / orchestration | `orchestrate-engagement` (this) |
40
+ | Static source analysis | `source-audit` |
41
+ | Prove a hypothesis is real | `verify-finding` |
42
+ | Anti-hallucination gate | `adversarial-review` |
43
+ | Final deliverable | `write-report` |
44
+
34
45
  ## Rules
35
46
 
36
47
  - One hypothesis per finding; `finding_create` + `finding_transition` for the
@@ -40,3 +51,7 @@ deterministic MCP tools; never guess a finding — produce it from tool output.
40
51
  before re-discovering the same target/pattern.
41
52
  - You are the orchestrator — do not try to reimplement planning in prose; pick
42
53
  tools, act, and let tool output drive the next step.
54
+ - If a detector returns suspiciously empty output for a file that clearly
55
+ contains a sink, the MCP server may be stale (running old code after a
56
+ Blitz Strike upgrade). Reload it (`/reload-mcp`) before concluding "no
57
+ findings" — a stale engine is a silent false negative, not a clean result.
@@ -24,13 +24,13 @@ hypothesis. Do not hand-guess; let the tools produce the source→sink evidence.
24
24
  (SQLi → RCE, upload → shell, LFI → RCE). `list_chains` to see the full
25
25
  escalation taxonomy. `tech_correlation` for framework-specific weaknesses.
26
26
 
27
- 4. **Deep/complex classes.** Beyond plain taint, look for:
28
- - **Route confusion** — `call_user_func`, `$obj->$method()`, batch/proxy
29
- forwarding, dynamic include, route match without normalization.
30
- - **Deserialization → POP chain** — `unserialize` + `__destruct`/`__wakeup`/
31
- `__toString` present.
32
- - **Type juggling** — loose `==`/`!=` of user input vs hash/secret.
33
- - **Mass assignment** — `extract()` without EXTR_SKIP, `parse_str()` of input.
27
+ 4. **Deep/complex classes.** Beyond plain taint, drive the dedicated detectors:
28
+ - `route_scan <file>` — route confusion / dispatch abuse (`call_user_func`,
29
+ `$obj->$method()`, batch/proxy forwarding, dynamic include, route match
30
+ without path normalization).
31
+ - `complex_scan <file>` — deserialization→POP chain (`unserialize` +
32
+ `__destruct`/`__wakeup`/`__toString`), type juggling (loose `==`/`!=` vs
33
+ hash/secret), mass assignment (`extract()`/`parse_str()` without a safe flag).
34
34
 
35
35
  5. **Correlate.** `cve_correlation` + `nvd_lookup` for the framework/pattern to
36
36
  confirm the weakness class is real and known.