blitzstrike 2.4.179 → 2.4.181

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,30 @@ 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.180] — 2026-10-11
9
+
10
+ ### Changed — goal decomposition corrected (goal = deliverable, not process)
11
+
12
+ - `decompose_goal` now registers the goal as ONE final deliverable (optional
13
+ vulnclass) and returns the decomposition rules + the six-phase PROCESS plan as
14
+ a reference — the process (recon→report) is the HOW and is no longer registered
15
+ as goals. `goal_set` accepts a `vulnclass` tag.
16
+
17
+ ### Changed — constraint self-containment + out-of-scope fact
18
+
19
+ - Constraints must be self-contained (replace pronouns with the concrete host/port);
20
+ a new target discovered outside the constraints is recorded as an out-of-scope
21
+ fact and skipped, never authorized.
22
+
23
+ ### Added — 4 doctrine rules
24
+
25
+ - `constraint_self_contained`, `record_is_memory` (write-back is anti-compaction
26
+ long-term memory — record immediately, only increments), `wrapup_highest_priority`
27
+ (land conclusions then stop), `high_value_surface` (parsing/charset, upload,
28
+ (de)serialization, cache race, TOCTOU, type confusion, mass assignment),
29
+ `serial_chain_discipline` (each chain step consumes the prior step's REAL output),
30
+ `compression_discipline` (synthesize causally, preserve observed/inferred + source ids).
31
+
8
32
  ## [2.4.179] — 2026-10-11
9
33
 
10
34
  ### Added — WordPress P1-P6 vulnerability pattern taxonomy
package/dist/index.js CHANGED
@@ -63774,6 +63774,36 @@ var HUNTING_DOCTRINE = [
63774
63774
  id: "observed_vs_inferred",
63775
63775
  title: "Observed vs Inferred — Never Upgrade Inferred to Confirmed",
63776
63776
  rule: "Tag every conclusion with its confidence honestly: OBSERVED (you directly triggered it and hold the request/response or command output) vs INFERRED (you deduced it from a fingerprint/version/diff/phenomenon without actually triggering it). A version/CVE match, a 'looks injectable' param, or a patch-diff inference is INFERRED and must never be reported as a confirmed finding — record it as a hypothesis and verify it live (strike_verify / OOB / a clean oracle) before it can claim confirmed. Disproof is worth as much as proof: an honest dead verdict is a deliverable, an overstated inferred-as-confirmed is a retraction waiting to happen."
63777
+ },
63778
+ {
63779
+ id: "constraint_self_contained",
63780
+ title: "Constraints Are Self-Contained; New Target Outside Them Is Not Authorization",
63781
+ rule: "Every operation constraint MUST be self-contained: replace 'this target' / 'current port' / 'this host' with the CONCRETE host/port/domain, because constraints are injected into later prompts standalone and a pronoun means nothing out of context. And a new target/port/host you discover OUTSIDE the active constraints is NOT authorization: record it as an out-of-scope fact (record_fact, confidence=observed) and skip — never derive an intent or action for it, and never widen a subdomain up to its root domain unless the user explicitly named the whole root."
63782
+ },
63783
+ {
63784
+ id: "record_is_memory",
63785
+ title: "Write-Back Is Your Long-Term Memory — Record Immediately, Only Increments",
63786
+ rule: "Persist every result IMMEDIATELY as you produce it — never accumulate findings in your head or in a scratch note to save for the end (a session can be cut short and everything un-persisted is lost; only what is written down survives). Written records (finding_create / record_fact / surface_add / asset_discovery) are your anti-compaction long-term memory, not just bookkeeping. Write ONLY INCREMENTS: before recording, scan the existing ledger (list_facts / list_findings / coverage) and record only what is NEW — re-wording an existing conclusion just bloats state and misleads you into thinking you made progress. A conclusion that merely corroborates an existing one adds nothing and should not be re-recorded."
63787
+ },
63788
+ {
63789
+ id: "wrapup_highest_priority",
63790
+ title: "Wrap-Up Is the Highest Priority — Land Conclusions, Then Stop",
63791
+ rule: "When you receive a wrap-up/finish signal (or self-judge the goal met / all reasonable routes exhausted), STOP all probing and commands IMMEDIATELY — 'continue exploring / try once more / exhaust this chain / wait for a command result' are all OVERRIDDEN by the wrap-up signal. Land everything still in flight first: write back every un-persisted conclusion (findings, facts, surface verdicts, coverage), then produce a concise plain-language summary of what was achieved, which routes were taken, which findings are confirmed (with PoC locations), and which directions are blocked and why. Report only what was actually done — never pad the wrap-up with unverified 'maybe' leads."
63792
+ },
63793
+ {
63794
+ id: "high_value_surface",
63795
+ title: "High-Value Attack Surface — The Often-Overlooked Faces",
63796
+ rule: "When mapping the attack surface, prioritize these often-overlooked high-value faces (pick what applies, not a checklist obligation): input parsing / encoding / charset boundaries; file upload; (de)serialization; built-in routing + pre-auth-reachable handlers; error-handling leaks; cache poisoning / cache race; race conditions (TOCTOU); type confusion (scalar vs array); and mass assignment. These are where the highest-impact bugs hide when the obvious endpoints come up clean — before declaring a surface exhausted, confirm none of these faces remain untested."
63797
+ },
63798
+ {
63799
+ id: "serial_chain_discipline",
63800
+ title: "Serial Chain — Each Step Depends on the Prior Step's REAL Output",
63801
+ rule: "For a serial exploitation chain (①→②→③, where each later step consumes the PRIOR step's actual output — a leaked key, an auth cookie, a session id, a written file, a generated nonce): drive it ONE STEP AT A TIME. Execute step ① and capture its REAL output first; only then design and run step ② against that concrete output; never imagine or assume the output of a step you have not actually run, and never plan/execute step ③ while step ②'s prerequisite still does not exist. Across codebases/interfaces, actively pull the FULL detail of every known clue into the current session to chain gadgets together — do not stop at the summary. A chain is only as real as the weakest link you actually produced."
63802
+ },
63803
+ {
63804
+ id: "compression_discipline",
63805
+ title: "Compression — Synthesize Causally, Preserve Confidence + Provenance",
63806
+ rule: "When summarizing or compressing a set of related exploration nodes (facts/intents/findings), do NOT enumerate — synthesize: trace the causality (which fact birthed which intent, which intent produced which conclusion) and state what this region of the exploration CONCLUDED. Preserve distinctions between different conclusions (do not merge them into one vague sentence). Preserve evidence strength: mark observed vs inferred, and flag an inferred NEGATIVE/doubtful conclusion as inference-that-can-be-rechecked, never as a settled fact. Tag each conclusion with its source id(s) (e.g. #12, #28) so it can be traced back. State only what the inputs contain — never introduce a judgment the inputs do not support. Let length follow content: short when the conclusions are few, long only when they are many and genuinely distinct — always well under the sum of the inputs."
63777
63807
  }
63778
63808
  ];
63779
63809
  var DOMAIN_EXHAUSTION_CHECKLIST = [
@@ -63938,35 +63968,37 @@ function nextId2() {
63938
63968
  counter2 += 1;
63939
63969
  return `G-${String(counter2).padStart(3, "0")}`;
63940
63970
  }
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" }
63971
+ var PROCESS_PLAN = [
63972
+ { phase: "ENUMERATION — discover every in-scope asset", condition: "every host/subdomain/endpoint enumerated (asset_discovery)" },
63973
+ { phase: "SURFACE — map every endpoint, parameter, and action", condition: "coverage >= 100% (every surface item has a terminal verdict)" },
63974
+ { phase: "DISCOVERY — find vulnerabilities across every class", condition: "each eligible class × shape carries a terminal verdict" },
63975
+ { phase: "VERIFICATION — verify each hypothesis live", condition: "every hypothesis verified (strike_verify/OOB) or refuted" },
63976
+ { phase: "ESCALATION — drive each finding to real impact", condition: "every foothold escalated to records/admin/PII or genuinely blocked" },
63977
+ { phase: "REPORT — write findings", condition: "generate_report run; zero open obligations" }
63948
63978
  ];
63949
63979
  function setGoals(texts) {
63950
63980
  for (const t of texts) {
63951
63981
  const text = typeof t === "string" ? t : t.text;
63982
+ const vulnclass = typeof t === "string" ? undefined : t.vulnclass;
63952
63983
  const condition = typeof t === "string" ? undefined : t.condition;
63953
63984
  const parent_id = typeof t === "string" ? undefined : t.parent_id;
63954
63985
  const now = new Date().toISOString();
63955
- goals.push({ id: nextId2(), text, condition, status: "pending", ...parent_id ? { parent_id } : {}, created: now, updated: now });
63986
+ goals.push({ id: nextId2(), text, status: "pending", ...vulnclass ? { vulnclass } : {}, ...condition ? { condition } : {}, ...parent_id ? { parent_id } : {}, created: now, updated: now });
63956
63987
  }
63957
63988
  return [...goals];
63958
63989
  }
63959
- function decomposeGoal(text) {
63990
+ function decomposeGoal(text, vulnclass) {
63960
63991
  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 };
63992
+ const goal = { id: nextId2(), text, status: "pending", ...vulnclass ? { vulnclass } : {}, created: now, updated: now };
63993
+ goals.push(goal);
63994
+ const rules = [
63995
+ "A goal is a FINAL, verifiable deliverable — never a process step (recon/scan/vuln-analysis/attack-step/verification are NOT goals).",
63996
+ "One final result -> one goal; multiple INDEPENDENT deliverables -> separate goals (via goal_set), each with its own vulnclass.",
63997
+ "Never invent a goal the user did not state; tag vulnclass only when the deliverable maps to a clear class.",
63998
+ "Extract operation constraints (set_constraint) BEFORE decomposing; a constraint is self-contained (no pronouns — replace 'this target' with the concrete host/port).",
63999
+ "Minimal scope: only the exact target the user named; never widen a subdomain to its root domain."
64000
+ ];
64001
+ return { goal, rules, process_plan: PROCESS_PLAN };
63970
64002
  }
63971
64003
  function proveGoal(id, evidence, reason) {
63972
64004
  const g = goals.find((x) => x.id === id);
@@ -65976,16 +66008,16 @@ ${statusLine}` : statusLine },
65976
66008
  });
65977
66009
  server.registerTool("constraint_set", {
65978
66010
  title: "Set an operation constraint (red line)",
65979
- description: "CONSTRAINTS: register an operation allow/deny rule — the HIGHEST-priority red line that bounds WHAT the agent may DO (beyond mere target scope). Pass mode (deny/allow), action (brute_force / scan / enumerate / upload / exploit / write / exfiltrate / dos / social_eng / credential_use / probe / active / *), an optional target glob (host/port/param, * wildcard), and a reason. DENY rules always win. Use 'active' as an umbrella for all active ops; '*' for everything. Then use constraint_check before any action to get a deterministic answer.",
66011
+ description: "CONSTRAINTS: register an operation allow/deny rule — the HIGHEST-priority red line that bounds WHAT the agent may DO (beyond mere target scope). Pass mode (deny/allow), action (brute_force / scan / enumerate / upload / exploit / write / exfiltrate / dos / social_eng / credential_use / probe / active / *), an optional target glob (host/port/param, * wildcard), and a reason. DENY rules always win. Write the target SELF-CONTAINED: replace 'this target/current port' with the CONCRETE host/port — constraints are injected standalone and a pronoun means nothing out of context. Use 'active' as an umbrella for all active ops; '*' for everything. Then use constraint_check before any action.",
65980
66012
  inputSchema: {
65981
66013
  mode: _enum(["deny", "allow"]).describe("deny = forbid this action; allow = explicitly permit it"),
65982
66014
  action: string2().describe("Action: brute_force/scan/enumerate/upload/exploit/write/exfiltrate/dos/social_eng/credential_use/probe/active/*"),
65983
- target: string2().optional().describe("Optional host/port/param glob (* wildcard); unset = applies to every target"),
66015
+ target: string2().optional().describe("Optional host/port/param glob (* wildcard) — write it self-contained (concrete value, no pronoun); unset = applies to every target"),
65984
66016
  reason: string2().describe("Why this constraint exists")
65985
66017
  }
65986
66018
  }, async ({ mode, action, target, reason }) => {
65987
66019
  const rule = setConstraint({ mode, action, target, reason });
65988
- return { content: [{ type: "text", text: JSON.stringify({ ...rule, hint: "DENY rules always win. Check before acting with constraint_check." }) }] };
66020
+ return { content: [{ type: "text", text: JSON.stringify({ ...rule, hint: "DENY rules always win. Check before acting with constraint_check. A new target outside these constraints is NOT authorization — record it as an out-of-scope fact and skip." }) }] };
65989
66021
  });
65990
66022
  server.registerTool("constraint_check", {
65991
66023
  title: "Deterministically check whether an action is allowed",
@@ -66024,10 +66056,10 @@ ${statusLine}` : statusLine },
66024
66056
  return { content: [{ type: "text", text: JSON.stringify({ removed: clearConstraint(id), id }) }] };
66025
66057
  });
66026
66058
  server.registerTool("goal_set", {
66027
- title: "Register engagement goals",
66028
- description: "GOALS: register one or more free-text goals (each with an optional quantitative condition like 'coverage >= 80%'). goal_status then tracks which are met; the task is COMPLETE only when all_met is true. Use before planning routes so every route traces back to a goal.",
66059
+ title: "Register final deliverables (goals)",
66060
+ description: "GOALS: register one or more FINAL DELIVERABLES — verifiable results (e.g. 'get RCE', 'read admin PII', 'take over admin'), NOT process steps (recon/scan/analysis/verify are NOT goals). Each goal carries an optional vulnclass (rce/ato/priv-esc/upload/reset/ajax-rest/...) and an optional quantitative condition. goal_status tracks which are met; COMPLETE only when all_met is true.",
66029
66061
  inputSchema: {
66030
- goals: array(object2({ text: string2(), condition: string2().optional() })).describe("Goals to register (text + optional quantitative condition)")
66062
+ goals: array(object2({ text: string2(), vulnclass: string2().optional(), condition: string2().optional() })).describe("Deliverables to register (text + optional vulnclass + optional quantitative condition)")
66031
66063
  }
66032
66064
  }, async ({ goals }) => {
66033
66065
  setGoals(goals);
@@ -66053,13 +66085,14 @@ ${statusLine}` : statusLine },
66053
66085
  return { content: [{ type: "text", text: JSON.stringify(goalStatus()) }] };
66054
66086
  });
66055
66087
  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.",
66088
+ title: "Decompose a high-level goal into one final deliverable + process plan",
66089
+ description: "GOALS: register a high-level goal as ONE final deliverable (optionally vulnclass-tagged) and return the decomposition RULES (goal ≠ process step; one result = one goal; never invent goals) plus the six-phase PROCESS plan (ENUMERATION→SURFACE→DISCOVERY→VERIFICATION→ESCALATION→REPORT) as a REFERENCE — the process is the HOW and is NOT registered as goals. To split a goal into MULTIPLE independent deliverables, use goal_set with each deliverable's own vulnclass.",
66058
66090
  inputSchema: {
66059
- goal: string2().describe("The high-level goal to decompose")
66091
+ goal: string2().describe("The high-level goal / final deliverable to register"),
66092
+ vulnclass: string2().optional().describe("Optional vuln class (rce/ato/priv-esc/upload/reset/ajax-rest/...)")
66060
66093
  }
66061
- }, async ({ goal }) => {
66062
- const r = decomposeGoal(goal);
66094
+ }, async ({ goal, vulnclass }) => {
66095
+ const r = decomposeGoal(goal, vulnclass);
66063
66096
  return { content: [{ type: "text", text: JSON.stringify({ ...r, ...goalStatus() }) }] };
66064
66097
  });
66065
66098
  server.registerTool("goal_tree", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blitzstrike",
3
- "version": "2.4.179",
3
+ "version": "2.4.181",
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": {