pentesting 0.40.1 → 0.40.3

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.
Files changed (2) hide show
  1. package/dist/main.js +950 -129
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -305,10 +305,8 @@ var ORPHAN_PROCESS_NAMES = [
305
305
  ];
306
306
 
307
307
  // src/shared/constants/agent.ts
308
- var ID_LENGTH = AGENT_LIMITS.ID_LENGTH;
309
- var ID_RADIX = AGENT_LIMITS.ID_RADIX;
310
308
  var APP_NAME = "Pentest AI";
311
- var APP_VERSION = "0.40.1";
309
+ var APP_VERSION = "0.40.3";
312
310
  var APP_DESCRIPTION = "Autonomous Penetration Testing AI Agent";
313
311
  var LLM_ROLES = {
314
312
  SYSTEM: "system",
@@ -591,7 +589,7 @@ var DEFAULTS = {
591
589
 
592
590
  // src/engine/process-manager.ts
593
591
  import { spawn as spawn3, execSync as execSync2 } from "child_process";
594
- import { readFileSync as readFileSync2, existsSync as existsSync3, unlinkSync, writeFileSync as writeFileSync3, appendFileSync as appendFileSync2 } from "fs";
592
+ import { readFileSync as readFileSync2, existsSync as existsSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3, appendFileSync as appendFileSync2 } from "fs";
595
593
 
596
594
  // src/engine/tools-base.ts
597
595
  import { spawn as spawn2 } from "child_process";
@@ -1520,58 +1518,8 @@ function createTempFile(suffix = "") {
1520
1518
  return join2(tmpdir(), generateTempFilename(suffix));
1521
1519
  }
1522
1520
 
1523
- // src/engine/process-detector.ts
1524
- function detectProcessRole(command) {
1525
- const tags = [];
1526
- let port;
1527
- let role = PROCESS_ROLES.BACKGROUND;
1528
- let isInteractive = false;
1529
- const cmd = command.toLowerCase();
1530
- if (cmd.includes("-lvnp") || cmd.includes("-nlvp") || cmd.includes("-lp") || cmd.includes("nc") && cmd.includes("listen")) {
1531
- tags.push(PROCESS_ROLES.LISTENER);
1532
- role = PROCESS_ROLES.LISTENER;
1533
- isInteractive = true;
1534
- const portMatch = command.match(DETECTION_PATTERNS.LISTENER);
1535
- if (portMatch) port = parseInt(portMatch[1], 10);
1536
- }
1537
- if (cmd.includes("http.server") || cmd.includes("simplehttpserver") || cmd.includes("httpd") || cmd.includes("php -s")) {
1538
- tags.push(PROCESS_ROLES.SERVER);
1539
- role = PROCESS_ROLES.SERVER;
1540
- const portMatch = command.match(DETECTION_PATTERNS.HTTP_SERVER);
1541
- if (portMatch) port = parseInt(portMatch[1], 10);
1542
- if (!port) {
1543
- const genericPort = command.match(DETECTION_PATTERNS.GENERIC_PORT);
1544
- if (genericPort) port = parseInt(genericPort[1], 10);
1545
- else if (cmd.includes("http.server")) port = SYSTEM_LIMITS.WEB_PORT_RANGE.MIN;
1546
- }
1547
- }
1548
- if (cmd.includes("tcpdump") || cmd.includes("tshark")) {
1549
- tags.push(PROCESS_ROLES.SNIFFER);
1550
- role = PROCESS_ROLES.SNIFFER;
1551
- }
1552
- if (cmd.includes("arpspoof") || cmd.includes("dnsspoof") || cmd.includes("ettercap")) {
1553
- tags.push(PROCESS_ROLES.SPOOFER);
1554
- role = PROCESS_ROLES.SPOOFER;
1555
- }
1556
- if (cmd.includes("mitm") || cmd.includes("proxy") || cmd.includes("intercept")) {
1557
- tags.push(PROCESS_ROLES.PROXY);
1558
- role = PROCESS_ROLES.PROXY;
1559
- }
1560
- if (cmd.includes("callback") || cmd.includes("oob")) {
1561
- tags.push(PROCESS_ROLES.CALLBACK);
1562
- role = PROCESS_ROLES.CALLBACK;
1563
- }
1564
- if (cmd.includes("socat") && cmd.includes("listen")) {
1565
- tags.push(PROCESS_ROLES.LISTENER);
1566
- role = PROCESS_ROLES.LISTENER;
1567
- isInteractive = true;
1568
- }
1569
- if (tags.length === 0) tags.push(PROCESS_ROLES.BACKGROUND);
1570
- return { tags, port, role, isInteractive };
1571
- }
1572
- function detectConnection(stdout) {
1573
- return DETECTION_PATTERNS.CONNECTION.some((p) => p.test(stdout));
1574
- }
1521
+ // src/engine/process-cleanup.ts
1522
+ import { unlinkSync } from "fs";
1575
1523
 
1576
1524
  // src/engine/process-tree.ts
1577
1525
  import { execSync } from "child_process";
@@ -1657,9 +1605,99 @@ function killProcessTreeSync(pid, childPids) {
1657
1605
  }
1658
1606
  }
1659
1607
 
1608
+ // src/engine/process-cleanup.ts
1609
+ function syncCleanupAllProcesses(processMap) {
1610
+ for (const [, proc] of processMap) {
1611
+ if (!proc.hasExited) {
1612
+ killProcessTreeSync(proc.pid, proc.childPids);
1613
+ }
1614
+ try {
1615
+ unlinkSync(proc.stdoutFile);
1616
+ } catch {
1617
+ }
1618
+ try {
1619
+ unlinkSync(proc.stderrFile);
1620
+ } catch {
1621
+ }
1622
+ try {
1623
+ unlinkSync(proc.stdinFile);
1624
+ } catch {
1625
+ }
1626
+ }
1627
+ }
1628
+ function registerExitHandlers(processMap) {
1629
+ process.on("exit", () => {
1630
+ syncCleanupAllProcesses(processMap);
1631
+ });
1632
+ process.on("SIGINT", () => {
1633
+ syncCleanupAllProcesses(processMap);
1634
+ processMap.clear();
1635
+ process.exit(EXIT_CODES.SIGINT);
1636
+ });
1637
+ process.on("SIGTERM", () => {
1638
+ syncCleanupAllProcesses(processMap);
1639
+ processMap.clear();
1640
+ process.exit(EXIT_CODES.SIGTERM);
1641
+ });
1642
+ }
1643
+
1644
+ // src/engine/process-detector.ts
1645
+ function detectProcessRole(command) {
1646
+ const tags = [];
1647
+ let port;
1648
+ let role = PROCESS_ROLES.BACKGROUND;
1649
+ let isInteractive = false;
1650
+ const cmd = command.toLowerCase();
1651
+ if (cmd.includes("-lvnp") || cmd.includes("-nlvp") || cmd.includes("-lp") || cmd.includes("nc") && cmd.includes("listen")) {
1652
+ tags.push(PROCESS_ROLES.LISTENER);
1653
+ role = PROCESS_ROLES.LISTENER;
1654
+ isInteractive = true;
1655
+ const portMatch = command.match(DETECTION_PATTERNS.LISTENER);
1656
+ if (portMatch) port = parseInt(portMatch[1], 10);
1657
+ }
1658
+ if (cmd.includes("http.server") || cmd.includes("simplehttpserver") || cmd.includes("httpd") || cmd.includes("php -s")) {
1659
+ tags.push(PROCESS_ROLES.SERVER);
1660
+ role = PROCESS_ROLES.SERVER;
1661
+ const portMatch = command.match(DETECTION_PATTERNS.HTTP_SERVER);
1662
+ if (portMatch) port = parseInt(portMatch[1], 10);
1663
+ if (!port) {
1664
+ const genericPort = command.match(DETECTION_PATTERNS.GENERIC_PORT);
1665
+ if (genericPort) port = parseInt(genericPort[1], 10);
1666
+ else if (cmd.includes("http.server")) port = SYSTEM_LIMITS.WEB_PORT_RANGE.MIN;
1667
+ }
1668
+ }
1669
+ if (cmd.includes("tcpdump") || cmd.includes("tshark")) {
1670
+ tags.push(PROCESS_ROLES.SNIFFER);
1671
+ role = PROCESS_ROLES.SNIFFER;
1672
+ }
1673
+ if (cmd.includes("arpspoof") || cmd.includes("dnsspoof") || cmd.includes("ettercap")) {
1674
+ tags.push(PROCESS_ROLES.SPOOFER);
1675
+ role = PROCESS_ROLES.SPOOFER;
1676
+ }
1677
+ if (cmd.includes("mitm") || cmd.includes("proxy") || cmd.includes("intercept")) {
1678
+ tags.push(PROCESS_ROLES.PROXY);
1679
+ role = PROCESS_ROLES.PROXY;
1680
+ }
1681
+ if (cmd.includes("callback") || cmd.includes("oob")) {
1682
+ tags.push(PROCESS_ROLES.CALLBACK);
1683
+ role = PROCESS_ROLES.CALLBACK;
1684
+ }
1685
+ if (cmd.includes("socat") && cmd.includes("listen")) {
1686
+ tags.push(PROCESS_ROLES.LISTENER);
1687
+ role = PROCESS_ROLES.LISTENER;
1688
+ isInteractive = true;
1689
+ }
1690
+ if (tags.length === 0) tags.push(PROCESS_ROLES.BACKGROUND);
1691
+ return { tags, port, role, isInteractive };
1692
+ }
1693
+ function detectConnection(stdout) {
1694
+ return DETECTION_PATTERNS.CONNECTION.some((p) => p.test(stdout));
1695
+ }
1696
+
1660
1697
  // src/engine/process-manager.ts
1661
1698
  var backgroundProcesses = /* @__PURE__ */ new Map();
1662
1699
  var cleanupDone = false;
1700
+ registerExitHandlers(backgroundProcesses);
1663
1701
  var processEventLog = [];
1664
1702
  function logEvent(processId, event, detail) {
1665
1703
  processEventLog.push({ timestamp: Date.now(), processId, event, detail });
@@ -1833,15 +1871,15 @@ async function stopBackgroundProcess(processId) {
1833
1871
  await killProcessTree(proc.pid, proc.childPids);
1834
1872
  }
1835
1873
  try {
1836
- unlinkSync(proc.stdoutFile);
1874
+ unlinkSync2(proc.stdoutFile);
1837
1875
  } catch {
1838
1876
  }
1839
1877
  try {
1840
- unlinkSync(proc.stderrFile);
1878
+ unlinkSync2(proc.stderrFile);
1841
1879
  } catch {
1842
1880
  }
1843
1881
  try {
1844
- unlinkSync(proc.stdinFile);
1882
+ unlinkSync2(proc.stdinFile);
1845
1883
  } catch {
1846
1884
  }
1847
1885
  logEvent(processId, PROCESS_EVENTS.STOPPED, `Stopped ${proc.role} (PID:${proc.pid}, children:${proc.childPids.length})`);
@@ -1939,15 +1977,15 @@ async function cleanupAllProcesses() {
1939
1977
  }
1940
1978
  for (const [, proc] of backgroundProcesses) {
1941
1979
  try {
1942
- unlinkSync(proc.stdoutFile);
1980
+ unlinkSync2(proc.stdoutFile);
1943
1981
  } catch {
1944
1982
  }
1945
1983
  try {
1946
- unlinkSync(proc.stderrFile);
1984
+ unlinkSync2(proc.stderrFile);
1947
1985
  } catch {
1948
1986
  }
1949
1987
  try {
1950
- unlinkSync(proc.stdinFile);
1988
+ unlinkSync2(proc.stdinFile);
1951
1989
  } catch {
1952
1990
  }
1953
1991
  }
@@ -2033,39 +2071,6 @@ Ports In Use: ${ports.join(", ")}`);
2033
2071
  }
2034
2072
  return lines.join("\n");
2035
2073
  }
2036
- function syncCleanupAllProcesses() {
2037
- for (const [, proc] of backgroundProcesses) {
2038
- if (!proc.hasExited) {
2039
- killProcessTreeSync(proc.pid, proc.childPids);
2040
- }
2041
- try {
2042
- unlinkSync(proc.stdoutFile);
2043
- } catch {
2044
- }
2045
- try {
2046
- unlinkSync(proc.stderrFile);
2047
- } catch {
2048
- }
2049
- try {
2050
- unlinkSync(proc.stdinFile);
2051
- } catch {
2052
- }
2053
- }
2054
- }
2055
- process.on("exit", () => {
2056
- syncCleanupAllProcesses();
2057
- });
2058
- process.on("SIGINT", () => {
2059
- syncCleanupAllProcesses();
2060
- backgroundProcesses.clear();
2061
- process.exit(EXIT_CODES.SIGINT);
2062
- });
2063
- process.on("SIGTERM", () => {
2064
- syncCleanupAllProcesses();
2065
- backgroundProcesses.clear();
2066
- process.exit(EXIT_CODES.SIGTERM);
2067
- });
2068
- var stopProcess = stopBackgroundProcess;
2069
2074
 
2070
2075
  // src/engine/state-serializer.ts
2071
2076
  var StateSerializer = class {
@@ -2134,7 +2139,7 @@ var StateSerializer = class {
2134
2139
  if (todo.length > 0) {
2135
2140
  lines.push(`TODO (${todo.length}):`);
2136
2141
  for (const t of todo.slice(0, DISPLAY_LIMITS.COMPACT_LIST_ITEMS)) {
2137
- const status = t.status === "done" ? "[x]" : t.status === "in_progress" ? "[->]" : "[ ]";
2142
+ const status = t.status === TODO_STATUSES.DONE ? "[x]" : t.status === TODO_STATUSES.IN_PROGRESS ? "[->]" : "[ ]";
2138
2143
  lines.push(` ${status} ${t.content} (${t.priority})`);
2139
2144
  }
2140
2145
  }
@@ -2598,6 +2603,13 @@ var PersistentMemory = class {
2598
2603
  getSuccessfulTechniques(service) {
2599
2604
  return this.knowledge.successfulTechniques.filter((t) => t.service.toLowerCase().includes(service.toLowerCase())).sort((a, b) => b.successCount - a.successCount);
2600
2605
  }
2606
+ /**
2607
+ * Clear all knowledge (for testing isolation).
2608
+ */
2609
+ clear() {
2610
+ this.knowledge = { successfulTechniques: [], failurePatterns: [], techFacts: [] };
2611
+ this.save();
2612
+ }
2601
2613
  /**
2602
2614
  * Format for prompt injection (most relevant persistent knowledge).
2603
2615
  */
@@ -2852,7 +2864,7 @@ var SharedState = class {
2852
2864
  }
2853
2865
  addMissionChecklistItems(items) {
2854
2866
  for (const text of items) {
2855
- const id = generateId(ID_RADIX, ID_LENGTH);
2867
+ const id = generateId(AGENT_LIMITS.ID_RADIX, AGENT_LIMITS.ID_LENGTH);
2856
2868
  this.data.missionChecklist.push({ id, text, isCompleted: false });
2857
2869
  }
2858
2870
  }
@@ -2872,7 +2884,7 @@ var SharedState = class {
2872
2884
  this.data.engagement.scope = scope;
2873
2885
  } else {
2874
2886
  this.data.engagement = {
2875
- id: generateId(ID_RADIX, ID_LENGTH),
2887
+ id: generateId(AGENT_LIMITS.ID_RADIX, AGENT_LIMITS.ID_LENGTH),
2876
2888
  name: DEFAULTS.ENGAGEMENT_NAME,
2877
2889
  client: DEFAULTS.ENGAGEMENT_CLIENT,
2878
2890
  scope,
@@ -2932,7 +2944,7 @@ var SharedState = class {
2932
2944
  }
2933
2945
  // --- TODO Management ---
2934
2946
  addTodo(content, priority = PRIORITIES.MEDIUM) {
2935
- const id = generateId(ID_RADIX, ID_LENGTH);
2947
+ const id = generateId(AGENT_LIMITS.ID_RADIX, AGENT_LIMITS.ID_LENGTH);
2936
2948
  const item = { id, content, status: TODO_STATUSES.PENDING, priority };
2937
2949
  this.data.todo.push(item);
2938
2950
  return id;
@@ -2950,7 +2962,7 @@ var SharedState = class {
2950
2962
  // --- Logs & Phase ---
2951
2963
  logAction(action) {
2952
2964
  this.data.actionLog.push({
2953
- id: generateId(ID_RADIX, ID_LENGTH),
2965
+ id: generateId(AGENT_LIMITS.ID_RADIX, AGENT_LIMITS.ID_LENGTH),
2954
2966
  timestamp: Date.now(),
2955
2967
  ...action
2956
2968
  });
@@ -4130,7 +4142,7 @@ Next steps:
4130
4142
  }
4131
4143
  case "stop": {
4132
4144
  if (!processId) return { success: false, output: "", error: "Missing process_id" };
4133
- return stopProcess(processId);
4145
+ return stopBackgroundProcess(processId);
4134
4146
  }
4135
4147
  case "stop_all": {
4136
4148
  const procs = listBackgroundProcesses();
@@ -4464,7 +4476,7 @@ Detail: ${detail}
4464
4476
  const affected = p.affected || [];
4465
4477
  const validation = validateFinding(evidence, severity);
4466
4478
  state.addFinding({
4467
- id: generateId(ID_RADIX, ID_LENGTH),
4479
+ id: generateId(AGENT_LIMITS.ID_RADIX, AGENT_LIMITS.ID_LENGTH),
4468
4480
  title,
4469
4481
  severity,
4470
4482
  affected,
@@ -4659,7 +4671,7 @@ async function installPlaywright() {
4659
4671
 
4660
4672
  // src/engine/tools/web-browser-script.ts
4661
4673
  import { spawn as spawn5 } from "child_process";
4662
- import { writeFileSync as writeFileSync5, unlinkSync as unlinkSync2 } from "fs";
4674
+ import { writeFileSync as writeFileSync5, unlinkSync as unlinkSync3 } from "fs";
4663
4675
  import { join as join5 } from "path";
4664
4676
  import { tmpdir as tmpdir2 } from "os";
4665
4677
  function safeJsString(str) {
@@ -4695,7 +4707,7 @@ function runPlaywrightScript(script, timeout, scriptPrefix) {
4695
4707
  child.stderr.on("data", (data) => stderr += data);
4696
4708
  child.on("close", (code) => {
4697
4709
  try {
4698
- unlinkSync2(scriptPath);
4710
+ unlinkSync3(scriptPath);
4699
4711
  } catch {
4700
4712
  }
4701
4713
  if (code !== 0) {
@@ -4722,7 +4734,7 @@ function runPlaywrightScript(script, timeout, scriptPrefix) {
4722
4734
  });
4723
4735
  child.on("error", (err) => {
4724
4736
  try {
4725
- unlinkSync2(scriptPath);
4737
+ unlinkSync3(scriptPath);
4726
4738
  } catch {
4727
4739
  }
4728
4740
  resolve({
@@ -6469,7 +6481,7 @@ Combine with packet_sniff to capture intercepted traffic.`,
6469
6481
  });
6470
6482
  await new Promise((r) => setTimeout(r, (duration + NETWORK_CONFIG.WAIT_BUFFER_SECONDS) * 1e3));
6471
6483
  const output = getProcessOutput(proc.id);
6472
- await stopProcess(proc.id);
6484
+ await stopBackgroundProcess(proc.id);
6473
6485
  await runCommand(NETWORK_COMMANDS.IP_FORWARD_DISABLE);
6474
6486
  return {
6475
6487
  success: true,
@@ -6523,7 +6535,7 @@ Requires root/sudo privileges.`,
6523
6535
  });
6524
6536
  await new Promise((r) => setTimeout(r, (duration + NETWORK_CONFIG.WAIT_BUFFER_SECONDS) * 1e3));
6525
6537
  const captureOutput = getProcessOutput(proc.id);
6526
- await stopProcess(proc.id);
6538
+ await stopBackgroundProcess(proc.id);
6527
6539
  let output = `Packet Capture Results:
6528
6540
  Interface: ${iface}
6529
6541
  Filter: ${filter || "none"}
@@ -6610,7 +6622,7 @@ ${spoofIp} *.${domain}
6610
6622
  });
6611
6623
  await new Promise((r) => setTimeout(r, (duration + NETWORK_CONFIG.WAIT_BUFFER_SECONDS) * 1e3));
6612
6624
  const output = getProcessOutput(proc.id);
6613
- await stopProcess(proc.id);
6625
+ await stopBackgroundProcess(proc.id);
6614
6626
  return {
6615
6627
  success: true,
6616
6628
  output: `DNS Spoofing Results:
@@ -6662,7 +6674,7 @@ Combine with arp_spoof for transparent proxying.`,
6662
6674
  });
6663
6675
  await new Promise((r) => setTimeout(r, (duration + NETWORK_CONFIG.WAIT_BUFFER_SECONDS) * 1e3));
6664
6676
  const procOutput = getProcessOutput(proc.id);
6665
- await stopProcess(proc.id);
6677
+ await stopBackgroundProcess(proc.id);
6666
6678
  let flowSummary = "";
6667
6679
  const readFlows = await runCommand(`mitmdump -r ${outputFile} -n 2>&1 | head -50`);
6668
6680
  if (readFlows.success && readFlows.output) {
@@ -6731,7 +6743,7 @@ This is a high-level tool that combines tcpdump capture with protocol analysis.`
6731
6743
  description: `Traffic intercept on ${target}`
6732
6744
  });
6733
6745
  await new Promise((r) => setTimeout(r, (duration + NETWORK_CONFIG.WAIT_BUFFER_SECONDS) * 1e3));
6734
- await stopProcess(proc.id);
6746
+ await stopBackgroundProcess(proc.id);
6735
6747
  let output = `Traffic Interception Report
6736
6748
  ${"=".repeat(50)}
6737
6749
  Target: ${target}
@@ -7063,7 +7075,7 @@ If killOrphans is true, also cleans up child processes whose parent has died.`,
7063
7075
  async execute(params) {
7064
7076
  const results = [];
7065
7077
  if (params.processId) {
7066
- const procResult = await stopProcess(params.processId);
7078
+ const procResult = await stopBackgroundProcess(params.processId);
7067
7079
  results.push(`Stopped ${params.processId}: ${procResult.success ? "success" : "failed"}`);
7068
7080
  if (procResult.output) {
7069
7081
  results.push(procResult.output.slice(0, PROCESS_OUTPUT_TRUNCATION_LIMIT));
@@ -7116,6 +7128,548 @@ Returns recommendations on process status, port conflicts, long-running tasks, e
7116
7128
  }
7117
7129
  ];
7118
7130
 
7131
+ // src/domains/network/tools.ts
7132
+ var NETWORK_TOOLS = [
7133
+ {
7134
+ name: TOOL_NAMES.NMAP_QUICK,
7135
+ description: "Quick nmap scan - fast discovery",
7136
+ parameters: {
7137
+ target: { type: "string", description: "Target IP/CIDR" }
7138
+ },
7139
+ required: ["target"],
7140
+ execute: async (params) => {
7141
+ const target = params.target;
7142
+ return await runCommand("nmap", ["-Pn", "-T4", "-F", target]);
7143
+ }
7144
+ },
7145
+ {
7146
+ name: TOOL_NAMES.NMAP_FULL,
7147
+ description: "Full nmap scan - comprehensive",
7148
+ parameters: {
7149
+ target: { type: "string", description: "Target IP/CIDR" }
7150
+ },
7151
+ required: ["target"],
7152
+ execute: async (params) => {
7153
+ const target = params.target;
7154
+ return await runCommand("nmap", ["-Pn", "-T4", "-sV", "-O", "-p-", target]);
7155
+ }
7156
+ },
7157
+ {
7158
+ name: TOOL_NAMES.RUSTSCAN,
7159
+ description: "RustScan - very fast port discovery",
7160
+ parameters: {
7161
+ target: { type: "string", description: "Target IP" }
7162
+ },
7163
+ required: ["target"],
7164
+ execute: async (params) => {
7165
+ const target = params.target;
7166
+ return await runCommand("rustscan", ["-a", target, "--range", "1-65535"]);
7167
+ }
7168
+ }
7169
+ ];
7170
+ var NETWORK_CONFIG2 = {
7171
+ name: SERVICE_CATEGORIES.NETWORK,
7172
+ description: "Network reconnaissance - scanning, OS fingerprinting",
7173
+ tools: NETWORK_TOOLS,
7174
+ dangerLevel: DANGER_LEVELS.ACTIVE,
7175
+ defaultApproval: APPROVAL_LEVELS.CONFIRM,
7176
+ commonPorts: [21, 22, 80, 443, 445, 3389, 8080],
7177
+ commonServices: [SERVICES.FTP, SERVICES.SSH, SERVICES.HTTP, SERVICES.HTTPS, SERVICES.SMB]
7178
+ };
7179
+
7180
+ // src/domains/web/tools.ts
7181
+ var WEB_TOOLS = [
7182
+ {
7183
+ name: TOOL_NAMES.HTTP_FINGERPRINT,
7184
+ description: "HTTP fingerprinting - detect WAF, server type",
7185
+ parameters: {
7186
+ target: { type: "string", description: "Target URL" }
7187
+ },
7188
+ required: ["target"],
7189
+ execute: async (params) => {
7190
+ const target = params.target;
7191
+ return await runCommand("curl", ["-sI", target]);
7192
+ }
7193
+ },
7194
+ {
7195
+ name: TOOL_NAMES.WAF_DETECT,
7196
+ description: "WAF detection using wafw00f",
7197
+ parameters: {
7198
+ target: { type: "string", description: "Target URL" }
7199
+ },
7200
+ required: ["target"],
7201
+ execute: async (params) => {
7202
+ const target = params.target;
7203
+ return await runCommand("wafw00f", [target]);
7204
+ }
7205
+ },
7206
+ {
7207
+ name: TOOL_NAMES.DIRSEARCH,
7208
+ description: "Directory bruteforcing",
7209
+ parameters: {
7210
+ target: { type: "string", description: "Target URL" }
7211
+ },
7212
+ required: ["target"],
7213
+ execute: async (params) => {
7214
+ const target = params.target;
7215
+ return await runCommand("dirsearch", ["-u", target, "--quiet"]);
7216
+ }
7217
+ },
7218
+ {
7219
+ name: TOOL_NAMES.NUCLEI_WEB,
7220
+ description: "Nuclei web vulnerability scanner",
7221
+ parameters: {
7222
+ target: { type: "string", description: "Target URL" },
7223
+ severity: { type: "string", description: "Severities to check" }
7224
+ },
7225
+ required: ["target"],
7226
+ execute: async (params) => {
7227
+ const target = params.target;
7228
+ const severity = params.severity || "medium,critical,high";
7229
+ return await runCommand("nuclei", ["-u", target, "-s", severity, "-silent"]);
7230
+ }
7231
+ }
7232
+ ];
7233
+ var WEB_CONFIG = {
7234
+ name: SERVICE_CATEGORIES.WEB,
7235
+ description: "Web application testing - HTTP/HTTPS, APIs",
7236
+ tools: WEB_TOOLS,
7237
+ dangerLevel: DANGER_LEVELS.ACTIVE,
7238
+ defaultApproval: APPROVAL_LEVELS.CONFIRM,
7239
+ commonPorts: [80, 443, 8080],
7240
+ commonServices: [SERVICES.HTTP, SERVICES.HTTPS]
7241
+ };
7242
+
7243
+ // src/domains/database/tools.ts
7244
+ var DATABASE_TOOLS = [
7245
+ {
7246
+ name: TOOL_NAMES.SQLMAP_BASIC,
7247
+ description: "SQL injection testing with sqlmap - basic scan",
7248
+ parameters: {
7249
+ target: { type: "string", description: "Target URL" }
7250
+ },
7251
+ required: ["target"],
7252
+ execute: async (params) => {
7253
+ const target = params.target;
7254
+ return await runCommand("sqlmap", ["-u", target, "--batch", "--risk=1", "--level=1"]);
7255
+ }
7256
+ },
7257
+ {
7258
+ name: TOOL_NAMES.SQLMAP_ADVANCED,
7259
+ description: "SQL injection with sqlmap - full enumeration",
7260
+ parameters: {
7261
+ target: { type: "string", description: "Target URL" }
7262
+ },
7263
+ required: ["target"],
7264
+ execute: async (params) => {
7265
+ const target = params.target;
7266
+ return await runCommand("sqlmap", ["-u", target, "--batch", "--risk=3", "--level=5", "--dbs", "--tables"]);
7267
+ }
7268
+ },
7269
+ {
7270
+ name: TOOL_NAMES.MYSQL_ENUM,
7271
+ description: "MySQL enumeration - version, users, databases",
7272
+ parameters: {
7273
+ target: { type: "string", description: "Target IP/hostname" },
7274
+ port: { type: "string", description: "Port (default 3306)" }
7275
+ },
7276
+ required: ["target"],
7277
+ execute: async (params) => {
7278
+ const target = params.target;
7279
+ const port = params.port || "3306";
7280
+ return await runCommand("mysql", ["-h", target, "-P", port, "-e", "SELECT VERSION(), USER(), DATABASE();"]);
7281
+ }
7282
+ },
7283
+ {
7284
+ name: TOOL_NAMES.POSTGRES_ENUM,
7285
+ description: "PostgreSQL enumeration",
7286
+ parameters: {
7287
+ target: { type: "string", description: "Target IP" }
7288
+ },
7289
+ required: ["target"],
7290
+ execute: async (params) => {
7291
+ const target = params.target;
7292
+ return await runCommand("psql", ["-h", target, "-U", "postgres", "-c", "SELECT version(); SELECT datname FROM pg_database;"]);
7293
+ }
7294
+ },
7295
+ {
7296
+ name: TOOL_NAMES.REDIS_ENUM,
7297
+ description: "Redis enumeration",
7298
+ parameters: {
7299
+ target: { type: "string", description: "Target IP" },
7300
+ port: { type: "string", description: "Port (default 6379)" }
7301
+ },
7302
+ required: ["target"],
7303
+ execute: async (params) => {
7304
+ const target = params.target;
7305
+ const port = params.port || "6379";
7306
+ return await runCommand("redis-cli", ["-h", target, "-p", port, "INFO"]);
7307
+ }
7308
+ },
7309
+ {
7310
+ name: TOOL_NAMES.DB_BRUTE,
7311
+ description: "Brute force database credentials",
7312
+ parameters: {
7313
+ target: { type: "string", description: "Target IP" },
7314
+ service: { type: "string", description: "Service (mysql, postgres, etc.)" }
7315
+ },
7316
+ required: ["target", "service"],
7317
+ execute: async (params) => {
7318
+ const target = params.target;
7319
+ const service = params.service || SERVICES.MYSQL;
7320
+ return await runCommand("hydra", [
7321
+ "-L",
7322
+ WORDLISTS.USERNAMES,
7323
+ "-P",
7324
+ WORDLISTS.COMMON_PASSWORDS,
7325
+ target,
7326
+ service
7327
+ ]);
7328
+ }
7329
+ }
7330
+ ];
7331
+ var DATABASE_CONFIG = {
7332
+ name: SERVICE_CATEGORIES.DATABASE,
7333
+ description: "Database exploitation - SQL injection, credential extraction",
7334
+ tools: DATABASE_TOOLS,
7335
+ dangerLevel: DANGER_LEVELS.EXPLOIT,
7336
+ defaultApproval: APPROVAL_LEVELS.REVIEW,
7337
+ commonPorts: [1433, 3306, 5432, 6379, 27017],
7338
+ commonServices: [SERVICES.MYSQL, SERVICES.POSTGRES, SERVICES.REDIS, SERVICES.MONGODB]
7339
+ };
7340
+
7341
+ // src/domains/ad/tools.ts
7342
+ var AD_TOOLS = [
7343
+ {
7344
+ name: TOOL_NAMES.BLOODHOUND_COLLECT,
7345
+ description: "BloodHound data collection",
7346
+ parameters: {
7347
+ target: { type: "string", description: "Target DC IP" },
7348
+ domain: { type: "string", description: "Domain name" }
7349
+ },
7350
+ required: ["target"],
7351
+ execute: async (params) => {
7352
+ const target = params.target;
7353
+ const domain = params.domain || "DOMAIN";
7354
+ return await runCommand("bloodhound-python", ["-c", "All", "-d", domain, target, "--zip"]);
7355
+ }
7356
+ },
7357
+ {
7358
+ name: TOOL_NAMES.KERBEROAST,
7359
+ description: "Kerberoasting attack",
7360
+ parameters: {
7361
+ target: { type: "string", description: "DC IP" },
7362
+ user: { type: "string", description: "Domain user" },
7363
+ password: { type: "string", description: "Password" }
7364
+ },
7365
+ required: ["target", "user", "password"],
7366
+ execute: async (params) => {
7367
+ const target = params.target;
7368
+ return await runCommand("GetUserSPNs.py", ["-dc-ip", target, `${params.user}:${params.password}`]);
7369
+ }
7370
+ },
7371
+ {
7372
+ name: TOOL_NAMES.LDAP_ENUM,
7373
+ description: "LDAP enumeration",
7374
+ parameters: {
7375
+ target: { type: "string", description: "LDAP Server" }
7376
+ },
7377
+ required: ["target"],
7378
+ execute: async (params) => {
7379
+ const target = params.target;
7380
+ return await runCommand("ldapsearch", ["-x", "-H", `ldap://${target}`, "-b", ""]);
7381
+ }
7382
+ }
7383
+ ];
7384
+ var AD_CONFIG = {
7385
+ name: SERVICE_CATEGORIES.AD,
7386
+ description: "Active Directory and Windows domain",
7387
+ tools: AD_TOOLS,
7388
+ dangerLevel: DANGER_LEVELS.EXPLOIT,
7389
+ defaultApproval: APPROVAL_LEVELS.REVIEW,
7390
+ commonPorts: [88, 389, 445],
7391
+ commonServices: [SERVICES.AD, SERVICES.SMB]
7392
+ };
7393
+
7394
+ // src/domains/email/tools.ts
7395
+ var EMAIL_TOOLS = [
7396
+ {
7397
+ name: TOOL_NAMES.SMTP_ENUM,
7398
+ description: "SMTP user enumeration",
7399
+ parameters: {
7400
+ target: { type: "string", description: "SMTP server" }
7401
+ },
7402
+ required: ["target"],
7403
+ execute: async (params) => {
7404
+ return await runCommand("smtp-user-enum", ["-M", "VRFY", "-t", params.target]);
7405
+ }
7406
+ }
7407
+ ];
7408
+ var EMAIL_CONFIG = {
7409
+ name: SERVICE_CATEGORIES.EMAIL,
7410
+ description: "Email services - SMTP, IMAP, POP3",
7411
+ tools: EMAIL_TOOLS,
7412
+ dangerLevel: DANGER_LEVELS.ACTIVE,
7413
+ defaultApproval: APPROVAL_LEVELS.CONFIRM,
7414
+ commonPorts: [25, 110, 143, 465, 587, 993, 995],
7415
+ commonServices: [SERVICES.SMTP, SERVICES.POP3, SERVICES.IMAP]
7416
+ };
7417
+
7418
+ // src/domains/remote-access/tools.ts
7419
+ var REMOTE_ACCESS_TOOLS = [
7420
+ {
7421
+ name: TOOL_NAMES.SSH_ENUM,
7422
+ description: "SSH enumeration",
7423
+ parameters: {
7424
+ target: { type: "string", description: "SSH Server" }
7425
+ },
7426
+ required: ["target"],
7427
+ execute: async (params) => {
7428
+ return await runCommand("ssh-audit", [params.target]);
7429
+ }
7430
+ },
7431
+ {
7432
+ name: TOOL_NAMES.RDP_ENUM,
7433
+ description: "RDP enumeration",
7434
+ parameters: {
7435
+ target: { type: "string", description: "RDP Server" }
7436
+ },
7437
+ required: ["target"],
7438
+ execute: async (params) => {
7439
+ return await runCommand("nmap", ["-p", "3389", "--script", "rdp-enum-encryption,rdp-ntlm-info", params.target]);
7440
+ }
7441
+ }
7442
+ ];
7443
+ var REMOTE_ACCESS_CONFIG = {
7444
+ name: SERVICE_CATEGORIES.REMOTE_ACCESS,
7445
+ description: "Remote access services - SSH, RDP, VNC",
7446
+ tools: REMOTE_ACCESS_TOOLS,
7447
+ dangerLevel: DANGER_LEVELS.ACTIVE,
7448
+ defaultApproval: APPROVAL_LEVELS.REVIEW,
7449
+ commonPorts: [22, 3389, 5900],
7450
+ commonServices: [SERVICES.SSH, SERVICES.RDP, SERVICES.VNC]
7451
+ };
7452
+
7453
+ // src/domains/file-sharing/tools.ts
7454
+ var FILE_SHARING_TOOLS = [
7455
+ {
7456
+ name: TOOL_NAMES.FTP_ENUM,
7457
+ description: "FTP enumeration",
7458
+ parameters: {
7459
+ target: { type: "string", description: "FTP Server" }
7460
+ },
7461
+ required: ["target"],
7462
+ execute: async (params) => {
7463
+ return await runCommand("nmap", ["-p", "21", "--script", "ftp-anon,ftp-syst", params.target]);
7464
+ }
7465
+ },
7466
+ {
7467
+ name: TOOL_NAMES.SMB_ENUM,
7468
+ description: "SMB enumeration",
7469
+ parameters: {
7470
+ target: { type: "string", description: "SMB Server" }
7471
+ },
7472
+ required: ["target"],
7473
+ execute: async (params) => {
7474
+ return await runCommand("enum4linux", ["-a", params.target]);
7475
+ }
7476
+ }
7477
+ ];
7478
+ var FILE_SHARING_CONFIG = {
7479
+ name: SERVICE_CATEGORIES.FILE_SHARING,
7480
+ description: "File sharing protocols - SMB, FTP, NFS",
7481
+ tools: FILE_SHARING_TOOLS,
7482
+ dangerLevel: DANGER_LEVELS.ACTIVE,
7483
+ defaultApproval: APPROVAL_LEVELS.CONFIRM,
7484
+ commonPorts: [21, 139, 445, 2049],
7485
+ commonServices: [SERVICES.FTP, SERVICES.SMB, SERVICES.NFS]
7486
+ };
7487
+
7488
+ // src/domains/cloud/tools.ts
7489
+ var CLOUD_TOOLS = [
7490
+ {
7491
+ name: TOOL_NAMES.AWS_S3_CHECK,
7492
+ description: "S3 bucket security check",
7493
+ parameters: {
7494
+ bucket: { type: "string", description: "Bucket name" }
7495
+ },
7496
+ required: ["bucket"],
7497
+ execute: async (params) => {
7498
+ const bucket = params.bucket;
7499
+ return await runCommand("aws", ["s3", "ls", `s3://${bucket}`, "--no-sign-request"]);
7500
+ }
7501
+ },
7502
+ {
7503
+ name: TOOL_NAMES.CLOUD_META_CHECK,
7504
+ description: "Check cloud metadata service access",
7505
+ parameters: {
7506
+ provider: { type: "string", description: "aws, azure, or gcp" }
7507
+ },
7508
+ required: ["provider"],
7509
+ execute: async (params) => {
7510
+ const provider = params.provider;
7511
+ if (provider === "aws") return await runCommand("curl", ["http://169.254.169.254/latest/meta-data/"]);
7512
+ if (provider === "azure") return await runCommand("curl", ["-H", "Metadata:true", "http://169.254.169.254/metadata/instance?api-version=2021-02-01"]);
7513
+ return await runCommand("curl", ["-H", "Metadata-Flavor: Google", "http://metadata.google.internal/computeMetadata/v1/"]);
7514
+ }
7515
+ }
7516
+ ];
7517
+ var CLOUD_CONFIG = {
7518
+ name: SERVICE_CATEGORIES.CLOUD,
7519
+ description: "Cloud infrastructure - AWS, Azure, GCP",
7520
+ tools: CLOUD_TOOLS,
7521
+ dangerLevel: DANGER_LEVELS.EXPLOIT,
7522
+ defaultApproval: APPROVAL_LEVELS.REVIEW,
7523
+ commonPorts: [443],
7524
+ commonServices: [SERVICES.HTTP, SERVICES.HTTPS]
7525
+ };
7526
+
7527
+ // src/domains/container/tools.ts
7528
+ var CONTAINER_TOOLS = [
7529
+ {
7530
+ name: TOOL_NAMES.DOCKER_PS,
7531
+ description: "List running Docker containers",
7532
+ parameters: {
7533
+ host: { type: "string", description: "Docker host" }
7534
+ },
7535
+ required: ["host"],
7536
+ execute: async (params) => {
7537
+ return await runCommand("docker", ["-H", params.host, "ps"]);
7538
+ }
7539
+ },
7540
+ {
7541
+ name: TOOL_NAMES.KUBE_GET_PODS,
7542
+ description: "List Kubernetes pods",
7543
+ parameters: {
7544
+ context: { type: "string", description: "Kube context" }
7545
+ },
7546
+ required: ["context"],
7547
+ execute: async (params) => {
7548
+ return await runCommand("kubectl", ["--context", params.context, "get", "pods"]);
7549
+ }
7550
+ }
7551
+ ];
7552
+ var CONTAINER_CONFIG = {
7553
+ name: SERVICE_CATEGORIES.CONTAINER,
7554
+ description: "Container platforms - Docker, Kubernetes",
7555
+ tools: CONTAINER_TOOLS,
7556
+ dangerLevel: DANGER_LEVELS.EXPLOIT,
7557
+ defaultApproval: APPROVAL_LEVELS.REVIEW,
7558
+ commonPorts: [2375, 2376, 5e3, 6443],
7559
+ commonServices: [SERVICES.DOCKER, SERVICES.KUBERNETES]
7560
+ };
7561
+
7562
+ // src/domains/api/tools.ts
7563
+ var API_TOOLS = [
7564
+ {
7565
+ name: TOOL_NAMES.API_DISCOVER,
7566
+ description: "API endpoint discovery - using Arjun",
7567
+ parameters: {
7568
+ target: { type: "string", description: "Target URL" }
7569
+ },
7570
+ required: ["target"],
7571
+ execute: async (params) => {
7572
+ const target = params.target;
7573
+ return await runCommand("arjun", ["-u", target, "-t", "20"]);
7574
+ }
7575
+ },
7576
+ {
7577
+ name: TOOL_NAMES.GRAPHQL_INTROSPECT,
7578
+ description: "GraphQL introspection - schema discovery",
7579
+ parameters: {
7580
+ target: { type: "string", description: "GQL Endpoint" }
7581
+ },
7582
+ required: ["target"],
7583
+ execute: async (params) => {
7584
+ const target = params.target;
7585
+ return await runCommand("curl", ["-X", "POST", target, "-H", "Content-Type: application/json", "-d", '{"query":"{__schema {queryType {name}}}"}']);
7586
+ }
7587
+ },
7588
+ {
7589
+ name: TOOL_NAMES.SWAGGER_PARSE,
7590
+ description: "Parse Swagger/OpenAPI specification",
7591
+ parameters: {
7592
+ spec: { type: "string", description: "URL to swagger.json/yaml" }
7593
+ },
7594
+ required: ["spec"],
7595
+ execute: async (params) => {
7596
+ const spec = params.spec;
7597
+ return await runCommand("swagger-codegen", ["generate", "-i", spec, "-l", "html2"]);
7598
+ }
7599
+ },
7600
+ {
7601
+ name: TOOL_NAMES.API_FUZZ,
7602
+ description: "General API fuzzing",
7603
+ parameters: {
7604
+ target: { type: "string", description: "Base API URL" },
7605
+ wordlist: { type: "string", description: "Wordlist path" }
7606
+ },
7607
+ required: ["target"],
7608
+ execute: async (params) => {
7609
+ const target = params.target;
7610
+ const wordlist = params.wordlist || WORDLISTS.API_FUZZ;
7611
+ return await runCommand("ffuf", ["-u", `${target}/FUZZ`, "-w", wordlist, "-mc", "all"]);
7612
+ }
7613
+ }
7614
+ ];
7615
+ var API_CONFIG = {
7616
+ name: SERVICE_CATEGORIES.API,
7617
+ description: "API testing - REST, GraphQL, SOAP",
7618
+ tools: API_TOOLS,
7619
+ dangerLevel: DANGER_LEVELS.ACTIVE,
7620
+ defaultApproval: APPROVAL_LEVELS.CONFIRM,
7621
+ commonPorts: [3e3, 5e3, 8e3, 8080],
7622
+ commonServices: [SERVICES.HTTP, SERVICES.HTTPS]
7623
+ };
7624
+
7625
+ // src/domains/wireless/tools.ts
7626
+ var WIRELESS_TOOLS = [
7627
+ {
7628
+ name: TOOL_NAMES.WIFI_SCAN,
7629
+ description: "WiFi network scanning",
7630
+ parameters: {
7631
+ interface: { type: "string", description: "Wireless interface" }
7632
+ },
7633
+ required: ["interface"],
7634
+ execute: async (params) => {
7635
+ return await runCommand("iwlist", [params.interface, "scanning"]);
7636
+ }
7637
+ }
7638
+ ];
7639
+ var WIRELESS_CONFIG = {
7640
+ name: SERVICE_CATEGORIES.WIRELESS,
7641
+ description: "Wireless security - WiFi, Bluetooth",
7642
+ tools: WIRELESS_TOOLS,
7643
+ dangerLevel: DANGER_LEVELS.ACTIVE,
7644
+ defaultApproval: APPROVAL_LEVELS.REVIEW,
7645
+ commonPorts: [],
7646
+ commonServices: [SERVICES.WIFI, SERVICES.BLUETOOTH]
7647
+ };
7648
+
7649
+ // src/domains/ics/tools.ts
7650
+ var ICS_TOOLS = [
7651
+ {
7652
+ name: TOOL_NAMES.MODBUS_ENUM,
7653
+ description: "Modbus enumeration",
7654
+ parameters: {
7655
+ target: { type: "string", description: "ICS Device" }
7656
+ },
7657
+ required: ["target"],
7658
+ execute: async (params) => {
7659
+ return await runCommand("nmap", ["-p", "502", "--script", "modbus-discover", params.target]);
7660
+ }
7661
+ }
7662
+ ];
7663
+ var ICS_CONFIG = {
7664
+ name: SERVICE_CATEGORIES.ICS,
7665
+ description: "Industrial control systems - Modbus, DNP3, EtherNet/IP",
7666
+ tools: ICS_TOOLS,
7667
+ dangerLevel: DANGER_LEVELS.ACTIVE,
7668
+ defaultApproval: APPROVAL_LEVELS.BLOCK,
7669
+ commonPorts: [502, 2e4],
7670
+ commonServices: [SERVICES.MODBUS, SERVICES.DNP3]
7671
+ };
7672
+
7119
7673
  // src/engine/tools.ts
7120
7674
  var ToolRegistry = class {
7121
7675
  constructor(state, scopeGuard, approvalGate, events) {
@@ -7132,7 +7686,20 @@ var ToolRegistry = class {
7132
7686
  ...createPentestTools(this.state),
7133
7687
  ...createAgentTools(),
7134
7688
  ...createNetworkAttackTools(),
7135
- ...resourceTools
7689
+ ...resourceTools,
7690
+ // Domain-specific tools (§3-3)
7691
+ ...NETWORK_TOOLS,
7692
+ ...WEB_TOOLS,
7693
+ ...DATABASE_TOOLS,
7694
+ ...AD_TOOLS,
7695
+ ...EMAIL_TOOLS,
7696
+ ...REMOTE_ACCESS_TOOLS,
7697
+ ...FILE_SHARING_TOOLS,
7698
+ ...CLOUD_TOOLS,
7699
+ ...CONTAINER_TOOLS,
7700
+ ...API_TOOLS,
7701
+ ...WIRELESS_TOOLS,
7702
+ ...ICS_TOOLS
7136
7703
  ];
7137
7704
  allTools.forEach((t) => this.tools.set(t.name, t));
7138
7705
  }
@@ -7971,7 +8538,7 @@ var __filename2 = fileURLToPath3(import.meta.url);
7971
8538
  var __dirname3 = dirname4(__filename2);
7972
8539
 
7973
8540
  // src/engine/state-persistence.ts
7974
- import { writeFileSync as writeFileSync6, readFileSync as readFileSync4, existsSync as existsSync6, readdirSync, statSync, unlinkSync as unlinkSync3 } from "fs";
8541
+ import { writeFileSync as writeFileSync6, readFileSync as readFileSync4, existsSync as existsSync6, readdirSync, statSync, unlinkSync as unlinkSync4 } from "fs";
7975
8542
  import { join as join9 } from "path";
7976
8543
  function saveState(state) {
7977
8544
  const sessionsDir = WORKSPACE.SESSIONS;
@@ -8006,7 +8573,7 @@ function pruneOldSessions(sessionsDir) {
8006
8573
  })).sort((a, b) => b.mtime - a.mtime);
8007
8574
  const toDelete = sessionFiles.slice(AGENT_LIMITS.MAX_SESSION_FILES);
8008
8575
  for (const file of toDelete) {
8009
- unlinkSync3(file.path);
8576
+ unlinkSync4(file.path);
8010
8577
  }
8011
8578
  } catch {
8012
8579
  }
@@ -8974,22 +9541,22 @@ Please decide how to handle this error and continue.`;
8974
9541
  /** Tools that are safe to run in parallel (read-only or per-key state mutations) */
8975
9542
  static PARALLEL_SAFE_TOOLS = /* @__PURE__ */ new Set([
8976
9543
  // Read-only intelligence tools
8977
- "get_state",
8978
- "parse_nmap",
8979
- "search_cve",
8980
- "web_search",
8981
- "browse_url",
8982
- "read_file",
8983
- "get_owasp_knowledge",
8984
- "get_web_attack_surface",
8985
- "get_cve_info",
8986
- "fill_form",
9544
+ TOOL_NAMES.GET_STATE,
9545
+ TOOL_NAMES.PARSE_NMAP,
9546
+ TOOL_NAMES.SEARCH_CVE,
9547
+ TOOL_NAMES.WEB_SEARCH,
9548
+ TOOL_NAMES.BROWSE_URL,
9549
+ TOOL_NAMES.READ_FILE,
9550
+ TOOL_NAMES.GET_OWASP_KNOWLEDGE,
9551
+ TOOL_NAMES.GET_WEB_ATTACK_SURFACE,
9552
+ TOOL_NAMES.GET_CVE_INFO,
9553
+ TOOL_NAMES.FILL_FORM,
8987
9554
  // State recording (per-key mutations, no external side effects)
8988
- "add_target",
8989
- "add_finding",
8990
- "add_loot",
8991
- "update_mission",
8992
- "update_todo"
9555
+ TOOL_NAMES.ADD_TARGET,
9556
+ TOOL_NAMES.ADD_FINDING,
9557
+ TOOL_NAMES.ADD_LOOT,
9558
+ TOOL_NAMES.UPDATE_MISSION,
9559
+ TOOL_NAMES.UPDATE_TODO
8993
9560
  ]);
8994
9561
  async processToolCalls(toolCalls, progress) {
8995
9562
  if (toolCalls.length <= 1) {
@@ -9303,6 +9870,233 @@ function getTimeAdaptiveStrategy(elapsedMs, deadlineMs) {
9303
9870
  };
9304
9871
  }
9305
9872
 
9873
+ // src/shared/constants/service-ports.ts
9874
+ var SERVICE_PORTS = {
9875
+ SSH: 22,
9876
+ FTP: 21,
9877
+ TELNET: 23,
9878
+ SMTP: 25,
9879
+ DNS: 53,
9880
+ HTTP: 80,
9881
+ POP3: 110,
9882
+ IMAP: 143,
9883
+ SMB_NETBIOS: 139,
9884
+ SMB: 445,
9885
+ HTTPS: 443,
9886
+ MSSQL: 1433,
9887
+ MYSQL: 3306,
9888
+ RDP: 3389,
9889
+ POSTGRESQL: 5432,
9890
+ REDIS: 6379,
9891
+ HTTP_ALT: 8080,
9892
+ HTTPS_ALT: 8443,
9893
+ MONGODB: 27017,
9894
+ ELASTICSEARCH: 9200,
9895
+ MEMCACHED: 11211,
9896
+ NODE_DEFAULT: 3e3,
9897
+ FLASK_DEFAULT: 5e3,
9898
+ DJANGO_DEFAULT: 8e3
9899
+ };
9900
+ var CRITICAL_SERVICE_PORTS = [
9901
+ SERVICE_PORTS.SSH,
9902
+ SERVICE_PORTS.RDP,
9903
+ SERVICE_PORTS.MYSQL,
9904
+ SERVICE_PORTS.POSTGRESQL,
9905
+ SERVICE_PORTS.REDIS,
9906
+ SERVICE_PORTS.MONGODB
9907
+ ];
9908
+ var NO_AUTH_CRITICAL_PORTS = [
9909
+ SERVICE_PORTS.REDIS,
9910
+ SERVICE_PORTS.MONGODB,
9911
+ SERVICE_PORTS.ELASTICSEARCH,
9912
+ SERVICE_PORTS.MEMCACHED
9913
+ ];
9914
+ var WEB_SERVICE_PORTS = [
9915
+ SERVICE_PORTS.HTTP,
9916
+ SERVICE_PORTS.HTTPS,
9917
+ SERVICE_PORTS.HTTP_ALT,
9918
+ SERVICE_PORTS.HTTPS_ALT,
9919
+ SERVICE_PORTS.NODE_DEFAULT,
9920
+ SERVICE_PORTS.FLASK_DEFAULT,
9921
+ SERVICE_PORTS.DJANGO_DEFAULT
9922
+ ];
9923
+ var PLAINTEXT_HTTP_PORTS = [
9924
+ SERVICE_PORTS.HTTP,
9925
+ SERVICE_PORTS.HTTP_ALT,
9926
+ SERVICE_PORTS.NODE_DEFAULT
9927
+ ];
9928
+ var DATABASE_PORTS = [
9929
+ SERVICE_PORTS.MYSQL,
9930
+ SERVICE_PORTS.POSTGRESQL,
9931
+ SERVICE_PORTS.MSSQL,
9932
+ SERVICE_PORTS.MONGODB,
9933
+ SERVICE_PORTS.REDIS
9934
+ ];
9935
+ var SMB_PORTS = [
9936
+ SERVICE_PORTS.SMB,
9937
+ SERVICE_PORTS.SMB_NETBIOS
9938
+ ];
9939
+
9940
+ // src/shared/constants/scoring.ts
9941
+ var ATTACK_SCORING = {
9942
+ /** Base score for all attack prioritization */
9943
+ BASE_SCORE: 50,
9944
+ /** Maximum possible score */
9945
+ MAX_SCORE: 100,
9946
+ /** Bonus for critical infrastructure services (SSH, RDP, DB, etc.) */
9947
+ CRITICAL_SERVICE_BONUS: 20,
9948
+ /** Bonus when service version is known (enables CVE lookup) */
9949
+ VERSION_KNOWN_BONUS: 15,
9950
+ /** Bonus when known critical CVE exists for the service version */
9951
+ CRITICAL_CVE_BONUS: 30,
9952
+ /** Bonus for sensitive services running without authentication */
9953
+ NO_AUTH_BONUS: 25,
9954
+ /** Bonus for plaintext HTTP on service ports (no HTTPS) */
9955
+ PLAINTEXT_HTTP_BONUS: 10
9956
+ };
9957
+
9958
+ // src/shared/utils/attack-knowledge-base.ts
9959
+ var SERVICE_VULN_MAP = {
9960
+ // Apache
9961
+ "apache/2.4.49": {
9962
+ cves: ["CVE-2021-41773"],
9963
+ exploits: ['curl --path-as-is "http://TARGET/cgi-bin/.%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd"'],
9964
+ priority: "critical",
9965
+ checks: ["Path traversal to RCE"]
9966
+ },
9967
+ "apache/2.4.50": {
9968
+ cves: ["CVE-2021-42013"],
9969
+ exploits: ['curl --path-as-is "http://TARGET/cgi-bin/.%%32%65/.%%32%65/.%%32%65/.%%32%65/etc/passwd"'],
9970
+ priority: "critical",
9971
+ checks: ["Path traversal bypass"]
9972
+ },
9973
+ // SSH
9974
+ "openssh/7.2": {
9975
+ cves: ["CVE-2016-10009", "CVE-2016-10010"],
9976
+ exploits: ["Check for Roaming auth bypass"],
9977
+ priority: "medium",
9978
+ checks: ["Version disclosure", "Weak algorithms"]
9979
+ },
9980
+ // vsftpd
9981
+ "vsftpd/2.3.4": {
9982
+ cves: ["CVE-2011-2523"],
9983
+ exploits: ["Connect with username containing :) to trigger backdoor on port 6200"],
9984
+ priority: "critical",
9985
+ checks: ["Backdoor trigger: user:)"]
9986
+ },
9987
+ // SMB
9988
+ "samba/3.0": {
9989
+ cves: ["CVE-2004-0882"],
9990
+ exploits: ["trans2open exploit"],
9991
+ priority: "high",
9992
+ checks: ["SMBv1 enabled"]
9993
+ },
9994
+ "smb": {
9995
+ cves: ["MS17-010"],
9996
+ exploits: ["EternalBlue exploit"],
9997
+ priority: "critical",
9998
+ checks: ["nmap --script smb-vuln-ms17-010"]
9999
+ },
10000
+ // MySQL
10001
+ "mysql/5.0": {
10002
+ cves: ["CVE-2012-2122"],
10003
+ exploits: ["MariaDB/CMySQL authentication bypass"],
10004
+ priority: "high",
10005
+ checks: ["Try root without password", "mysql -u root"]
10006
+ },
10007
+ // Redis
10008
+ "redis": {
10009
+ cves: [],
10010
+ exploits: ["Unauthenticated RCE via CONFIG SET dir + SLAVEOF"],
10011
+ priority: "critical",
10012
+ checks: ["redis-cli -h TARGET ping", "CONFIG GET dir"]
10013
+ },
10014
+ // Jenkins
10015
+ "jenkins": {
10016
+ cves: [],
10017
+ exploits: ["Script Console RCE", "CVE-2019-1003000"],
10018
+ priority: "high",
10019
+ checks: ["/scriptText endpoint", "/manage/scriptConsole"]
10020
+ },
10021
+ // Elasticsearch
10022
+ "elasticsearch/1": {
10023
+ cves: ["CVE-2014-3120"],
10024
+ exploits: ["Groovy sandbox bypass RCE"],
10025
+ priority: "critical",
10026
+ checks: ["Dynamic script execution"]
10027
+ }
10028
+ };
10029
+
10030
+ // src/shared/utils/attack-intelligence.ts
10031
+ function calculateAttackPriority(findings) {
10032
+ let score = ATTACK_SCORING.BASE_SCORE;
10033
+ if (CRITICAL_SERVICE_PORTS.includes(findings.port)) {
10034
+ score += ATTACK_SCORING.CRITICAL_SERVICE_BONUS;
10035
+ }
10036
+ if (findings.version) {
10037
+ score += ATTACK_SCORING.VERSION_KNOWN_BONUS;
10038
+ const key = `${findings.service.toLowerCase()}/${findings.version.split(".")[0]}`;
10039
+ if (SERVICE_VULN_MAP[key]?.priority === "critical") {
10040
+ score += ATTACK_SCORING.CRITICAL_CVE_BONUS;
10041
+ }
10042
+ }
10043
+ if (!findings.hasAuth && NO_AUTH_CRITICAL_PORTS.includes(findings.port)) {
10044
+ score += ATTACK_SCORING.NO_AUTH_BONUS;
10045
+ }
10046
+ if (PLAINTEXT_HTTP_PORTS.includes(findings.port) && !findings.isHttps) {
10047
+ score += ATTACK_SCORING.PLAINTEXT_HTTP_BONUS;
10048
+ }
10049
+ return Math.min(score, ATTACK_SCORING.MAX_SCORE);
10050
+ }
10051
+ function getAttacksForService(service, port) {
10052
+ const attacks = [];
10053
+ const svc = service.toLowerCase();
10054
+ if (WEB_SERVICE_PORTS.includes(port)) {
10055
+ attacks.push(
10056
+ "OWASP-A01: Directory brute force",
10057
+ "OWASP-A03: SQLi testing",
10058
+ "OWASP-A03: XSS testing",
10059
+ "OWASP-A05: Header analysis",
10060
+ "OWASP-A10: SSRF testing",
10061
+ "OWASP-A06: Version fingerprinting"
10062
+ );
10063
+ }
10064
+ if (port === SERVICE_PORTS.SSH || svc.includes("ssh")) {
10065
+ attacks.push(
10066
+ "SSH version scan",
10067
+ "Brute force common credentials",
10068
+ "SSH key enumeration",
10069
+ "Check for weak algorithms"
10070
+ );
10071
+ }
10072
+ if (SMB_PORTS.includes(port) || svc.includes("smb")) {
10073
+ attacks.push(
10074
+ "MS17-010 EternalBlue check",
10075
+ "SMB enumeration",
10076
+ "Null session test",
10077
+ "Share enumeration"
10078
+ );
10079
+ }
10080
+ if (DATABASE_PORTS.includes(port) || svc.includes("sql") || svc.includes("mongo") || svc.includes("redis")) {
10081
+ attacks.push(
10082
+ "Default credential test",
10083
+ "Unauthenticated access check",
10084
+ "SQLi through web app",
10085
+ "UDF injection",
10086
+ "NoSQL injection"
10087
+ );
10088
+ }
10089
+ if (port === SERVICE_PORTS.FTP || svc.includes("ftp")) {
10090
+ attacks.push(
10091
+ "Anonymous login test",
10092
+ "Brute force credentials",
10093
+ "VSFTPD backdoor check",
10094
+ "Directory traversal"
10095
+ );
10096
+ }
10097
+ return attacks;
10098
+ }
10099
+
9306
10100
  // src/agents/prompt-builder.ts
9307
10101
  var __dirname4 = dirname5(fileURLToPath4(import.meta.url));
9308
10102
  var PROMPTS_DIR = join10(__dirname4, "prompts");
@@ -9366,6 +10160,7 @@ var PromptBuilder = class {
9366
10160
  * 8. Time awareness + adaptive strategy (#8)
9367
10161
  * 9. Challenge analysis (#2: Auto-Prompter)
9368
10162
  * 10. Attack graph (#6: recommended attack chains)
10163
+ * 10b. Attack intelligence — per-service attack suggestions
9369
10164
  * 11. Working memory (#12: failed/succeeded attempts)
9370
10165
  * 12. Session timeline (#12: episodic memory)
9371
10166
  * 13. Learned techniques (#7: dynamic technique library)
@@ -9387,6 +10182,8 @@ var PromptBuilder = class {
9387
10182
  // #2
9388
10183
  this.getAttackGraphFragment(),
9389
10184
  // #6
10185
+ this.getAttackIntelligenceFragment(),
10186
+ // service-specific attacks
9390
10187
  this.getWorkingMemoryFragment(),
9391
10188
  // #12
9392
10189
  this.getEpisodicMemoryFragment(),
@@ -9540,6 +10337,30 @@ ${strategy.directive}
9540
10337
  getAttackGraphFragment() {
9541
10338
  return this.state.attackGraph.toPrompt();
9542
10339
  }
10340
+ // --- Attack Intelligence: per-service bootstrapped attack suggestions ---
10341
+ getAttackIntelligenceFragment() {
10342
+ const targets = this.state.getAllTargets();
10343
+ if (targets.length === 0) return "";
10344
+ const lines = [];
10345
+ for (const target of targets) {
10346
+ for (const port of target.ports) {
10347
+ const attacks = getAttacksForService(port.service || "", port.port);
10348
+ if (attacks.length === 0) continue;
10349
+ const priority = calculateAttackPriority({
10350
+ service: port.service || "",
10351
+ version: port.version,
10352
+ port: port.port
10353
+ });
10354
+ lines.push(`[${target.ip}:${port.port}] ${port.service || "unknown"} (priority: ${priority}/100)`);
10355
+ attacks.forEach((a) => lines.push(` - ${a}`));
10356
+ }
10357
+ }
10358
+ if (lines.length === 0) return "";
10359
+ return `<attack-intelligence>
10360
+ Bootstrap attack suggestions (try these first, adapt if they fail):
10361
+ ${lines.join("\n")}
10362
+ </attack-intelligence>`;
10363
+ }
9543
10364
  // --- Improvement #12: Working Memory ---
9544
10365
  getWorkingMemoryFragment() {
9545
10366
  return this.state.workingMemory.toPrompt();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pentesting",
3
- "version": "0.40.1",
3
+ "version": "0.40.3",
4
4
  "description": "Autonomous Penetration Testing AI Agent",
5
5
  "type": "module",
6
6
  "main": "dist/main.js",