blitzstrike 2.4.47 → 2.4.48

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,24 @@ 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.48] — 2026-09-14
9
+
10
+ ### Changed — Precision + consistency (traced to WP core dispatch)
11
+
12
+ - Grounded the authz/nonce rules in the WordPress core dispatch: `wp_ajax_*` and
13
+ `admin_post_*` fire ONLY when `is_user_logged_in()`, while `*_nopriv_*` fire
14
+ unauthenticated. `missing_authz` is now scoped to nopriv handlers that perform
15
+ a state-changing/privileged operation.
16
+ - Added a DANGEROUS_OP_RE gate: `missing_nonce`/`missing_authz` only fire when
17
+ the handler actually performs a WRITE (option/meta/user/post/comment writes,
18
+ file upload/write, `$wpdb->query/insert/update/delete`, `wp_mail`, `wp_redirect`).
19
+ Read-only handlers (list/search/get) are no longer flagged — removes the CSRF/
20
+ authz false-positive storm (forminator 90→16, elementor 11→4, wp-fastest-cache
21
+ 15→1).
22
+ - Removed `is_admin()` / `wp_doing_ajax()` from the auth surface — they are
23
+ request-context checks, not authorization (treating them as auth caused false
24
+ negatives).
25
+
8
26
  ## [2.4.47] — 2026-09-14
9
27
 
10
28
  ### Changed — WordPress integration coverage is now COMPLETE (class-method + direct handlers)
package/dist/index.js CHANGED
@@ -56478,8 +56478,9 @@ function handlerName(expr) {
56478
56478
  return null;
56479
56479
  }
56480
56480
  var INDIRECT_AUTH = /\b[a-zA-Z0-9_]*(auth|permission|cap|nonce|can_|check|verify|allow)[a-zA-Z0-9_]*\s*\(/;
56481
- var AUTH_RE = /current_user_can|is_user_logged_in|is_admin\b|is_super_admin|current_user_can_edit_post|authorize|wp_doing_ajax/;
56481
+ var AUTH_RE = /current_user_can|is_user_logged_in|is_super_admin|current_user_can_edit_post|authorize/;
56482
56482
  var NONCE_RE = /wp_verify_nonce|check_ajax_referer|check_admin_referer|verify_nonce/;
56483
+ var DANGEROUS_OP_RE = /\b(update_option|add_option|delete_option|update_site_option|delete_site_option|update_post_meta|add_post_meta|delete_post_meta|update_user_meta|add_user_meta|delete_user_meta|update_metadata|add_metadata|delete_metadata|set_transient|delete_transient|wp_insert_post|wp_update_post|wp_delete_post|wp_trash_post|wp_untrash_post|wp_insert_comment|wp_update_comment|wp_delete_comment|wp_insert_user|wp_update_user|wp_delete_user|wp_create_user|wp_set_current_user|set_user_role|wp_set_auth_cookie|wp_mail|wp_new_user_notification|wp_handle_upload|move_uploaded_file|wp_upload_bits|wp_set_object_terms|wp_set_post_terms|wp_schedule_event|wp_clear_scheduled_hook|wp_redirect|file_put_contents|unlink|rename|wpdb->query|wpdb->insert|wpdb->update|wpdb->delete|wpdb->replace)\s*\(/;
56483
56484
  function detectWpAuthz(code, file, out) {
56484
56485
  const ajaxRe = /add_action\s*\(\s*['"](wp_ajax(?:_nopriv)?_\w+)['"]\s*,\s*(.+?)\s*\)/g;
56485
56486
  let m;
@@ -56494,12 +56495,13 @@ function detectWpAuthz(code, file, out) {
56494
56495
  continue;
56495
56496
  const hasCap = AUTH_RE.test(body) || INDIRECT_AUTH.test(body);
56496
56497
  const hasNonce = NONCE_RE.test(body);
56498
+ const dangerous = DANGEROUS_OP_RE.test(body);
56497
56499
  const line = lineNoOf(code, m.index);
56498
- if (nopriv && !hasCap) {
56499
- out.push({ file, line, type: "missing_authz", category: "Missing capability check (unauthenticated AJAX handler)", severity: "high", evidence: `add_action('${hook}', ...)`, detail: `Unauthenticated AJAX handler '${handler}()' performs no current_user_can()/authorization check — any unauthenticated visitor can trigger it (auth bypass / privilege escalation).` });
56500
+ if (nopriv && !hasCap && dangerous) {
56501
+ out.push({ file, line, type: "missing_authz", category: "Missing capability check (unauthenticated AJAX handler)", severity: "high", evidence: `add_action('${hook}', ...)`, detail: `Unauthenticated AJAX handler '${handler}()' performs a privileged/state-changing operation with no current_user_can()/authorization check — auth bypass / privilege escalation.` });
56500
56502
  }
56501
- if (!hasNonce) {
56502
- out.push({ file, line, type: "missing_nonce", category: "Missing nonce verification", severity: "medium", evidence: `add_action('${hook}', ...)`, detail: `AJAX handler '${handler}()' does not verify a nonce (wp_verify_nonce / check_ajax_referer) — CSRF.` });
56503
+ if (!hasNonce && dangerous) {
56504
+ out.push({ file, line, type: "missing_nonce", category: "Missing nonce verification", severity: "medium", evidence: `add_action('${hook}', ...)`, detail: `AJAX handler '${handler}()' performs a state-changing operation without nonce verification (wp_verify_nonce / check_ajax_referer) — CSRF.` });
56503
56505
  }
56504
56506
  }
56505
56507
  const adminRe = /add_action\s*\(\s*['"](admin_post(?:_nopriv)?_\w+)['"]\s*,\s*(.+?)\s*\)/g;
@@ -56514,12 +56516,13 @@ function detectWpAuthz(code, file, out) {
56514
56516
  continue;
56515
56517
  const hasCap = AUTH_RE.test(body) || INDIRECT_AUTH.test(body);
56516
56518
  const hasNonce = NONCE_RE.test(body);
56519
+ const dangerous = DANGEROUS_OP_RE.test(body);
56517
56520
  const line = lineNoOf(code, m.index);
56518
- if (nopriv && !hasCap) {
56519
- out.push({ file, line, type: "missing_authz", category: "Missing capability check (unauthenticated admin-post handler)", severity: "high", evidence: `add_action('${hook}', ...)`, detail: `Unauthenticated admin-post handler '${handler}()' has no authorization check — auth bypass / privilege escalation.` });
56521
+ if (nopriv && !hasCap && dangerous) {
56522
+ out.push({ file, line, type: "missing_authz", category: "Missing capability check (unauthenticated admin-post handler)", severity: "high", evidence: `add_action('${hook}', ...)`, detail: `Unauthenticated admin-post handler '${handler}()' performs a privileged/state-changing operation with no authorization check — auth bypass / privilege escalation.` });
56520
56523
  }
56521
- if (!hasNonce) {
56522
- out.push({ file, line, type: "missing_nonce", category: "Missing nonce verification", severity: "medium", evidence: `add_action('${hook}', ...)`, detail: `admin-post handler '${handler}()' does not verify a nonce — CSRF.` });
56524
+ if (!hasNonce && dangerous) {
56525
+ out.push({ file, line, type: "missing_nonce", category: "Missing nonce verification", severity: "medium", evidence: `add_action('${hook}', ...)`, detail: `admin-post handler '${handler}()' performs a state-changing operation without nonce verification — CSRF.` });
56523
56526
  }
56524
56527
  }
56525
56528
  const restRe = /register_rest_route\s*\(\s*['"]([^'"]+)['"]\s*,\s*['"]([^'"]+)['"]/g;
@@ -56543,11 +56546,12 @@ function detectWpAuthz(code, file, out) {
56543
56546
  continue;
56544
56547
  const hasCap = AUTH_RE.test(body) || INDIRECT_AUTH.test(body);
56545
56548
  const hasNonce = NONCE_RE.test(body);
56549
+ const dangerous = DANGEROUS_OP_RE.test(body);
56546
56550
  const line = lineNoOf(code, m.index);
56547
- if (!hasNonce) {
56548
- out.push({ file, line, type: "missing_nonce", category: "Missing nonce verification (direct request handler)", severity: "medium", evidence: `add_action('${hook}', ...)`, detail: `Request handler '${handler}()' (on '${hook}') reads request input without nonce verification — CSRF.` });
56551
+ if (!hasNonce && dangerous) {
56552
+ out.push({ file, line, type: "missing_nonce", category: "Missing nonce verification (direct request handler)", severity: "medium", evidence: `add_action('${hook}', ...)`, detail: `Request handler '${handler}()' (on '${hook}') performs a state-changing operation without nonce verification — CSRF.` });
56549
56553
  }
56550
- if (!hasCap && /(update_option|add_option|delete_option|wp_insert_post|wp_update_post|wp_delete_post|update_user_meta|delete_user_meta|wp_set_current_user|wp_mail|wp_handle_upload|move_uploaded_file|wp_delete_user|add_user|wp_create_user|set_user_role|wp_redirect\s*\(\s*['"]admin)/.test(body)) {
56554
+ if (!hasCap && dangerous) {
56551
56555
  out.push({ file, line, type: "missing_authz", category: "Missing capability check (direct request handler)", severity: "high", evidence: `add_action('${hook}', ...)`, detail: `Request handler '${handler}()' (on '${hook}') performs a privileged/state-changing operation with no capability check — auth bypass / privilege escalation.` });
56552
56556
  }
56553
56557
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blitzstrike",
3
- "version": "2.4.47",
3
+ "version": "2.4.48",
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": {