pentesting 0.56.2 → 0.56.4

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 +131 -26
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -711,7 +711,7 @@ var INPUT_PROMPT_PATTERNS = [
711
711
 
712
712
  // src/shared/constants/agent.ts
713
713
  var APP_NAME = "Pentest AI";
714
- var APP_VERSION = "0.56.2";
714
+ var APP_VERSION = "0.56.4";
715
715
  var APP_DESCRIPTION = "Autonomous Penetration Testing AI Agent";
716
716
  var LLM_ROLES = {
717
717
  SYSTEM: "system",
@@ -14803,20 +14803,28 @@ var createSessionCommands = (ctx) => ({
14803
14803
 
14804
14804
  // src/platform/tui/hooks/commands/target-commands.ts
14805
14805
  var createTargetCommands = (ctx) => ({
14806
- [UI_COMMANDS.TARGET]: (args) => {
14806
+ [UI_COMMANDS.TARGET]: async (args) => {
14807
14807
  if (!args[0]) {
14808
14808
  ctx.addMessage("error", "Usage: /target <ip>");
14809
14809
  return;
14810
14810
  }
14811
+ if (ctx.agent.getState().getTargets().size > 0) {
14812
+ await ctx.agent.resetSession();
14813
+ ctx.addMessage("system", "Previous target data cleared. Starting fresh session for the new target.");
14814
+ }
14811
14815
  ctx.agent.addTarget(args[0]);
14812
14816
  ctx.agent.setScope([args[0]]);
14813
14817
  ctx.addMessage("system", `Target \u2192 ${args[0]}`);
14814
14818
  },
14815
- [UI_COMMANDS.TARGET_SHORT]: (args) => {
14819
+ [UI_COMMANDS.TARGET_SHORT]: async (args) => {
14816
14820
  if (!args[0]) {
14817
14821
  ctx.addMessage("error", "Usage: /target <ip>");
14818
14822
  return;
14819
14823
  }
14824
+ if (ctx.agent.getState().getTargets().size > 0) {
14825
+ await ctx.agent.resetSession();
14826
+ ctx.addMessage("system", "Previous target data cleared. Starting fresh session for the new target.");
14827
+ }
14820
14828
  ctx.agent.addTarget(args[0]);
14821
14829
  ctx.agent.setScope([args[0]]);
14822
14830
  ctx.addMessage("system", `Target \u2192 ${args[0]}`);
@@ -14929,6 +14937,15 @@ var boxLine = (content, width) => {
14929
14937
  const truncated = content.length > inner ? content.slice(0, inner - 1) + "\u2026" : content;
14930
14938
  return `\u2502 ${truncated.padEnd(inner - 1)}`;
14931
14939
  };
14940
+ var formatTargetLine = (target) => {
14941
+ if (target.ports.length === 0) return target.ip;
14942
+ const portList = target.ports.map((p) => `${p.port}`).join(", ");
14943
+ return `${target.ip} \u2192 ${target.ip}:${portList}`;
14944
+ };
14945
+ var formatServiceLabel = (target, port) => {
14946
+ const svc = port.version ? `${port.service}/${port.version}` : port.service;
14947
+ return `${target.ip}:${port.port} (${svc})`;
14948
+ };
14932
14949
  var formatFindingsWithFlags = (findings, flags) => {
14933
14950
  const findingsOutput = formatFindings(findings);
14934
14951
  const flagsOutput = formatFlags(flags);
@@ -14938,41 +14955,108 @@ ${flagsOutput}`;
14938
14955
  }
14939
14956
  return findingsOutput;
14940
14957
  };
14941
- var formatGraphWithSummary = (_graphASCII, findings, flags) => {
14958
+ var formatGraphWithSummary = (state, findings, flags) => {
14942
14959
  const lines = [];
14943
14960
  const w = getBoxWidth();
14944
14961
  const innerDash = w - 2;
14945
- lines.push(`\u250C${"\u2500".repeat(innerDash)}\u2510`);
14946
- lines.push(boxLine(`\u{1F5A5} 1 \u26A0 ${findings.length} \u2699 1`, w));
14947
- lines.push(boxLine("", w));
14948
- lines.push(boxLine("\u{1F5A5} HOST (1)", w));
14949
- lines.push(boxLine(` \u25CB 138.2.89.94 \u2192 138.2.89.94:443`, w));
14962
+ const targets = state.getAllTargets();
14963
+ const graphStats = state.attackGraph.getStats();
14964
+ const allNodes = state.attackGraph.getAllNodes();
14965
+ const hostNodes = allNodes.filter((n) => n.type === NODE_TYPE.HOST);
14966
+ const serviceNodes = allNodes.filter((n) => n.type === NODE_TYPE.SERVICE);
14967
+ const vulnNodes = allNodes.filter((n) => n.type === NODE_TYPE.VULNERABILITY);
14968
+ const hostCount = hostNodes.length || targets.length;
14969
+ const serviceCount = serviceNodes.length || targets.reduce((sum, t) => sum + t.ports.length, 0);
14970
+ const vulnCount = findings.length;
14971
+ const topTitle = "\u2500\u2500\u2500 Attack Graph ";
14972
+ lines.push(`\u250C${topTitle}${"\u2500".repeat(Math.max(0, innerDash - topTitle.length))}\u2510`);
14973
+ lines.push(boxLine(`\u{1F5A5} ${hostCount} \u26A0 ${vulnCount} \u2699 ${serviceCount}`, w));
14950
14974
  lines.push(boxLine("", w));
14951
- lines.push(boxLine(`\u26A0 VULNERABILITY (${findings.length})`, w));
14952
- const sortedFindings = [...findings].sort((a, b) => b.confidence - a.confidence).slice(0, 5);
14953
- for (const f of sortedFindings) {
14954
- const icon = confIcon(f.confidence);
14955
- const cat = f.category ? ` \u2502 ${f.category}` : "";
14956
- lines.push(boxLine(` \u25CB ${icon} ${f.title.slice(0, 60)}${f.title.length > 60 ? "..." : ""}`, w));
14957
- lines.push(boxLine(` ${confLabel(f.confidence).toUpperCase()} \u2502 ${f.severity.toUpperCase()}${cat}`, w));
14975
+ lines.push(boxLine(`\u{1F5A5} HOST (${hostCount})`, w));
14976
+ if (targets.length > 0) {
14977
+ for (const t of targets.slice(0, 5)) {
14978
+ lines.push(boxLine(` \u25CB ${formatTargetLine(t)}`, w));
14979
+ }
14980
+ if (targets.length > 5) {
14981
+ lines.push(boxLine(` ... and ${targets.length - 5} more hosts`, w));
14982
+ }
14983
+ } else if (hostNodes.length > 0) {
14984
+ for (const node of hostNodes.slice(0, 5)) {
14985
+ lines.push(boxLine(` \u25CB ${node.label}`, w));
14986
+ }
14987
+ if (hostNodes.length > 5) {
14988
+ lines.push(boxLine(` ... and ${hostNodes.length - 5} more hosts`, w));
14989
+ }
14990
+ } else {
14991
+ lines.push(boxLine(" (no hosts discovered)", w));
14958
14992
  }
14959
- if (findings.length > 5) {
14960
- lines.push(boxLine(` ... and ${findings.length - 5} more findings`, w));
14993
+ lines.push(boxLine("", w));
14994
+ lines.push(boxLine(`\u26A0 VULNERABILITY (${vulnCount})`, w));
14995
+ if (findings.length > 0) {
14996
+ const sortedFindings = [...findings].sort((a, b) => b.confidence - a.confidence).slice(0, 5);
14997
+ for (const f of sortedFindings) {
14998
+ const icon = confIcon(f.confidence);
14999
+ const cat = f.category ? ` \u2502 ${f.category}` : "";
15000
+ lines.push(boxLine(` \u25CB ${icon} ${f.title.slice(0, 60)}${f.title.length > 60 ? "..." : ""}`, w));
15001
+ lines.push(boxLine(` ${confLabel(f.confidence).toUpperCase()} \u2502 ${f.severity.toUpperCase()}${cat}`, w));
15002
+ }
15003
+ if (findings.length > 5) {
15004
+ lines.push(boxLine(` ... and ${findings.length - 5} more findings`, w));
15005
+ }
15006
+ } else if (vulnNodes.length > 0) {
15007
+ for (const node of vulnNodes.slice(0, 5)) {
15008
+ lines.push(boxLine(` \u25CB ${node.label}`, w));
15009
+ }
15010
+ if (vulnNodes.length > 5) {
15011
+ lines.push(boxLine(` ... and ${vulnNodes.length - 5} more`, w));
15012
+ }
15013
+ } else {
15014
+ lines.push(boxLine(" (no vulnerabilities found)", w));
14961
15015
  }
14962
15016
  const cveFindings = findings.filter((f) => f.title.includes("CVE"));
14963
15017
  if (cveFindings.length > 0) {
14964
- lines.push(boxLine(` \u25CB CVE search: https nginx/1.24.0 (Ubuntu) -> Apache CouchDB 3.5.1`, w));
15018
+ const cveList = cveFindings.slice(0, 3).map((f) => f.title.match(/CVE-\d{4}-\d+/)?.[0] ?? f.title).join(", ");
15019
+ const suffix = cveFindings.length > 3 ? ` (+${cveFindings.length - 3} more)` : "";
15020
+ lines.push(boxLine(` \u25CB CVE found: ${cveList}${suffix}`, w));
14965
15021
  }
14966
15022
  lines.push(boxLine("", w));
14967
- lines.push(boxLine("\u2699 SERVICE (1)", w));
14968
- lines.push(boxLine(` \u25CB 138.2.89.94:443 (nginx/1.24.0 (Ubuntu) -> Apache CouchDB 3.5.1)`, w));
15023
+ lines.push(boxLine(`\u2699 SERVICE (${serviceCount})`, w));
15024
+ if (targets.length > 0) {
15025
+ let shownServices = 0;
15026
+ const maxShow = 5;
15027
+ for (const t of targets) {
15028
+ for (const p of t.ports) {
15029
+ if (shownServices >= maxShow) break;
15030
+ lines.push(boxLine(` \u25CB ${formatServiceLabel(t, p)}`, w));
15031
+ shownServices++;
15032
+ }
15033
+ if (shownServices >= maxShow) break;
15034
+ }
15035
+ const totalServices = targets.reduce((sum, t) => sum + t.ports.length, 0);
15036
+ if (totalServices > maxShow) {
15037
+ lines.push(boxLine(` ... and ${totalServices - maxShow} more services`, w));
15038
+ }
15039
+ } else if (serviceNodes.length > 0) {
15040
+ for (const node of serviceNodes.slice(0, 5)) {
15041
+ lines.push(boxLine(` \u25CB ${node.label}`, w));
15042
+ }
15043
+ if (serviceNodes.length > 5) {
15044
+ lines.push(boxLine(` ... and ${serviceNodes.length - 5} more`, w));
15045
+ }
15046
+ } else {
15047
+ lines.push(boxLine(" (no services discovered)", w));
15048
+ }
14969
15049
  if (flags.length > 0) {
14970
15050
  lines.push(boxLine("", w));
14971
15051
  lines.push(boxLine(`\u{1F3F4} Captured: ${flags.length}`, w));
14972
15052
  }
14973
15053
  lines.push(boxLine("", w));
14974
- lines.push(`\u251C${"\u2500".repeat(innerDash)}\u2524`);
14975
- lines.push(boxLine(`Nodes: ${findings.length + 2} | Edges: 2 | Succeeded: 0 | Failed: 0 | Chains: 0`, w));
15054
+ const midTitle = "\u2500\u2500\u2500 Summary ";
15055
+ lines.push(`\u251C${midTitle}${"\u2500".repeat(Math.max(0, innerDash - midTitle.length))}\u2524`);
15056
+ lines.push(boxLine(
15057
+ `Nodes: ${graphStats.nodes} | Edges: ${graphStats.edges} | Succeeded: ${graphStats.succeeded} | Failed: ${graphStats.failed} | Chains: ${graphStats.chains}`,
15058
+ w
15059
+ ));
14976
15060
  lines.push(`\u2514${"\u2500".repeat(innerDash)}\u2518`);
14977
15061
  return lines.join("\n");
14978
15062
  };
@@ -15031,7 +15115,7 @@ ${procData.stdout || "(no output)"}
15031
15115
  const flags = state.getFlags();
15032
15116
  const graphASCII = state.attackGraph.toASCII();
15033
15117
  if (state.attackGraph.isEmpty() && (findings.length > 0 || flags.length > 0)) {
15034
- ctx.showModal("graph", formatGraphWithSummary(graphASCII, findings, flags));
15118
+ ctx.showModal("graph", formatGraphWithSummary(state, findings, flags));
15035
15119
  } else {
15036
15120
  let output = graphASCII;
15037
15121
  if (flags.length > 0) {
@@ -15046,7 +15130,7 @@ ${procData.stdout || "(no output)"}
15046
15130
  const flags = state.getFlags();
15047
15131
  const graphASCII = state.attackGraph.toASCII();
15048
15132
  if (state.attackGraph.isEmpty() && (findings.length > 0 || flags.length > 0)) {
15049
- ctx.showModal("graph", formatGraphWithSummary(graphASCII, findings, flags));
15133
+ ctx.showModal("graph", formatGraphWithSummary(state, findings, flags));
15050
15134
  } else {
15051
15135
  let output = graphASCII;
15052
15136
  if (flags.length > 0) {
@@ -16306,6 +16390,27 @@ var ChatInput = memo10(({
16306
16390
  setSelectedIdx(0);
16307
16391
  setInputKey((k) => k + 1);
16308
16392
  }, []);
16393
+ const onSubmitRef = useRef8(onSubmit);
16394
+ onSubmitRef.current = onSubmit;
16395
+ const wrappedOnSubmit = useCallback9((val) => {
16396
+ if (showPreviewRef.current) {
16397
+ const sug = suggestionsRef.current;
16398
+ if (!sug.length) {
16399
+ onSubmitRef.current(val);
16400
+ return;
16401
+ }
16402
+ const best = sug[Math.min(selectedIdxRef.current, sug.length - 1)];
16403
+ if (best.args) {
16404
+ completeCommand(selectedIdxRef.current);
16405
+ } else {
16406
+ const completed = `/${best.name}`;
16407
+ onChangeRef.current(completed);
16408
+ onSubmitRef.current(completed);
16409
+ }
16410
+ return;
16411
+ }
16412
+ onSubmitRef.current(val);
16413
+ }, [completeCommand]);
16309
16414
  useInput3(useCallback9((_input, key) => {
16310
16415
  if (inputRequestRef.current.status === "active") return;
16311
16416
  const sug = suggestionsRef.current;
@@ -16349,7 +16454,7 @@ var ChatInput = memo10(({
16349
16454
  inputKey,
16350
16455
  value,
16351
16456
  onChange,
16352
- onSubmit,
16457
+ onSubmit: wrappedOnSubmit,
16353
16458
  placeholder
16354
16459
  }
16355
16460
  )
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pentesting",
3
- "version": "0.56.2",
3
+ "version": "0.56.4",
4
4
  "description": "Autonomous Penetration Testing AI Agent",
5
5
  "type": "module",
6
6
  "main": "dist/main.js",