pentesting 0.21.9 → 0.21.11

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 (3) hide show
  1. package/README.md +3 -0
  2. package/dist/main.js +179 -43
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -36,3 +36,6 @@ docker run -it --rm \
36
36
  agnusdei1207/pentesting
37
37
  ```
38
38
 
39
+ ## Issue
40
+
41
+ email: agnusdei1207@gmail.com
package/dist/main.js CHANGED
@@ -157,7 +157,7 @@ var EXIT_CODES = {
157
157
  var ID_LENGTH = AGENT_LIMITS.ID_LENGTH;
158
158
  var ID_RADIX = AGENT_LIMITS.ID_RADIX;
159
159
  var APP_NAME = "Pentest AI";
160
- var APP_VERSION = "0.21.9";
160
+ var APP_VERSION = "0.21.11";
161
161
  var APP_DESCRIPTION = "Autonomous Penetration Testing AI Agent";
162
162
  var LLM_ROLES = {
163
163
  SYSTEM: "system",
@@ -2995,12 +2995,57 @@ var SEARCH_LIMIT = {
2995
2995
  // src/shared/utils/debug-logger.ts
2996
2996
  import { appendFileSync as appendFileSync2, writeFileSync as writeFileSync3 } from "fs";
2997
2997
  import { join as join2 } from "path";
2998
+
2999
+ // src/shared/constants/paths.ts
3000
+ import path2 from "path";
3001
+ import { fileURLToPath as fileURLToPath2 } from "url";
3002
+ import { homedir } from "os";
3003
+ var __filename2 = fileURLToPath2(import.meta.url);
3004
+ var __dirname2 = path2.dirname(__filename2);
3005
+ var PROJECT_ROOT = path2.resolve(__dirname2, "../../../");
3006
+ var WORKSPACE_DIR_NAME = ".pentesting";
3007
+ function getWorkspaceRoot() {
3008
+ return path2.join(homedir(), WORKSPACE_DIR_NAME);
3009
+ }
3010
+ var WORKSPACE = {
3011
+ /** Root directory (resolved lazily via getWorkspaceRoot) */
3012
+ get ROOT() {
3013
+ return getWorkspaceRoot();
3014
+ },
3015
+ /** Per-session state snapshots */
3016
+ get SESSIONS() {
3017
+ return path2.join(getWorkspaceRoot(), "sessions");
3018
+ },
3019
+ /** Debug logs */
3020
+ get DEBUG() {
3021
+ return path2.join(getWorkspaceRoot(), "debug");
3022
+ },
3023
+ /** Generated reports */
3024
+ get REPORTS() {
3025
+ return path2.join(getWorkspaceRoot(), "reports");
3026
+ },
3027
+ /** Downloaded loot, captured files */
3028
+ get LOOT() {
3029
+ return path2.join(getWorkspaceRoot(), "loot");
3030
+ },
3031
+ /** Temporary files for active operations */
3032
+ get TEMP() {
3033
+ return path2.join(getWorkspaceRoot(), "temp");
3034
+ }
3035
+ };
3036
+ var PATHS = {
3037
+ ROOT: PROJECT_ROOT,
3038
+ SRC: path2.join(PROJECT_ROOT, "src"),
3039
+ DIST: path2.join(PROJECT_ROOT, "dist")
3040
+ };
3041
+
3042
+ // src/shared/utils/debug-logger.ts
2998
3043
  var DebugLogger = class _DebugLogger {
2999
3044
  static instance;
3000
3045
  logPath;
3001
3046
  initialized = false;
3002
3047
  constructor(clearOnInit = false) {
3003
- const debugDir = join2(process.cwd(), ".pentesting", "debug");
3048
+ const debugDir = WORKSPACE.DEBUG;
3004
3049
  try {
3005
3050
  ensureDirExists(debugDir);
3006
3051
  this.logPath = join2(debugDir, "debug.log");
@@ -3071,7 +3116,8 @@ function debugLog(category, message, data) {
3071
3116
  }
3072
3117
 
3073
3118
  // src/engine/tools/web-browser.ts
3074
- import { join as join5, tmpdir as tmpdir3 } from "path";
3119
+ import { join as join5 } from "path";
3120
+ import { tmpdir as tmpdir3 } from "os";
3075
3121
 
3076
3122
  // src/shared/constants/browser/config.ts
3077
3123
  var BROWSER_CONFIG = {
@@ -3188,7 +3234,8 @@ async function installPlaywright() {
3188
3234
  // src/engine/tools/web-browser-script.ts
3189
3235
  import { spawn as spawn4 } from "child_process";
3190
3236
  import { writeFileSync as writeFileSync4, unlinkSync as unlinkSync2 } from "fs";
3191
- import { join as join4, tmpdir as tmpdir2 } from "path";
3237
+ import { join as join4 } from "path";
3238
+ import { tmpdir as tmpdir2 } from "os";
3192
3239
  function safeJsString(str) {
3193
3240
  return JSON.stringify(str);
3194
3241
  }
@@ -4683,8 +4730,8 @@ Returns: All available wordlists with their paths, sizes, and categories.`,
4683
4730
  }
4684
4731
  },
4685
4732
  execute: async (p) => {
4686
- const { existsSync: existsSync6, statSync, readdirSync: readdirSync2 } = await import("fs");
4687
- const { join: join9 } = await import("path");
4733
+ const { existsSync: existsSync7, statSync: statSync2, readdirSync: readdirSync3 } = await import("fs");
4734
+ const { join: join10 } = await import("path");
4688
4735
  const category = p.category || "";
4689
4736
  const search = p.search || "";
4690
4737
  const minSize = p.min_size || 0;
@@ -4699,11 +4746,11 @@ Returns: All available wordlists with their paths, sizes, and categories.`,
4699
4746
  let totalCount = 0;
4700
4747
  const scanDir = (dirPath, maxDepth = 3, currentDepth = 0) => {
4701
4748
  if (currentDepth > maxDepth) return;
4702
- if (!existsSync6(dirPath)) return;
4749
+ if (!existsSync7(dirPath)) return;
4703
4750
  try {
4704
- const entries = readdirSync2(dirPath, { withFileTypes: true });
4751
+ const entries = readdirSync3(dirPath, { withFileTypes: true });
4705
4752
  for (const entry of entries) {
4706
- const fullPath = join9(dirPath, entry.name);
4753
+ const fullPath = join10(dirPath, entry.name);
4707
4754
  if (entry.isDirectory()) {
4708
4755
  if (entry.name.startsWith(".")) continue;
4709
4756
  if (entry.name === "doc") continue;
@@ -4714,7 +4761,7 @@ Returns: All available wordlists with their paths, sizes, and categories.`,
4714
4761
  continue;
4715
4762
  }
4716
4763
  try {
4717
- const stats = statSync(fullPath);
4764
+ const stats = statSync2(fullPath);
4718
4765
  const sizeBytes = stats.size;
4719
4766
  if (sizeBytes < minSize) continue;
4720
4767
  const relPath = fullPath;
@@ -5124,8 +5171,8 @@ Requires root/sudo privileges.`,
5124
5171
  const iface = p.interface || "";
5125
5172
  const duration = p.duration || NETWORK_CONFIG.DEFAULT_SPOOF_DURATION;
5126
5173
  const hostsFile = createTempFile(".hosts");
5127
- const { writeFileSync: writeFileSync5 } = await import("fs");
5128
- writeFileSync5(hostsFile, `${spoofIp} ${domain}
5174
+ const { writeFileSync: writeFileSync6 } = await import("fs");
5175
+ writeFileSync6(hostsFile, `${spoofIp} ${domain}
5129
5176
  ${spoofIp} *.${domain}
5130
5177
  `);
5131
5178
  const ifaceFlag = iface ? `-i ${iface}` : "";
@@ -5828,80 +5875,80 @@ var ServiceParser = class {
5828
5875
 
5829
5876
  // src/domains/registry.ts
5830
5877
  import { join as join6, dirname as dirname3 } from "path";
5831
- import { fileURLToPath as fileURLToPath2 } from "url";
5832
- var __dirname2 = dirname3(fileURLToPath2(import.meta.url));
5878
+ import { fileURLToPath as fileURLToPath3 } from "url";
5879
+ var __dirname3 = dirname3(fileURLToPath3(import.meta.url));
5833
5880
  var DOMAINS = {
5834
5881
  [SERVICE_CATEGORIES.NETWORK]: {
5835
5882
  id: SERVICE_CATEGORIES.NETWORK,
5836
5883
  name: "Network Infrastructure",
5837
5884
  description: "Vulnerability scanning, port mapping, and network service exploitation.",
5838
- promptPath: join6(__dirname2, "network/prompt.md")
5885
+ promptPath: join6(__dirname3, "network/prompt.md")
5839
5886
  },
5840
5887
  [SERVICE_CATEGORIES.WEB]: {
5841
5888
  id: SERVICE_CATEGORIES.WEB,
5842
5889
  name: "Web Application",
5843
5890
  description: "Web app security testing, injection attacks, and auth bypass.",
5844
- promptPath: join6(__dirname2, "web/prompt.md")
5891
+ promptPath: join6(__dirname3, "web/prompt.md")
5845
5892
  },
5846
5893
  [SERVICE_CATEGORIES.DATABASE]: {
5847
5894
  id: SERVICE_CATEGORIES.DATABASE,
5848
5895
  name: "Database Security",
5849
5896
  description: "SQL injection, database enumeration, and data extraction.",
5850
- promptPath: join6(__dirname2, "database/prompt.md")
5897
+ promptPath: join6(__dirname3, "database/prompt.md")
5851
5898
  },
5852
5899
  [SERVICE_CATEGORIES.AD]: {
5853
5900
  id: SERVICE_CATEGORIES.AD,
5854
5901
  name: "Active Directory",
5855
5902
  description: "Kerberos, LDAP, and Windows domain privilege escalation.",
5856
- promptPath: join6(__dirname2, "ad/prompt.md")
5903
+ promptPath: join6(__dirname3, "ad/prompt.md")
5857
5904
  },
5858
5905
  [SERVICE_CATEGORIES.EMAIL]: {
5859
5906
  id: SERVICE_CATEGORIES.EMAIL,
5860
5907
  name: "Email Services",
5861
5908
  description: "SMTP, IMAP, POP3 security and user enumeration.",
5862
- promptPath: join6(__dirname2, "email/prompt.md")
5909
+ promptPath: join6(__dirname3, "email/prompt.md")
5863
5910
  },
5864
5911
  [SERVICE_CATEGORIES.REMOTE_ACCESS]: {
5865
5912
  id: SERVICE_CATEGORIES.REMOTE_ACCESS,
5866
5913
  name: "Remote Access",
5867
5914
  description: "SSH, RDP, VNC and other remote control protocols.",
5868
- promptPath: join6(__dirname2, "remote-access/prompt.md")
5915
+ promptPath: join6(__dirname3, "remote-access/prompt.md")
5869
5916
  },
5870
5917
  [SERVICE_CATEGORIES.FILE_SHARING]: {
5871
5918
  id: SERVICE_CATEGORIES.FILE_SHARING,
5872
5919
  name: "File Sharing",
5873
5920
  description: "SMB, NFS, FTP and shared resource security.",
5874
- promptPath: join6(__dirname2, "file-sharing/prompt.md")
5921
+ promptPath: join6(__dirname3, "file-sharing/prompt.md")
5875
5922
  },
5876
5923
  [SERVICE_CATEGORIES.CLOUD]: {
5877
5924
  id: SERVICE_CATEGORIES.CLOUD,
5878
5925
  name: "Cloud Infrastructure",
5879
5926
  description: "AWS, Azure, and GCP security and misconfiguration.",
5880
- promptPath: join6(__dirname2, "cloud/prompt.md")
5927
+ promptPath: join6(__dirname3, "cloud/prompt.md")
5881
5928
  },
5882
5929
  [SERVICE_CATEGORIES.CONTAINER]: {
5883
5930
  id: SERVICE_CATEGORIES.CONTAINER,
5884
5931
  name: "Container Systems",
5885
5932
  description: "Docker and Kubernetes security testing.",
5886
- promptPath: join6(__dirname2, "container/prompt.md")
5933
+ promptPath: join6(__dirname3, "container/prompt.md")
5887
5934
  },
5888
5935
  [SERVICE_CATEGORIES.API]: {
5889
5936
  id: SERVICE_CATEGORIES.API,
5890
5937
  name: "API Security",
5891
5938
  description: "REST, GraphQL, and SOAP API security testing.",
5892
- promptPath: join6(__dirname2, "api/prompt.md")
5939
+ promptPath: join6(__dirname3, "api/prompt.md")
5893
5940
  },
5894
5941
  [SERVICE_CATEGORIES.WIRELESS]: {
5895
5942
  id: SERVICE_CATEGORIES.WIRELESS,
5896
5943
  name: "Wireless Networks",
5897
5944
  description: "WiFi and Bluetooth security testing.",
5898
- promptPath: join6(__dirname2, "wireless/prompt.md")
5945
+ promptPath: join6(__dirname3, "wireless/prompt.md")
5899
5946
  },
5900
5947
  [SERVICE_CATEGORIES.ICS]: {
5901
5948
  id: SERVICE_CATEGORIES.ICS,
5902
5949
  name: "Industrial Systems",
5903
5950
  description: "Critical infrastructure - Modbus, DNP3, ENIP.",
5904
- promptPath: join6(__dirname2, "ics/prompt.md")
5951
+ promptPath: join6(__dirname3, "ics/prompt.md")
5905
5952
  }
5906
5953
  };
5907
5954
 
@@ -6681,10 +6728,77 @@ function logLLM(message, data) {
6681
6728
  }
6682
6729
 
6683
6730
  // src/engine/orchestrator/orchestrator.ts
6684
- import { fileURLToPath as fileURLToPath3 } from "url";
6731
+ import { fileURLToPath as fileURLToPath4 } from "url";
6685
6732
  import { dirname as dirname4, join as join7 } from "path";
6686
- var __filename2 = fileURLToPath3(import.meta.url);
6687
- var __dirname3 = dirname4(__filename2);
6733
+ var __filename3 = fileURLToPath4(import.meta.url);
6734
+ var __dirname4 = dirname4(__filename3);
6735
+
6736
+ // src/engine/state-persistence.ts
6737
+ import { writeFileSync as writeFileSync5, readFileSync as readFileSync3, existsSync as existsSync5, readdirSync, statSync } from "fs";
6738
+ import { join as join8, basename } from "path";
6739
+ function saveState(state) {
6740
+ const sessionsDir = WORKSPACE.SESSIONS;
6741
+ ensureDirExists(sessionsDir);
6742
+ const snapshot = {
6743
+ version: 1,
6744
+ savedAt: Date.now(),
6745
+ engagement: state.getEngagement(),
6746
+ targets: Array.from(state.getTargets().entries()).map(([key, value]) => ({ key, value })),
6747
+ findings: state.getFindings(),
6748
+ loot: state.getLoot(),
6749
+ todo: state.getTodo(),
6750
+ actionLog: state.getRecentActions(9999),
6751
+ currentPhase: state.getPhase(),
6752
+ missionSummary: state.getMissionSummary(),
6753
+ missionChecklist: state.getMissionChecklist()
6754
+ };
6755
+ const sessionId = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
6756
+ const sessionFile = join8(sessionsDir, `${sessionId}.json`);
6757
+ writeFileSync5(sessionFile, JSON.stringify(snapshot, null, 2), "utf-8");
6758
+ const latestFile = join8(sessionsDir, "latest.json");
6759
+ writeFileSync5(latestFile, JSON.stringify(snapshot, null, 2), "utf-8");
6760
+ return sessionFile;
6761
+ }
6762
+ function loadState(state) {
6763
+ const latestFile = join8(WORKSPACE.SESSIONS, "latest.json");
6764
+ if (!existsSync5(latestFile)) {
6765
+ return false;
6766
+ }
6767
+ try {
6768
+ const raw = readFileSync3(latestFile, "utf-8");
6769
+ const snapshot = JSON.parse(raw);
6770
+ if (snapshot.version !== 1) {
6771
+ console.warn(`[StatePersistence] Unknown snapshot version: ${snapshot.version}`);
6772
+ return false;
6773
+ }
6774
+ if (snapshot.engagement) {
6775
+ state.setEngagement(snapshot.engagement);
6776
+ }
6777
+ for (const { value } of snapshot.targets) {
6778
+ state.addTarget(value);
6779
+ }
6780
+ for (const finding of snapshot.findings) {
6781
+ state.addFinding(finding);
6782
+ }
6783
+ for (const loot of snapshot.loot) {
6784
+ state.addLoot(loot);
6785
+ }
6786
+ for (const item of snapshot.todo) {
6787
+ state.addTodo(item.content, item.priority);
6788
+ }
6789
+ state.setPhase(snapshot.currentPhase);
6790
+ if (snapshot.missionSummary) {
6791
+ state.setMissionSummary(snapshot.missionSummary);
6792
+ }
6793
+ if (snapshot.missionChecklist?.length > 0) {
6794
+ state.addMissionChecklistItems(snapshot.missionChecklist.map((c) => c.text));
6795
+ }
6796
+ return true;
6797
+ } catch (err) {
6798
+ console.warn(`[StatePersistence] Failed to load state: ${err}`);
6799
+ return false;
6800
+ }
6801
+ }
6688
6802
 
6689
6803
  // src/agents/core-agent.ts
6690
6804
  var CoreAgent = class _CoreAgent {
@@ -7213,9 +7327,9 @@ Please decide how to handle this error and continue.`;
7213
7327
  };
7214
7328
 
7215
7329
  // src/agents/prompt-builder.ts
7216
- import { readFileSync as readFileSync3, existsSync as existsSync5 } from "fs";
7217
- import { join as join8, dirname as dirname5 } from "path";
7218
- import { fileURLToPath as fileURLToPath4 } from "url";
7330
+ import { readFileSync as readFileSync4, existsSync as existsSync6 } from "fs";
7331
+ import { join as join9, dirname as dirname5 } from "path";
7332
+ import { fileURLToPath as fileURLToPath5 } from "url";
7219
7333
 
7220
7334
  // src/shared/constants/prompts.ts
7221
7335
  var PROMPT_PATHS = {
@@ -7268,9 +7382,9 @@ var INITIAL_TASKS = {
7268
7382
  };
7269
7383
 
7270
7384
  // src/agents/prompt-builder.ts
7271
- var __dirname4 = dirname5(fileURLToPath4(import.meta.url));
7272
- var PROMPTS_DIR = join8(__dirname4, "prompts");
7273
- var TECHNIQUES_DIR = join8(PROMPTS_DIR, PROMPT_PATHS.TECHNIQUES_DIR);
7385
+ var __dirname5 = dirname5(fileURLToPath5(import.meta.url));
7386
+ var PROMPTS_DIR = join9(__dirname5, "prompts");
7387
+ var TECHNIQUES_DIR = join9(PROMPTS_DIR, PROMPT_PATHS.TECHNIQUES_DIR);
7274
7388
  var { AGENT_FILES } = PROMPT_PATHS;
7275
7389
  var PHASE_PROMPT_MAP = {
7276
7390
  // Direct mappings — phase has its own prompt file
@@ -7346,8 +7460,8 @@ var PromptBuilder = class {
7346
7460
  * Load a prompt file from src/agents/prompts/
7347
7461
  */
7348
7462
  loadPromptFile(filename) {
7349
- const path2 = join8(PROMPTS_DIR, filename);
7350
- return existsSync5(path2) ? readFileSync3(path2, PROMPT_CONFIG.ENCODING) : "";
7463
+ const path3 = join9(PROMPTS_DIR, filename);
7464
+ return existsSync6(path3) ? readFileSync4(path3, PROMPT_CONFIG.ENCODING) : "";
7351
7465
  }
7352
7466
  /**
7353
7467
  * Load phase-specific prompt.
@@ -7390,15 +7504,15 @@ ${content}
7390
7504
  * use web_search to look up specific attack techniques on demand.
7391
7505
  */
7392
7506
  loadPhaseRelevantTechniques(phase) {
7393
- if (!existsSync5(TECHNIQUES_DIR)) return "";
7507
+ if (!existsSync6(TECHNIQUES_DIR)) return "";
7394
7508
  const relevantTechniques = PHASE_TECHNIQUE_MAP[phase] || [];
7395
7509
  if (relevantTechniques.length === 0) return "";
7396
7510
  const fragments = [];
7397
7511
  for (const technique of relevantTechniques) {
7398
- const filePath = join8(TECHNIQUES_DIR, `${technique}.md`);
7512
+ const filePath = join9(TECHNIQUES_DIR, `${technique}.md`);
7399
7513
  try {
7400
- if (!existsSync5(filePath)) continue;
7401
- const content = readFileSync3(filePath, PROMPT_CONFIG.ENCODING);
7514
+ if (!existsSync6(filePath)) continue;
7515
+ const content = readFileSync4(filePath, PROMPT_CONFIG.ENCODING);
7402
7516
  if (content) {
7403
7517
  fragments.push(`<technique-reference category="${technique}">
7404
7518
  ${content}
@@ -7454,6 +7568,10 @@ var MainAgent = class extends CoreAgent {
7454
7568
  const result2 = await this.run(userInput, this.getCurrentPrompt());
7455
7569
  return result2.output;
7456
7570
  } finally {
7571
+ try {
7572
+ saveState(this.state);
7573
+ } catch {
7574
+ }
7457
7575
  await cleanupAllProcesses();
7458
7576
  }
7459
7577
  }
@@ -7472,10 +7590,28 @@ var MainAgent = class extends CoreAgent {
7472
7590
  }
7473
7591
  // ─── Internal Helpers ────────────────────────────────────────
7474
7592
  initializeTask() {
7593
+ try {
7594
+ ensureDirExists(WORKSPACE.ROOT);
7595
+ } catch {
7596
+ }
7475
7597
  if (this.state.getTodo().length === 0) {
7476
7598
  this.state.addTodo(INITIAL_TASKS.RECON, PRIORITIES.HIGH);
7477
7599
  }
7478
7600
  }
7601
+ /**
7602
+ * Load previous session state from .pentesting/sessions/latest.json
7603
+ * @returns true if a previous session was restored
7604
+ */
7605
+ loadPreviousSession() {
7606
+ return loadState(this.state);
7607
+ }
7608
+ /**
7609
+ * Manually save current state to .pentesting/sessions/
7610
+ * @returns Path to the saved session file
7611
+ */
7612
+ saveCurrentState() {
7613
+ return saveState(this.state);
7614
+ }
7479
7615
  getCurrentPrompt() {
7480
7616
  const phase = this.state.getPhase() || PHASES.RECON;
7481
7617
  return this.promptBuilder.build(this.userInput, phase);
@@ -8028,7 +8164,7 @@ var useAgentEvents = (agent, eventsRef, state) => {
8028
8164
  isPassword,
8029
8165
  inputType: request.type,
8030
8166
  context: request.context,
8031
- optional: request.optional,
8167
+ optional: request.isOptional,
8032
8168
  options: request.options,
8033
8169
  resolve
8034
8170
  });
@@ -8123,7 +8259,7 @@ function buildCredentialPrompt(request) {
8123
8259
  displayPrompt = `${displayPrompt}
8124
8260
  Context: ${request.context}`;
8125
8261
  }
8126
- if (request.optional) {
8262
+ if (request.isOptional) {
8127
8263
  displayPrompt += " (optional - press Enter to skip)";
8128
8264
  }
8129
8265
  if (request.options && request.options.length > 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pentesting",
3
- "version": "0.21.9",
3
+ "version": "0.21.11",
4
4
  "description": "Autonomous Penetration Testing AI Agent",
5
5
  "type": "module",
6
6
  "main": "dist/main.js",