@pensar/apex 0.0.26 → 0.0.28-canary.0
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/bin/pensar.js +64 -20
- package/build/benchmark.js +268 -11
- package/build/index.js +1138 -147
- package/build/pentest.js +48198 -0
- package/build/quicktest.js +359 -126
- package/build/swarm.js +320 -125
- package/package.json +3 -2
package/build/index.js
CHANGED
|
@@ -64634,7 +64634,7 @@ function getProviderModel(model, authConfig) {
|
|
|
64634
64634
|
const bedrockAccessKeyId = authConfig?.bedrock?.accessKeyId || process.env.AWS_ACCESS_KEY_ID;
|
|
64635
64635
|
const bedrockSecretAccessKey = authConfig?.bedrock?.secretAccessKey || process.env.AWS_SECRET_ACCESS_KEY;
|
|
64636
64636
|
const bedrockRegion = authConfig?.bedrock?.region || process.env.AWS_REGION || "us-east-1";
|
|
64637
|
-
const localBaseURL = authConfig?.local?.baseURL || process.env.LOCAL_MODEL_URL;
|
|
64637
|
+
const localBaseURL = authConfig?.local?.baseURL || process.env.LOCAL_MODEL_URL || "http://127.0.0.1:1234/v1";
|
|
64638
64638
|
let providerModel;
|
|
64639
64639
|
switch (provider) {
|
|
64640
64640
|
case "openai":
|
|
@@ -66454,13 +66454,200 @@ Remember: You are a focused penetration testing agent assigned a specific target
|
|
|
66454
66454
|
import { exec } from "child_process";
|
|
66455
66455
|
import { promisify } from "util";
|
|
66456
66456
|
import {
|
|
66457
|
-
writeFileSync,
|
|
66457
|
+
writeFileSync as writeFileSync2,
|
|
66458
66458
|
appendFileSync,
|
|
66459
|
-
readdirSync,
|
|
66459
|
+
readdirSync as readdirSync2,
|
|
66460
|
+
readFileSync as readFileSync2,
|
|
66461
|
+
existsSync as existsSync5
|
|
66462
|
+
} from "fs";
|
|
66463
|
+
import { join as join2 } from "path";
|
|
66464
|
+
|
|
66465
|
+
// src/core/agent/sessions/index.ts
|
|
66466
|
+
import {
|
|
66467
|
+
mkdirSync,
|
|
66468
|
+
existsSync as existsSync3,
|
|
66469
|
+
writeFileSync,
|
|
66460
66470
|
readFileSync,
|
|
66461
|
-
|
|
66471
|
+
readdirSync,
|
|
66472
|
+
statSync,
|
|
66473
|
+
rmSync
|
|
66462
66474
|
} from "fs";
|
|
66463
66475
|
import { join } from "path";
|
|
66476
|
+
import { homedir } from "os";
|
|
66477
|
+
|
|
66478
|
+
// src/core/services/rateLimiter/index.ts
|
|
66479
|
+
function sleep(ms) {
|
|
66480
|
+
return new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
66481
|
+
}
|
|
66482
|
+
|
|
66483
|
+
class RateLimiter {
|
|
66484
|
+
tokens;
|
|
66485
|
+
lastRefillTime;
|
|
66486
|
+
rps;
|
|
66487
|
+
bucketSize;
|
|
66488
|
+
msPerToken;
|
|
66489
|
+
queue;
|
|
66490
|
+
constructor(config3) {
|
|
66491
|
+
this.rps = config3?.requestsPerSecond;
|
|
66492
|
+
this.bucketSize = this.rps ? 1 : 0;
|
|
66493
|
+
this.tokens = this.bucketSize;
|
|
66494
|
+
this.lastRefillTime = performance.now();
|
|
66495
|
+
this.msPerToken = this.rps ? 1000 / this.rps : undefined;
|
|
66496
|
+
this.queue = Promise.resolve();
|
|
66497
|
+
}
|
|
66498
|
+
async acquireSlot() {
|
|
66499
|
+
if (!this.rps || !this.msPerToken)
|
|
66500
|
+
return;
|
|
66501
|
+
const previousPromise = this.queue;
|
|
66502
|
+
let resolveCurrentRequest;
|
|
66503
|
+
this.queue = new Promise((resolve4) => {
|
|
66504
|
+
resolveCurrentRequest = resolve4;
|
|
66505
|
+
});
|
|
66506
|
+
await previousPromise;
|
|
66507
|
+
try {
|
|
66508
|
+
const now2 = performance.now();
|
|
66509
|
+
this.refill(now2);
|
|
66510
|
+
if (this.tokens < 1) {
|
|
66511
|
+
const waitTime = (1 - this.tokens) * this.msPerToken;
|
|
66512
|
+
await sleep(waitTime);
|
|
66513
|
+
const nowAfterSleep = performance.now();
|
|
66514
|
+
this.refill(nowAfterSleep);
|
|
66515
|
+
}
|
|
66516
|
+
this.tokens -= 1;
|
|
66517
|
+
} finally {
|
|
66518
|
+
resolveCurrentRequest();
|
|
66519
|
+
}
|
|
66520
|
+
}
|
|
66521
|
+
refill(now2) {
|
|
66522
|
+
if (this.tokens >= this.bucketSize) {
|
|
66523
|
+
this.lastRefillTime = now2;
|
|
66524
|
+
return;
|
|
66525
|
+
}
|
|
66526
|
+
const elapsed = now2 - this.lastRefillTime;
|
|
66527
|
+
const tokensToAdd = elapsed / this.msPerToken;
|
|
66528
|
+
this.tokens = Math.min(this.bucketSize, this.tokens + tokensToAdd);
|
|
66529
|
+
this.lastRefillTime = now2;
|
|
66530
|
+
}
|
|
66531
|
+
isEnabled() {
|
|
66532
|
+
return this.rps !== undefined;
|
|
66533
|
+
}
|
|
66534
|
+
}
|
|
66535
|
+
|
|
66536
|
+
// src/core/agent/sessions/index.ts
|
|
66537
|
+
var DEFAULT_OFFENSIVE_HEADERS = {
|
|
66538
|
+
"User-Agent": "pensar-apex"
|
|
66539
|
+
};
|
|
66540
|
+
function generateSessionId(prefix) {
|
|
66541
|
+
const timestamp = Date.now().toString(36);
|
|
66542
|
+
return `${prefix ? `${prefix}-` : ""}${timestamp}`;
|
|
66543
|
+
}
|
|
66544
|
+
function getPensarDir() {
|
|
66545
|
+
return join(homedir(), ".pensar");
|
|
66546
|
+
}
|
|
66547
|
+
function getExecutionsDir() {
|
|
66548
|
+
return join(getPensarDir(), "executions");
|
|
66549
|
+
}
|
|
66550
|
+
function createSession(target, objective, prefix, config3) {
|
|
66551
|
+
const sessionId = generateSessionId(prefix);
|
|
66552
|
+
const rootPath = join(getExecutionsDir(), sessionId);
|
|
66553
|
+
const findingsPath = join(rootPath, "findings");
|
|
66554
|
+
const scratchpadPath = join(rootPath, "scratchpad");
|
|
66555
|
+
const logsPath = join(rootPath, "logs");
|
|
66556
|
+
ensureDirectoryExists(rootPath);
|
|
66557
|
+
ensureDirectoryExists(findingsPath);
|
|
66558
|
+
ensureDirectoryExists(scratchpadPath);
|
|
66559
|
+
ensureDirectoryExists(logsPath);
|
|
66560
|
+
const session = {
|
|
66561
|
+
id: sessionId,
|
|
66562
|
+
rootPath,
|
|
66563
|
+
findingsPath,
|
|
66564
|
+
scratchpadPath,
|
|
66565
|
+
logsPath,
|
|
66566
|
+
target,
|
|
66567
|
+
objective: objective ?? "",
|
|
66568
|
+
startTime: new Date().toISOString(),
|
|
66569
|
+
config: config3
|
|
66570
|
+
};
|
|
66571
|
+
if (config3?.rateLimiter) {
|
|
66572
|
+
session._rateLimiter = new RateLimiter(config3.rateLimiter);
|
|
66573
|
+
}
|
|
66574
|
+
const metadataPath = join(rootPath, "session.json");
|
|
66575
|
+
writeFileSync(metadataPath, JSON.stringify(session, null, 2));
|
|
66576
|
+
const readmePath = join(rootPath, "README.md");
|
|
66577
|
+
const readme = `# Penetration Test Session
|
|
66578
|
+
|
|
66579
|
+
**Session ID:** ${sessionId}
|
|
66580
|
+
**Target:** ${target}
|
|
66581
|
+
**Objective:** ${objective}
|
|
66582
|
+
**Started:** ${session.startTime}
|
|
66583
|
+
|
|
66584
|
+
## Directory Structure
|
|
66585
|
+
|
|
66586
|
+
- \`findings/\` - Security findings and vulnerabilities
|
|
66587
|
+
- \`scratchpad/\` - Notes and temporary data during testing
|
|
66588
|
+
- \`logs/\` - Execution logs and command outputs
|
|
66589
|
+
- \`session.json\` - Session metadata
|
|
66590
|
+
|
|
66591
|
+
## Findings
|
|
66592
|
+
|
|
66593
|
+
Security findings will be documented in the \`findings/\` directory as individual files.
|
|
66594
|
+
|
|
66595
|
+
## Status
|
|
66596
|
+
|
|
66597
|
+
Testing in progress...
|
|
66598
|
+
`;
|
|
66599
|
+
writeFileSync(readmePath, readme);
|
|
66600
|
+
return session;
|
|
66601
|
+
}
|
|
66602
|
+
function ensureDirectoryExists(path3) {
|
|
66603
|
+
if (!existsSync3(path3)) {
|
|
66604
|
+
mkdirSync(path3, { recursive: true });
|
|
66605
|
+
}
|
|
66606
|
+
}
|
|
66607
|
+
function getSession(sessionId) {
|
|
66608
|
+
const sessionPath = join(getExecutionsDir(), sessionId);
|
|
66609
|
+
const metadataPath = join(sessionPath, "session.json");
|
|
66610
|
+
if (!existsSync3(metadataPath)) {
|
|
66611
|
+
return null;
|
|
66612
|
+
}
|
|
66613
|
+
const metadata = JSON.parse(readFileSync(metadataPath, "utf-8"));
|
|
66614
|
+
return metadata;
|
|
66615
|
+
}
|
|
66616
|
+
function extractTimestamp(sessionId) {
|
|
66617
|
+
const parts = sessionId.split("-");
|
|
66618
|
+
const timestampBase36 = parts[parts.length - 1];
|
|
66619
|
+
return parseInt(timestampBase36 || "", 36);
|
|
66620
|
+
}
|
|
66621
|
+
function listSessions() {
|
|
66622
|
+
const executionsDir = getExecutionsDir();
|
|
66623
|
+
if (!existsSync3(executionsDir)) {
|
|
66624
|
+
return [];
|
|
66625
|
+
}
|
|
66626
|
+
const entries = readdirSync(executionsDir);
|
|
66627
|
+
const directories = entries.filter((entry) => {
|
|
66628
|
+
const fullPath = join(executionsDir, entry);
|
|
66629
|
+
return statSync(fullPath).isDirectory();
|
|
66630
|
+
});
|
|
66631
|
+
return directories.sort((a, b) => {
|
|
66632
|
+
const timestampA = extractTimestamp(a);
|
|
66633
|
+
const timestampB = extractTimestamp(b);
|
|
66634
|
+
return timestampB - timestampA;
|
|
66635
|
+
});
|
|
66636
|
+
}
|
|
66637
|
+
function getOffensiveHeaders(session) {
|
|
66638
|
+
const config3 = session.config?.offensiveHeaders;
|
|
66639
|
+
if (!config3 || config3.mode === "none") {
|
|
66640
|
+
return;
|
|
66641
|
+
}
|
|
66642
|
+
if (config3.mode === "default") {
|
|
66643
|
+
return DEFAULT_OFFENSIVE_HEADERS;
|
|
66644
|
+
}
|
|
66645
|
+
if (config3.mode === "custom" && config3.headers) {
|
|
66646
|
+
return config3.headers;
|
|
66647
|
+
}
|
|
66648
|
+
return;
|
|
66649
|
+
}
|
|
66650
|
+
// src/core/agent/tools.ts
|
|
66464
66651
|
var execAsync = promisify(exec);
|
|
66465
66652
|
var PayloadSchema = exports_external.object({
|
|
66466
66653
|
payload: exports_external.string(),
|
|
@@ -67554,7 +67741,7 @@ FINDING STRUCTURE:
|
|
|
67554
67741
|
const safeTitle = finding.title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").substring(0, 50);
|
|
67555
67742
|
const findingId = `${timestamp.split("T")[0]}-${safeTitle}`;
|
|
67556
67743
|
const filename = `${findingId}.md`;
|
|
67557
|
-
const filepath =
|
|
67744
|
+
const filepath = join2(session.findingsPath, filename);
|
|
67558
67745
|
const markdown = `# ${finding.title}
|
|
67559
67746
|
|
|
67560
67747
|
**Severity:** ${finding.severity}
|
|
@@ -67588,8 +67775,8 @@ ${finding.references}` : ""}
|
|
|
67588
67775
|
|
|
67589
67776
|
*This finding was automatically documented by the Pensar penetration testing agent.*
|
|
67590
67777
|
`;
|
|
67591
|
-
|
|
67592
|
-
const summaryPath =
|
|
67778
|
+
writeFileSync2(filepath, markdown);
|
|
67779
|
+
const summaryPath = join2(session.rootPath, "findings-summary.md");
|
|
67593
67780
|
const summaryEntry = `- [${finding.severity}] ${finding.title} - \`findings/${filename}\`
|
|
67594
67781
|
`;
|
|
67595
67782
|
try {
|
|
@@ -67603,7 +67790,7 @@ ${finding.references}` : ""}
|
|
|
67603
67790
|
## All Findings
|
|
67604
67791
|
|
|
67605
67792
|
`;
|
|
67606
|
-
|
|
67793
|
+
writeFileSync2(summaryPath, header + summaryEntry);
|
|
67607
67794
|
}
|
|
67608
67795
|
return {
|
|
67609
67796
|
success: true,
|
|
@@ -67642,7 +67829,7 @@ The scratchpad is session-specific and helps maintain context during long assess
|
|
|
67642
67829
|
execute: async ({ note, category }) => {
|
|
67643
67830
|
try {
|
|
67644
67831
|
const timestamp = new Date().toISOString();
|
|
67645
|
-
const scratchpadFile =
|
|
67832
|
+
const scratchpadFile = join2(session.scratchpadPath, "notes.md");
|
|
67646
67833
|
const entry = `## ${category.toUpperCase()} - ${timestamp}
|
|
67647
67834
|
|
|
67648
67835
|
${note}
|
|
@@ -67661,7 +67848,7 @@ ${note}
|
|
|
67661
67848
|
---
|
|
67662
67849
|
|
|
67663
67850
|
`;
|
|
67664
|
-
|
|
67851
|
+
writeFileSync2(scratchpadFile, header + entry);
|
|
67665
67852
|
}
|
|
67666
67853
|
return {
|
|
67667
67854
|
success: true,
|
|
@@ -67788,11 +67975,11 @@ The report will be saved as 'pentest-report.md' in the session root directory.`,
|
|
|
67788
67975
|
MEDIUM: 0,
|
|
67789
67976
|
LOW: 0
|
|
67790
67977
|
};
|
|
67791
|
-
if (
|
|
67792
|
-
const findingFiles =
|
|
67978
|
+
if (existsSync5(session.findingsPath)) {
|
|
67979
|
+
const findingFiles = readdirSync2(session.findingsPath).filter((f) => f.endsWith(".json"));
|
|
67793
67980
|
for (const file2 of findingFiles) {
|
|
67794
|
-
const filePath =
|
|
67795
|
-
const content =
|
|
67981
|
+
const filePath = join2(session.findingsPath, file2);
|
|
67982
|
+
const content = readFileSync2(filePath, "utf-8");
|
|
67796
67983
|
const severityMatch = content.match(/\*\*Severity:\*\*\s+(CRITICAL|HIGH|MEDIUM|LOW)/);
|
|
67797
67984
|
const titleMatch = content.match(/^#\s+(.+)$/m);
|
|
67798
67985
|
if (severityMatch && titleMatch) {
|
|
@@ -67817,14 +68004,14 @@ The report will be saved as 'pentest-report.md' in the session root directory.`,
|
|
|
67817
68004
|
const totalFindings = findings.length;
|
|
67818
68005
|
const criticalAndHigh = severityCounts.CRITICAL + severityCounts.HIGH;
|
|
67819
68006
|
let scratchpadNotes = "";
|
|
67820
|
-
const scratchpadFile =
|
|
67821
|
-
if (
|
|
67822
|
-
scratchpadNotes =
|
|
68007
|
+
const scratchpadFile = join2(session.scratchpadPath, "notes.md");
|
|
68008
|
+
if (existsSync5(scratchpadFile)) {
|
|
68009
|
+
scratchpadNotes = readFileSync2(scratchpadFile, "utf-8");
|
|
67823
68010
|
}
|
|
67824
68011
|
let testResultsSummary = "";
|
|
67825
|
-
const testResultsFile =
|
|
67826
|
-
if (
|
|
67827
|
-
const testLines =
|
|
68012
|
+
const testResultsFile = join2(session.scratchpadPath, "test-results.jsonl");
|
|
68013
|
+
if (existsSync5(testResultsFile)) {
|
|
68014
|
+
const testLines = readFileSync2(testResultsFile, "utf-8").split(`
|
|
67828
68015
|
`).filter((l) => l.trim());
|
|
67829
68016
|
const testResults = testLines.map((line) => {
|
|
67830
68017
|
try {
|
|
@@ -67998,25 +68185,25 @@ This report should be treated as confidential and distributed only to authorized
|
|
|
67998
68185
|
*Report generated by Pensar Penetration Testing Agent*
|
|
67999
68186
|
*Session: ${session.id}*
|
|
68000
68187
|
`;
|
|
68001
|
-
const reportPath =
|
|
68002
|
-
|
|
68003
|
-
const readmePath =
|
|
68004
|
-
if (
|
|
68005
|
-
let readme =
|
|
68188
|
+
const reportPath = join2(session.rootPath, "pentest-report.md");
|
|
68189
|
+
writeFileSync2(reportPath, report);
|
|
68190
|
+
const readmePath = join2(session.rootPath, "README.md");
|
|
68191
|
+
if (existsSync5(readmePath)) {
|
|
68192
|
+
let readme = readFileSync2(readmePath, "utf-8");
|
|
68006
68193
|
readme = readme.replace("Testing in progress...", `Testing completed on ${endDate.toLocaleString()}
|
|
68007
68194
|
|
|
68008
68195
|
**Final Report:** \`pentest-report.md\``);
|
|
68009
|
-
|
|
68196
|
+
writeFileSync2(readmePath, readme);
|
|
68010
68197
|
}
|
|
68011
|
-
const metadataPath =
|
|
68012
|
-
if (
|
|
68013
|
-
const metadata = JSON.parse(
|
|
68198
|
+
const metadataPath = join2(session.rootPath, "session.json");
|
|
68199
|
+
if (existsSync5(metadataPath)) {
|
|
68200
|
+
const metadata = JSON.parse(readFileSync2(metadataPath, "utf-8"));
|
|
68014
68201
|
metadata.endTime = endTime;
|
|
68015
68202
|
metadata.duration = duration3;
|
|
68016
68203
|
metadata.status = "completed";
|
|
68017
68204
|
metadata.totalFindings = totalFindings;
|
|
68018
68205
|
metadata.severityCounts = severityCounts;
|
|
68019
|
-
|
|
68206
|
+
writeFileSync2(metadataPath, JSON.stringify(metadata, null, 2));
|
|
68020
68207
|
}
|
|
68021
68208
|
return {
|
|
68022
68209
|
success: true,
|
|
@@ -68057,7 +68244,7 @@ async function recordTestResultCore(session, params) {
|
|
|
68057
68244
|
evidence: params.evidence || "",
|
|
68058
68245
|
confidence: params.confidence || "high"
|
|
68059
68246
|
};
|
|
68060
|
-
const testResultsPath =
|
|
68247
|
+
const testResultsPath = join2(session.scratchpadPath, "test-results.jsonl");
|
|
68061
68248
|
const resultLine = JSON.stringify(testResult) + `
|
|
68062
68249
|
`;
|
|
68063
68250
|
appendFileSync(testResultsPath, resultLine);
|
|
@@ -68468,8 +68655,8 @@ Use this when:
|
|
|
68468
68655
|
}),
|
|
68469
68656
|
execute: async ({ objective }) => {
|
|
68470
68657
|
try {
|
|
68471
|
-
const testResultsPath =
|
|
68472
|
-
if (!
|
|
68658
|
+
const testResultsPath = join2(session.scratchpadPath, "test-results.jsonl");
|
|
68659
|
+
if (!existsSync5(testResultsPath)) {
|
|
68473
68660
|
return {
|
|
68474
68661
|
success: true,
|
|
68475
68662
|
totalTests: 0,
|
|
@@ -68478,7 +68665,7 @@ Use this when:
|
|
|
68478
68665
|
suggestions: objective ? `Based on objective "${objective}", consider testing relevant parameters with test_parameter tool.` : "Use test_parameter to test parameters for vulnerabilities."
|
|
68479
68666
|
};
|
|
68480
68667
|
}
|
|
68481
|
-
const fileContent =
|
|
68668
|
+
const fileContent = readFileSync2(testResultsPath, "utf-8");
|
|
68482
68669
|
const testResults = fileContent.trim().split(`
|
|
68483
68670
|
`).filter((line) => line.trim()).map((line) => JSON.parse(line));
|
|
68484
68671
|
const parametersTested = new Set;
|
|
@@ -68735,7 +68922,7 @@ ${discovered.map((d) => `- ${d.endpoint} [${d.method}] → HTTP ${d.status}`).jo
|
|
|
68735
68922
|
Not found: ${range.max - range.min + 1 - discovered.length} endpoints returned 404`;
|
|
68736
68923
|
try {
|
|
68737
68924
|
const timestamp = new Date().toISOString();
|
|
68738
|
-
const scratchpadFile =
|
|
68925
|
+
const scratchpadFile = join2(session.scratchpadPath, "notes.md");
|
|
68739
68926
|
const entry = `## RESULT - ${timestamp}
|
|
68740
68927
|
|
|
68741
68928
|
${note}
|
|
@@ -68754,7 +68941,7 @@ ${note}
|
|
|
68754
68941
|
---
|
|
68755
68942
|
|
|
68756
68943
|
`;
|
|
68757
|
-
|
|
68944
|
+
writeFileSync2(scratchpadFile, header + entry);
|
|
68758
68945
|
}
|
|
68759
68946
|
} catch (err) {
|
|
68760
68947
|
console.error("Failed to record to scratchpad:", err);
|
|
@@ -68771,7 +68958,53 @@ ${note}
|
|
|
68771
68958
|
}
|
|
68772
68959
|
});
|
|
68773
68960
|
}
|
|
68961
|
+
function wrapCommandWithHeaders(command, headers) {
|
|
68962
|
+
const userAgent = headers["User-Agent"];
|
|
68963
|
+
if (!userAgent)
|
|
68964
|
+
return command;
|
|
68965
|
+
let wrapped = command;
|
|
68966
|
+
if (command.includes("curl") && !command.includes("User-Agent") && !command.includes("-A")) {
|
|
68967
|
+
wrapped = wrapped.replace(/\bcurl(\s+)/g, `curl -A "${userAgent}" $1`);
|
|
68968
|
+
}
|
|
68969
|
+
if (command.includes("nikto") && !command.includes("-useragent")) {
|
|
68970
|
+
wrapped = wrapped.replace(/\bnikto\s+/, `nikto -useragent "${userAgent}" `);
|
|
68971
|
+
}
|
|
68972
|
+
if (command.includes("nmap") && command.includes("--script") && /--script[= ](.*?http.*?)/.test(command) && !command.includes("http.useragent")) {
|
|
68973
|
+
if (command.includes("--script-args")) {
|
|
68974
|
+
wrapped = wrapped.replace(/--script-args\s+([^\s]+)/, `--script-args $1,http.useragent="${userAgent}"`);
|
|
68975
|
+
} else {
|
|
68976
|
+
wrapped = `${wrapped} --script-args http.useragent="${userAgent}"`;
|
|
68977
|
+
}
|
|
68978
|
+
}
|
|
68979
|
+
if (command.includes("gobuster") && !command.includes("-a ") && !command.includes("--useragent")) {
|
|
68980
|
+
wrapped = wrapped.replace(/\bgobuster\s+/, `gobuster -a "${userAgent}" `);
|
|
68981
|
+
}
|
|
68982
|
+
if (command.includes("ffuf") && !command.includes("User-Agent:")) {
|
|
68983
|
+
wrapped = wrapped.replace(/\bffuf\s+/, `ffuf -H "User-Agent: ${userAgent}" `);
|
|
68984
|
+
}
|
|
68985
|
+
if (command.includes("sqlmap") && !command.includes("--user-agent")) {
|
|
68986
|
+
wrapped = wrapped.replace(/\bsqlmap\s+/, `sqlmap --user-agent="${userAgent}" `);
|
|
68987
|
+
}
|
|
68988
|
+
if (command.includes("wfuzz") && !command.includes("-H") && !command.includes("User-Agent")) {
|
|
68989
|
+
wrapped = wrapped.replace(/\bwfuzz\s+/, `wfuzz -H "User-Agent: ${userAgent}" `);
|
|
68990
|
+
}
|
|
68991
|
+
if (command.includes("dirb") && !command.includes("-a")) {
|
|
68992
|
+
wrapped = wrapped.replace(/\bdirb\s+/, `dirb -a "${userAgent}" `);
|
|
68993
|
+
}
|
|
68994
|
+
if (command.includes("wpscan") && !command.includes("--user-agent")) {
|
|
68995
|
+
wrapped = wrapped.replace(/\bwpscan\s+/, `wpscan --user-agent "${userAgent}" `);
|
|
68996
|
+
}
|
|
68997
|
+
if (command.includes("nuclei") && !command.includes("-H")) {
|
|
68998
|
+
wrapped = wrapped.replace(/\bnuclei\s+/, `nuclei -H "User-Agent: ${userAgent}" `);
|
|
68999
|
+
}
|
|
69000
|
+
if (command.includes("httpx") && !command.includes("-H")) {
|
|
69001
|
+
wrapped = wrapped.replace(/\bhttpx\s+/, `httpx -H "User-Agent: ${userAgent}" `);
|
|
69002
|
+
}
|
|
69003
|
+
return wrapped;
|
|
69004
|
+
}
|
|
68774
69005
|
function createPentestTools(session, model, toolOverride) {
|
|
69006
|
+
const offensiveHeaders = getOffensiveHeaders(session);
|
|
69007
|
+
const rateLimiter = session._rateLimiter;
|
|
68775
69008
|
const executeCommand = tool({
|
|
68776
69009
|
name: "execute_command",
|
|
68777
69010
|
description: `Execute a shell command for penetration testing activities.
|
|
@@ -68816,6 +69049,9 @@ IMPORTANT: Always analyze results and adjust your approach based on findings.`,
|
|
|
68816
69049
|
inputSchema: ExecuteCommandInput,
|
|
68817
69050
|
execute: async ({ command, timeout = 30000, toolCallDescription }) => {
|
|
68818
69051
|
try {
|
|
69052
|
+
if (rateLimiter) {
|
|
69053
|
+
await rateLimiter.acquireSlot();
|
|
69054
|
+
}
|
|
68819
69055
|
if (toolOverride?.execute_command) {
|
|
68820
69056
|
return toolOverride.execute_command({
|
|
68821
69057
|
command,
|
|
@@ -68823,7 +69059,8 @@ IMPORTANT: Always analyze results and adjust your approach based on findings.`,
|
|
|
68823
69059
|
toolCallDescription
|
|
68824
69060
|
});
|
|
68825
69061
|
}
|
|
68826
|
-
const
|
|
69062
|
+
const finalCommand = offensiveHeaders ? wrapCommandWithHeaders(command, offensiveHeaders) : command;
|
|
69063
|
+
const { stdout, stderr } = await execAsync(finalCommand, {
|
|
68827
69064
|
timeout,
|
|
68828
69065
|
maxBuffer: 10 * 1024 * 1024
|
|
68829
69066
|
});
|
|
@@ -68833,7 +69070,7 @@ IMPORTANT: Always analyze results and adjust your approach based on findings.`,
|
|
|
68833
69070
|
|
|
68834
69071
|
(truncated) call the command again with grep / tail to paginate the response` || "(no output)",
|
|
68835
69072
|
stderr: stderr || "",
|
|
68836
|
-
command,
|
|
69073
|
+
command: finalCommand,
|
|
68837
69074
|
error: ""
|
|
68838
69075
|
};
|
|
68839
69076
|
} catch (error46) {
|
|
@@ -68871,6 +69108,9 @@ COMMON TESTING PATTERNS:
|
|
|
68871
69108
|
inputSchema: HttpRequestInput,
|
|
68872
69109
|
execute: async ({ url: url2, method, headers, body, followRedirects, timeout, toolCallDescription }) => {
|
|
68873
69110
|
try {
|
|
69111
|
+
if (rateLimiter) {
|
|
69112
|
+
await rateLimiter.acquireSlot();
|
|
69113
|
+
}
|
|
68874
69114
|
if (toolOverride?.http_request) {
|
|
68875
69115
|
return toolOverride.http_request({
|
|
68876
69116
|
url: url2,
|
|
@@ -68886,7 +69126,10 @@ COMMON TESTING PATTERNS:
|
|
|
68886
69126
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
68887
69127
|
const response = await fetch(url2, {
|
|
68888
69128
|
method,
|
|
68889
|
-
headers:
|
|
69129
|
+
headers: {
|
|
69130
|
+
...offensiveHeaders || {},
|
|
69131
|
+
...headers || {}
|
|
69132
|
+
},
|
|
68890
69133
|
body: body || undefined,
|
|
68891
69134
|
redirect: followRedirects ? "follow" : "manual",
|
|
68892
69135
|
signal: controller.signal
|
|
@@ -68945,102 +69188,6 @@ COMMON TESTING PATTERNS:
|
|
|
68945
69188
|
};
|
|
68946
69189
|
}
|
|
68947
69190
|
|
|
68948
|
-
// src/core/agent/sessions/index.ts
|
|
68949
|
-
import {
|
|
68950
|
-
mkdirSync,
|
|
68951
|
-
existsSync as existsSync5,
|
|
68952
|
-
writeFileSync as writeFileSync2,
|
|
68953
|
-
readFileSync as readFileSync2,
|
|
68954
|
-
readdirSync as readdirSync2,
|
|
68955
|
-
statSync,
|
|
68956
|
-
rmSync
|
|
68957
|
-
} from "fs";
|
|
68958
|
-
import { join as join2 } from "path";
|
|
68959
|
-
import { homedir } from "os";
|
|
68960
|
-
function generateSessionId(prefix) {
|
|
68961
|
-
const timestamp = Date.now().toString(36);
|
|
68962
|
-
return `${prefix ? `${prefix}-` : ""}${timestamp}`;
|
|
68963
|
-
}
|
|
68964
|
-
function getPensarDir() {
|
|
68965
|
-
return join2(homedir(), ".pensar");
|
|
68966
|
-
}
|
|
68967
|
-
function getExecutionsDir() {
|
|
68968
|
-
return join2(getPensarDir(), "executions");
|
|
68969
|
-
}
|
|
68970
|
-
function createSession(target, objective, prefix) {
|
|
68971
|
-
const sessionId = generateSessionId(prefix);
|
|
68972
|
-
const rootPath = join2(getExecutionsDir(), sessionId);
|
|
68973
|
-
const findingsPath = join2(rootPath, "findings");
|
|
68974
|
-
const scratchpadPath = join2(rootPath, "scratchpad");
|
|
68975
|
-
const logsPath = join2(rootPath, "logs");
|
|
68976
|
-
ensureDirectoryExists(rootPath);
|
|
68977
|
-
ensureDirectoryExists(findingsPath);
|
|
68978
|
-
ensureDirectoryExists(scratchpadPath);
|
|
68979
|
-
ensureDirectoryExists(logsPath);
|
|
68980
|
-
const session = {
|
|
68981
|
-
id: sessionId,
|
|
68982
|
-
rootPath,
|
|
68983
|
-
findingsPath,
|
|
68984
|
-
scratchpadPath,
|
|
68985
|
-
logsPath,
|
|
68986
|
-
target,
|
|
68987
|
-
objective: objective ?? "",
|
|
68988
|
-
startTime: new Date().toISOString()
|
|
68989
|
-
};
|
|
68990
|
-
const metadataPath = join2(rootPath, "session.json");
|
|
68991
|
-
writeFileSync2(metadataPath, JSON.stringify(session, null, 2));
|
|
68992
|
-
const readmePath = join2(rootPath, "README.md");
|
|
68993
|
-
const readme = `# Penetration Test Session
|
|
68994
|
-
|
|
68995
|
-
**Session ID:** ${sessionId}
|
|
68996
|
-
**Target:** ${target}
|
|
68997
|
-
**Objective:** ${objective}
|
|
68998
|
-
**Started:** ${session.startTime}
|
|
68999
|
-
|
|
69000
|
-
## Directory Structure
|
|
69001
|
-
|
|
69002
|
-
- \`findings/\` - Security findings and vulnerabilities
|
|
69003
|
-
- \`scratchpad/\` - Notes and temporary data during testing
|
|
69004
|
-
- \`logs/\` - Execution logs and command outputs
|
|
69005
|
-
- \`session.json\` - Session metadata
|
|
69006
|
-
|
|
69007
|
-
## Findings
|
|
69008
|
-
|
|
69009
|
-
Security findings will be documented in the \`findings/\` directory as individual files.
|
|
69010
|
-
|
|
69011
|
-
## Status
|
|
69012
|
-
|
|
69013
|
-
Testing in progress...
|
|
69014
|
-
`;
|
|
69015
|
-
writeFileSync2(readmePath, readme);
|
|
69016
|
-
return session;
|
|
69017
|
-
}
|
|
69018
|
-
function ensureDirectoryExists(path3) {
|
|
69019
|
-
if (!existsSync5(path3)) {
|
|
69020
|
-
mkdirSync(path3, { recursive: true });
|
|
69021
|
-
}
|
|
69022
|
-
}
|
|
69023
|
-
function getSession(sessionId) {
|
|
69024
|
-
const sessionPath = join2(getExecutionsDir(), sessionId);
|
|
69025
|
-
const metadataPath = join2(sessionPath, "session.json");
|
|
69026
|
-
if (!existsSync5(metadataPath)) {
|
|
69027
|
-
return null;
|
|
69028
|
-
}
|
|
69029
|
-
const metadata = JSON.parse(readFileSync2(metadataPath, "utf-8"));
|
|
69030
|
-
return metadata;
|
|
69031
|
-
}
|
|
69032
|
-
function listSessions() {
|
|
69033
|
-
const executionsDir = getExecutionsDir();
|
|
69034
|
-
if (!existsSync5(executionsDir)) {
|
|
69035
|
-
return [];
|
|
69036
|
-
}
|
|
69037
|
-
const entries = readdirSync2(executionsDir);
|
|
69038
|
-
return entries.filter((entry) => {
|
|
69039
|
-
const fullPath = join2(executionsDir, entry);
|
|
69040
|
-
return statSync(fullPath).isDirectory();
|
|
69041
|
-
});
|
|
69042
|
-
}
|
|
69043
|
-
|
|
69044
69191
|
// src/core/agent/utils.ts
|
|
69045
69192
|
import { readFileSync as readFileSync3, existsSync as existsSync6 } from "fs";
|
|
69046
69193
|
import { execSync } from "child_process";
|
|
@@ -69855,9 +70002,10 @@ function runAgent(opts) {
|
|
|
69855
70002
|
silent,
|
|
69856
70003
|
authConfig,
|
|
69857
70004
|
toolOverride,
|
|
69858
|
-
messages
|
|
70005
|
+
messages,
|
|
70006
|
+
sessionConfig
|
|
69859
70007
|
} = opts;
|
|
69860
|
-
const session = opts.session || createSession(target, objective);
|
|
70008
|
+
const session = opts.session || createSession(target, objective, undefined, sessionConfig);
|
|
69861
70009
|
const pocsPath = join4(session.rootPath, "pocs");
|
|
69862
70010
|
if (!existsSync9(pocsPath)) {
|
|
69863
70011
|
mkdirSync4(pocsPath, { recursive: true });
|
|
@@ -71613,9 +71761,128 @@ import fs5 from "fs";
|
|
|
71613
71761
|
|
|
71614
71762
|
// src/core/messages/index.ts
|
|
71615
71763
|
import fs4 from "fs";
|
|
71764
|
+
|
|
71765
|
+
// src/core/messages/types.ts
|
|
71766
|
+
var ToolMessageObject = exports_external.object({
|
|
71767
|
+
role: exports_external.literal("tool"),
|
|
71768
|
+
status: exports_external.enum(["pending", "completed"]),
|
|
71769
|
+
toolCallId: exports_external.string(),
|
|
71770
|
+
content: exports_external.string(),
|
|
71771
|
+
args: exports_external.record(exports_external.string(), exports_external.any()),
|
|
71772
|
+
toolName: exports_external.string(),
|
|
71773
|
+
createdAt: exports_external.coerce.date()
|
|
71774
|
+
});
|
|
71775
|
+
var SystemModelMessageObject = exports_external.object({
|
|
71776
|
+
role: exports_external.literal("system"),
|
|
71777
|
+
content: exports_external.string(),
|
|
71778
|
+
createdAt: exports_external.coerce.date(),
|
|
71779
|
+
providerOptions: exports_external.record(exports_external.string(), exports_external.any()).optional()
|
|
71780
|
+
});
|
|
71781
|
+
var TextPartObject = exports_external.object({
|
|
71782
|
+
type: exports_external.literal("text"),
|
|
71783
|
+
text: exports_external.string(),
|
|
71784
|
+
providerOptions: exports_external.record(exports_external.string(), exports_external.any()).optional()
|
|
71785
|
+
});
|
|
71786
|
+
var FilePartObject = exports_external.object({
|
|
71787
|
+
type: exports_external.literal("file"),
|
|
71788
|
+
data: exports_external.union([
|
|
71789
|
+
exports_external.string(),
|
|
71790
|
+
exports_external.instanceof(Uint8Array),
|
|
71791
|
+
exports_external.instanceof(ArrayBuffer),
|
|
71792
|
+
exports_external.instanceof(Buffer),
|
|
71793
|
+
exports_external.url()
|
|
71794
|
+
]),
|
|
71795
|
+
filename: exports_external.string().optional(),
|
|
71796
|
+
mediaType: exports_external.string(),
|
|
71797
|
+
providerOptions: exports_external.record(exports_external.string(), exports_external.any()).optional()
|
|
71798
|
+
});
|
|
71799
|
+
var ReasoningPartObject = exports_external.object({
|
|
71800
|
+
type: exports_external.literal("reasoning"),
|
|
71801
|
+
text: exports_external.string(),
|
|
71802
|
+
providerOptions: exports_external.record(exports_external.string(), exports_external.any()).optional()
|
|
71803
|
+
});
|
|
71804
|
+
var ToolCallPartObject = exports_external.object({
|
|
71805
|
+
type: exports_external.literal("tool-call"),
|
|
71806
|
+
toolCallId: exports_external.string(),
|
|
71807
|
+
toolName: exports_external.string(),
|
|
71808
|
+
input: exports_external.unknown(),
|
|
71809
|
+
providerOptions: exports_external.record(exports_external.string(), exports_external.any()).optional(),
|
|
71810
|
+
providerExecuted: exports_external.boolean().optional()
|
|
71811
|
+
});
|
|
71812
|
+
var ToolResultOutputObject = exports_external.discriminatedUnion("type", [
|
|
71813
|
+
exports_external.object({
|
|
71814
|
+
type: exports_external.literal("text"),
|
|
71815
|
+
value: exports_external.string()
|
|
71816
|
+
}),
|
|
71817
|
+
exports_external.object({
|
|
71818
|
+
type: exports_external.literal("json"),
|
|
71819
|
+
value: exports_external.any()
|
|
71820
|
+
}),
|
|
71821
|
+
exports_external.object({
|
|
71822
|
+
type: exports_external.literal("error-text"),
|
|
71823
|
+
value: exports_external.string()
|
|
71824
|
+
}),
|
|
71825
|
+
exports_external.object({
|
|
71826
|
+
type: exports_external.literal("error-json"),
|
|
71827
|
+
value: exports_external.any()
|
|
71828
|
+
}),
|
|
71829
|
+
exports_external.object({
|
|
71830
|
+
type: exports_external.literal("content"),
|
|
71831
|
+
value: exports_external.array(exports_external.discriminatedUnion("type", [
|
|
71832
|
+
exports_external.object({
|
|
71833
|
+
type: exports_external.literal("text"),
|
|
71834
|
+
text: exports_external.string()
|
|
71835
|
+
}),
|
|
71836
|
+
exports_external.object({
|
|
71837
|
+
type: exports_external.literal("media"),
|
|
71838
|
+
data: exports_external.string(),
|
|
71839
|
+
mediaType: exports_external.string()
|
|
71840
|
+
})
|
|
71841
|
+
]))
|
|
71842
|
+
})
|
|
71843
|
+
]);
|
|
71844
|
+
var ToolResultPartObject = exports_external.object({
|
|
71845
|
+
type: exports_external.literal("tool-result"),
|
|
71846
|
+
toolCallId: exports_external.string(),
|
|
71847
|
+
toolName: exports_external.string(),
|
|
71848
|
+
output: ToolResultOutputObject,
|
|
71849
|
+
providerOptions: exports_external.record(exports_external.string(), exports_external.any()).optional()
|
|
71850
|
+
});
|
|
71851
|
+
var AssistantModelMessageObject = exports_external.object({
|
|
71852
|
+
role: exports_external.literal("assistant"),
|
|
71853
|
+
content: exports_external.union([
|
|
71854
|
+
exports_external.string(),
|
|
71855
|
+
exports_external.array(exports_external.discriminatedUnion("type", [
|
|
71856
|
+
TextPartObject,
|
|
71857
|
+
FilePartObject,
|
|
71858
|
+
ReasoningPartObject,
|
|
71859
|
+
ToolCallPartObject,
|
|
71860
|
+
ToolResultPartObject
|
|
71861
|
+
]))
|
|
71862
|
+
]),
|
|
71863
|
+
createdAt: exports_external.coerce.date(),
|
|
71864
|
+
providerOptions: exports_external.record(exports_external.string(), exports_external.any()).optional()
|
|
71865
|
+
});
|
|
71866
|
+
var UserModelMessageObject = exports_external.object({
|
|
71867
|
+
role: exports_external.literal("user"),
|
|
71868
|
+
content: exports_external.union([
|
|
71869
|
+
exports_external.string(),
|
|
71870
|
+
exports_external.array(exports_external.discriminatedUnion("type", [TextPartObject, FilePartObject]))
|
|
71871
|
+
]),
|
|
71872
|
+
createdAt: exports_external.coerce.date(),
|
|
71873
|
+
providerOptions: exports_external.record(exports_external.string(), exports_external.any()).optional()
|
|
71874
|
+
});
|
|
71875
|
+
var ModelMessageObject = exports_external.discriminatedUnion("role", [
|
|
71876
|
+
SystemModelMessageObject,
|
|
71877
|
+
UserModelMessageObject,
|
|
71878
|
+
AssistantModelMessageObject,
|
|
71879
|
+
ToolMessageObject
|
|
71880
|
+
]);
|
|
71881
|
+
|
|
71882
|
+
// src/core/messages/index.ts
|
|
71616
71883
|
function getMessages(session) {
|
|
71617
71884
|
const messages = fs4.readFileSync(session.rootPath + "/messages.json", "utf8");
|
|
71618
|
-
return JSON.parse(messages);
|
|
71885
|
+
return ModelMessageObject.array().parse(JSON.parse(messages));
|
|
71619
71886
|
}
|
|
71620
71887
|
function saveMessages(session, messages) {
|
|
71621
71888
|
fs4.writeFileSync(session.rootPath + "/messages.json", JSON.stringify(messages, null, 2));
|
|
@@ -71643,6 +71910,15 @@ function PentestAgentDisplay() {
|
|
|
71643
71910
|
const [isCompleted, setIsCompleted] = import_react20.useState(false);
|
|
71644
71911
|
const [sessionPath, setSessionPath] = import_react20.useState("");
|
|
71645
71912
|
const [abortController, setAbortController] = import_react20.useState(null);
|
|
71913
|
+
const [rps, setRps] = import_react20.useState("");
|
|
71914
|
+
const [headerMode, setHeaderMode] = import_react20.useState("default");
|
|
71915
|
+
const [customHeaders, setCustomHeaders] = import_react20.useState({});
|
|
71916
|
+
const [headerInputName, setHeaderInputName] = import_react20.useState("");
|
|
71917
|
+
const [headerInputValue, setHeaderInputValue] = import_react20.useState("");
|
|
71918
|
+
const [selectedHeaderIndex, setSelectedHeaderIndex] = import_react20.useState(0);
|
|
71919
|
+
const [headerEditMode, setHeaderEditMode] = import_react20.useState("list");
|
|
71920
|
+
const [inputError, setInputError] = import_react20.useState("");
|
|
71921
|
+
const [editingHeaderKey, setEditingHeaderKey] = import_react20.useState(null);
|
|
71646
71922
|
const { closePentest } = useCommand();
|
|
71647
71923
|
const {
|
|
71648
71924
|
model,
|
|
@@ -71652,7 +71928,8 @@ function PentestAgentDisplay() {
|
|
|
71652
71928
|
isExecuting,
|
|
71653
71929
|
setIsExecuting
|
|
71654
71930
|
} = useAgent();
|
|
71655
|
-
const inputs = ["target", "objective"];
|
|
71931
|
+
const inputs = headerMode === "custom" && headerEditMode === "input" ? ["target", "objective", "rps", "headerMode", "headerInputName", "headerInputValue"] : ["target", "objective", "rps", "headerMode"];
|
|
71932
|
+
const headerEntries = Object.entries(customHeaders);
|
|
71656
71933
|
useKeyboard((key) => {
|
|
71657
71934
|
if (key.name === "escape") {
|
|
71658
71935
|
closePentest();
|
|
@@ -71671,6 +71948,105 @@ function PentestAgentDisplay() {
|
|
|
71671
71948
|
if (hasStarted) {
|
|
71672
71949
|
return;
|
|
71673
71950
|
}
|
|
71951
|
+
if (focusedIndex === 3 && key.name === "up") {
|
|
71952
|
+
if (headerMode === "custom" && headerEditMode === "list") {
|
|
71953
|
+
if (headerEntries.length > 0) {
|
|
71954
|
+
setSelectedHeaderIndex((prev) => (prev - 1 + headerEntries.length) % headerEntries.length);
|
|
71955
|
+
}
|
|
71956
|
+
} else {
|
|
71957
|
+
const modes = ["none", "default", "custom"];
|
|
71958
|
+
const currentIndex = modes.indexOf(headerMode);
|
|
71959
|
+
const newMode = modes[(currentIndex - 1 + 3) % 3];
|
|
71960
|
+
if (newMode)
|
|
71961
|
+
setHeaderMode(newMode);
|
|
71962
|
+
}
|
|
71963
|
+
return;
|
|
71964
|
+
}
|
|
71965
|
+
if (focusedIndex === 3 && key.name === "down") {
|
|
71966
|
+
if (headerMode === "custom" && headerEditMode === "list") {
|
|
71967
|
+
if (headerEntries.length > 0) {
|
|
71968
|
+
setSelectedHeaderIndex((prev) => (prev + 1) % headerEntries.length);
|
|
71969
|
+
}
|
|
71970
|
+
} else {
|
|
71971
|
+
const modes = ["none", "default", "custom"];
|
|
71972
|
+
const currentIndex = modes.indexOf(headerMode);
|
|
71973
|
+
const newMode = modes[(currentIndex + 1) % 3];
|
|
71974
|
+
if (newMode)
|
|
71975
|
+
setHeaderMode(newMode);
|
|
71976
|
+
}
|
|
71977
|
+
return;
|
|
71978
|
+
}
|
|
71979
|
+
if (headerMode === "custom" && focusedIndex === 3) {
|
|
71980
|
+
if (key.name === "a" && headerEditMode === "list") {
|
|
71981
|
+
setHeaderEditMode("input");
|
|
71982
|
+
setHeaderInputName("");
|
|
71983
|
+
setHeaderInputValue("");
|
|
71984
|
+
setInputError("");
|
|
71985
|
+
setEditingHeaderKey(null);
|
|
71986
|
+
setFocusedIndex(3);
|
|
71987
|
+
return;
|
|
71988
|
+
}
|
|
71989
|
+
if (key.name === "e" && headerEditMode === "list" && headerEntries.length > 0) {
|
|
71990
|
+
const entry = headerEntries[selectedHeaderIndex];
|
|
71991
|
+
if (entry) {
|
|
71992
|
+
const [key2, value] = entry;
|
|
71993
|
+
setHeaderInputName(key2);
|
|
71994
|
+
setHeaderInputValue(value);
|
|
71995
|
+
setEditingHeaderKey(key2);
|
|
71996
|
+
setHeaderEditMode("input");
|
|
71997
|
+
setInputError("");
|
|
71998
|
+
setFocusedIndex(3);
|
|
71999
|
+
}
|
|
72000
|
+
return;
|
|
72001
|
+
}
|
|
72002
|
+
if (key.name === "d" && headerEditMode === "list" && headerEntries.length > 0) {
|
|
72003
|
+
const entry = headerEntries[selectedHeaderIndex];
|
|
72004
|
+
if (entry) {
|
|
72005
|
+
const [keyToDelete] = entry;
|
|
72006
|
+
const newHeaders = { ...customHeaders };
|
|
72007
|
+
delete newHeaders[keyToDelete];
|
|
72008
|
+
setCustomHeaders(newHeaders);
|
|
72009
|
+
setSelectedHeaderIndex(Math.max(0, selectedHeaderIndex - 1));
|
|
72010
|
+
}
|
|
72011
|
+
return;
|
|
72012
|
+
}
|
|
72013
|
+
if (key.name === "escape" && headerEditMode === "input") {
|
|
72014
|
+
setHeaderEditMode("list");
|
|
72015
|
+
setHeaderInputName("");
|
|
72016
|
+
setHeaderInputValue("");
|
|
72017
|
+
setInputError("");
|
|
72018
|
+
setEditingHeaderKey(null);
|
|
72019
|
+
setFocusedIndex(2);
|
|
72020
|
+
return;
|
|
72021
|
+
}
|
|
72022
|
+
}
|
|
72023
|
+
if (headerMode === "custom" && focusedIndex === 4 && key.name === "return") {
|
|
72024
|
+
const headerName = headerInputName.trim();
|
|
72025
|
+
const headerValue = headerInputValue.trim();
|
|
72026
|
+
if (!headerName) {
|
|
72027
|
+
setInputError("Header name cannot be empty");
|
|
72028
|
+
return;
|
|
72029
|
+
}
|
|
72030
|
+
if (!/^[A-Za-z][A-Za-z0-9-]*$/.test(headerName)) {
|
|
72031
|
+
setInputError("Invalid header name - Use only letters, numbers, and hyphens");
|
|
72032
|
+
return;
|
|
72033
|
+
}
|
|
72034
|
+
if (editingHeaderKey && editingHeaderKey !== headerName) {
|
|
72035
|
+
const newHeaders = { ...customHeaders };
|
|
72036
|
+
delete newHeaders[editingHeaderKey];
|
|
72037
|
+
newHeaders[headerName] = headerValue;
|
|
72038
|
+
setCustomHeaders(newHeaders);
|
|
72039
|
+
} else {
|
|
72040
|
+
setCustomHeaders({ ...customHeaders, [headerName]: headerValue });
|
|
72041
|
+
}
|
|
72042
|
+
setHeaderEditMode("list");
|
|
72043
|
+
setHeaderInputName("");
|
|
72044
|
+
setHeaderInputValue("");
|
|
72045
|
+
setInputError("");
|
|
72046
|
+
setEditingHeaderKey(null);
|
|
72047
|
+
setFocusedIndex(2);
|
|
72048
|
+
return;
|
|
72049
|
+
}
|
|
71674
72050
|
if (key.name === "tab" && !key.shift) {
|
|
71675
72051
|
setFocusedIndex((prev) => (prev + 1) % inputs.length);
|
|
71676
72052
|
return;
|
|
@@ -71679,9 +72055,21 @@ function PentestAgentDisplay() {
|
|
|
71679
72055
|
setFocusedIndex((prev) => (prev - 1 + inputs.length) % inputs.length);
|
|
71680
72056
|
return;
|
|
71681
72057
|
}
|
|
71682
|
-
if (key.name === "return") {
|
|
72058
|
+
if (key.name === "return" && focusedIndex < 4) {
|
|
71683
72059
|
if (target && objective) {
|
|
71684
|
-
|
|
72060
|
+
const parsedRps = rps ? parseInt(rps, 10) : undefined;
|
|
72061
|
+
const sessionConfig = {
|
|
72062
|
+
offensiveHeaders: {
|
|
72063
|
+
mode: headerMode,
|
|
72064
|
+
headers: headerMode === "custom" ? customHeaders : undefined
|
|
72065
|
+
},
|
|
72066
|
+
...parsedRps && !isNaN(parsedRps) && parsedRps > 0 && {
|
|
72067
|
+
rateLimiter: {
|
|
72068
|
+
requestsPerSecond: parsedRps
|
|
72069
|
+
}
|
|
72070
|
+
}
|
|
72071
|
+
};
|
|
72072
|
+
beginExecution(sessionConfig);
|
|
71685
72073
|
}
|
|
71686
72074
|
}
|
|
71687
72075
|
});
|
|
@@ -71695,7 +72083,7 @@ function PentestAgentDisplay() {
|
|
|
71695
72083
|
});
|
|
71696
72084
|
}
|
|
71697
72085
|
}
|
|
71698
|
-
async function beginExecution() {
|
|
72086
|
+
async function beginExecution(sessionConfig) {
|
|
71699
72087
|
if (target && objective && !hasStarted) {
|
|
71700
72088
|
setHasStarted(true);
|
|
71701
72089
|
setThinking(true);
|
|
@@ -71708,6 +72096,7 @@ function PentestAgentDisplay() {
|
|
|
71708
72096
|
objective,
|
|
71709
72097
|
model: model.id,
|
|
71710
72098
|
abortSignal: controller.signal,
|
|
72099
|
+
sessionConfig,
|
|
71711
72100
|
onStepFinish: ({ usage }) => {
|
|
71712
72101
|
const stepTokens = (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0);
|
|
71713
72102
|
setTokenCount(stepTokens);
|
|
@@ -71901,6 +72290,244 @@ Path: ${result.session.rootPath}`,
|
|
|
71901
72290
|
onInput: setObjective,
|
|
71902
72291
|
focused: focusedIndex === 1
|
|
71903
72292
|
}, undefined, false, undefined, this),
|
|
72293
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(Input, {
|
|
72294
|
+
label: "Rate Limit (RPS)",
|
|
72295
|
+
description: "Max requests/sec (leave empty for unlimited)",
|
|
72296
|
+
placeholder: "15 (recommended)",
|
|
72297
|
+
value: rps,
|
|
72298
|
+
onInput: setRps,
|
|
72299
|
+
focused: focusedIndex === 2
|
|
72300
|
+
}, undefined, false, undefined, this),
|
|
72301
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
72302
|
+
border: true,
|
|
72303
|
+
width: "100%",
|
|
72304
|
+
borderStyle: "heavy",
|
|
72305
|
+
backgroundColor: "black",
|
|
72306
|
+
borderColor: focusedIndex === 3 ? "green" : "gray",
|
|
72307
|
+
flexDirection: "column",
|
|
72308
|
+
padding: 1,
|
|
72309
|
+
children: [
|
|
72310
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
72311
|
+
fg: "green",
|
|
72312
|
+
children: "Offensive Request Headers"
|
|
72313
|
+
}, undefined, false, undefined, this),
|
|
72314
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
72315
|
+
fg: "gray",
|
|
72316
|
+
children: "Configure headers for HTTP tools (curl, nmap, nikto, etc.)"
|
|
72317
|
+
}, undefined, false, undefined, this),
|
|
72318
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
72319
|
+
fg: "gray",
|
|
72320
|
+
children: "─────────────────────────────────────────────────"
|
|
72321
|
+
}, undefined, false, undefined, this),
|
|
72322
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
72323
|
+
flexDirection: "column",
|
|
72324
|
+
children: [
|
|
72325
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
72326
|
+
fg: headerMode === "none" ? "green" : "gray",
|
|
72327
|
+
children: [
|
|
72328
|
+
headerMode === "none" ? "●" : "○",
|
|
72329
|
+
" None ",
|
|
72330
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
72331
|
+
fg: "gray",
|
|
72332
|
+
children: "(no custom headers)"
|
|
72333
|
+
}, undefined, false, undefined, this)
|
|
72334
|
+
]
|
|
72335
|
+
}, undefined, true, undefined, this),
|
|
72336
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
72337
|
+
fg: headerMode === "default" ? "green" : "gray",
|
|
72338
|
+
children: [
|
|
72339
|
+
headerMode === "default" ? "●" : "○",
|
|
72340
|
+
" Default ",
|
|
72341
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
72342
|
+
fg: "gray",
|
|
72343
|
+
children: "(User-Agent: pensar-apex)"
|
|
72344
|
+
}, undefined, false, undefined, this)
|
|
72345
|
+
]
|
|
72346
|
+
}, undefined, true, undefined, this),
|
|
72347
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
72348
|
+
fg: headerMode === "custom" ? "green" : "gray",
|
|
72349
|
+
children: [
|
|
72350
|
+
headerMode === "custom" ? "●" : "○",
|
|
72351
|
+
" Custom ",
|
|
72352
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
72353
|
+
fg: "gray",
|
|
72354
|
+
children: "(define headers below)"
|
|
72355
|
+
}, undefined, false, undefined, this)
|
|
72356
|
+
]
|
|
72357
|
+
}, undefined, true, undefined, this)
|
|
72358
|
+
]
|
|
72359
|
+
}, undefined, true, undefined, this),
|
|
72360
|
+
headerMode === "custom" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
72361
|
+
flexDirection: "column",
|
|
72362
|
+
children: [
|
|
72363
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
72364
|
+
fg: "gray",
|
|
72365
|
+
children: "─────────────────────────────────────────────────"
|
|
72366
|
+
}, undefined, false, undefined, this),
|
|
72367
|
+
headerEditMode === "list" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
72368
|
+
flexDirection: "column",
|
|
72369
|
+
children: headerEntries.length > 0 ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
|
|
72370
|
+
children: [
|
|
72371
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
72372
|
+
fg: "green",
|
|
72373
|
+
children: "Configured Headers:"
|
|
72374
|
+
}, undefined, false, undefined, this),
|
|
72375
|
+
headerEntries.map(([key, value], index) => /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
72376
|
+
fg: index === selectedHeaderIndex ? "green" : "gray",
|
|
72377
|
+
children: [
|
|
72378
|
+
index === selectedHeaderIndex ? "▸" : " ",
|
|
72379
|
+
" • ",
|
|
72380
|
+
key,
|
|
72381
|
+
": ",
|
|
72382
|
+
value
|
|
72383
|
+
]
|
|
72384
|
+
}, key, true, undefined, this))
|
|
72385
|
+
]
|
|
72386
|
+
}, undefined, true, undefined, this) : /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
72387
|
+
fg: "gray",
|
|
72388
|
+
children: "No headers configured. Press [A] to add."
|
|
72389
|
+
}, undefined, false, undefined, this)
|
|
72390
|
+
}, undefined, false, undefined, this),
|
|
72391
|
+
headerEditMode === "input" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
72392
|
+
flexDirection: "column",
|
|
72393
|
+
children: [
|
|
72394
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
72395
|
+
fg: "green",
|
|
72396
|
+
children: editingHeaderKey ? "Edit Header" : "Add Header"
|
|
72397
|
+
}, undefined, false, undefined, this),
|
|
72398
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
72399
|
+
flexDirection: "row",
|
|
72400
|
+
children: [
|
|
72401
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
72402
|
+
fg: "gray",
|
|
72403
|
+
children: "Name: "
|
|
72404
|
+
}, undefined, false, undefined, this),
|
|
72405
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("input", {
|
|
72406
|
+
value: headerInputName,
|
|
72407
|
+
onInput: setHeaderInputName,
|
|
72408
|
+
placeholder: "User-Agent",
|
|
72409
|
+
focused: focusedIndex === 3,
|
|
72410
|
+
width: 40,
|
|
72411
|
+
backgroundColor: "black"
|
|
72412
|
+
}, undefined, false, undefined, this)
|
|
72413
|
+
]
|
|
72414
|
+
}, undefined, true, undefined, this),
|
|
72415
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
72416
|
+
flexDirection: "row",
|
|
72417
|
+
children: [
|
|
72418
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
72419
|
+
fg: "gray",
|
|
72420
|
+
children: "Value: "
|
|
72421
|
+
}, undefined, false, undefined, this),
|
|
72422
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("input", {
|
|
72423
|
+
value: headerInputValue,
|
|
72424
|
+
onInput: setHeaderInputValue,
|
|
72425
|
+
placeholder: "pensar-apex_client123",
|
|
72426
|
+
focused: focusedIndex === 4,
|
|
72427
|
+
width: 40,
|
|
72428
|
+
backgroundColor: "black"
|
|
72429
|
+
}, undefined, false, undefined, this)
|
|
72430
|
+
]
|
|
72431
|
+
}, undefined, true, undefined, this),
|
|
72432
|
+
inputError && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
72433
|
+
fg: "red",
|
|
72434
|
+
children: inputError
|
|
72435
|
+
}, undefined, false, undefined, this)
|
|
72436
|
+
]
|
|
72437
|
+
}, undefined, true, undefined, this),
|
|
72438
|
+
headerEntries.length > 0 && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
72439
|
+
flexDirection: "column",
|
|
72440
|
+
children: [
|
|
72441
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
72442
|
+
fg: "gray",
|
|
72443
|
+
children: "─────────────────────────────────────────────────"
|
|
72444
|
+
}, undefined, false, undefined, this),
|
|
72445
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
72446
|
+
fg: "green",
|
|
72447
|
+
children: "Preview:"
|
|
72448
|
+
}, undefined, false, undefined, this),
|
|
72449
|
+
headerEntries.map(([key, value]) => /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
72450
|
+
fg: "gray",
|
|
72451
|
+
children: [
|
|
72452
|
+
key,
|
|
72453
|
+
": ",
|
|
72454
|
+
value
|
|
72455
|
+
]
|
|
72456
|
+
}, key, true, undefined, this))
|
|
72457
|
+
]
|
|
72458
|
+
}, undefined, true, undefined, this),
|
|
72459
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
72460
|
+
fg: "gray",
|
|
72461
|
+
children: "─────────────────────────────────────────────────"
|
|
72462
|
+
}, undefined, false, undefined, this),
|
|
72463
|
+
headerEditMode === "list" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
72464
|
+
fg: "gray",
|
|
72465
|
+
children: [
|
|
72466
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
72467
|
+
fg: "green",
|
|
72468
|
+
children: "[A]"
|
|
72469
|
+
}, undefined, false, undefined, this),
|
|
72470
|
+
" Add ",
|
|
72471
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
72472
|
+
fg: "green",
|
|
72473
|
+
children: "[E]"
|
|
72474
|
+
}, undefined, false, undefined, this),
|
|
72475
|
+
" Edit ",
|
|
72476
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
72477
|
+
fg: "green",
|
|
72478
|
+
children: "[D]"
|
|
72479
|
+
}, undefined, false, undefined, this),
|
|
72480
|
+
" Delete ",
|
|
72481
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
72482
|
+
fg: "green",
|
|
72483
|
+
children: "[↑↓]"
|
|
72484
|
+
}, undefined, false, undefined, this),
|
|
72485
|
+
" Navigate"
|
|
72486
|
+
]
|
|
72487
|
+
}, undefined, true, undefined, this),
|
|
72488
|
+
headerEditMode === "input" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
72489
|
+
fg: "gray",
|
|
72490
|
+
children: [
|
|
72491
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
72492
|
+
fg: "green",
|
|
72493
|
+
children: "[TAB]"
|
|
72494
|
+
}, undefined, false, undefined, this),
|
|
72495
|
+
" Next Field ",
|
|
72496
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
72497
|
+
fg: "green",
|
|
72498
|
+
children: "[ENTER]"
|
|
72499
|
+
}, undefined, false, undefined, this),
|
|
72500
|
+
" Save ",
|
|
72501
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
72502
|
+
fg: "green",
|
|
72503
|
+
children: "[ESC]"
|
|
72504
|
+
}, undefined, false, undefined, this),
|
|
72505
|
+
" Cancel"
|
|
72506
|
+
]
|
|
72507
|
+
}, undefined, true, undefined, this)
|
|
72508
|
+
]
|
|
72509
|
+
}, undefined, true, undefined, this),
|
|
72510
|
+
headerMode !== "custom" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
72511
|
+
flexDirection: "column",
|
|
72512
|
+
children: [
|
|
72513
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
72514
|
+
fg: "gray",
|
|
72515
|
+
children: "─────────────────────────────────────────────────"
|
|
72516
|
+
}, undefined, false, undefined, this),
|
|
72517
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
72518
|
+
fg: "gray",
|
|
72519
|
+
children: [
|
|
72520
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
72521
|
+
fg: "green",
|
|
72522
|
+
children: "[↑↓]"
|
|
72523
|
+
}, undefined, false, undefined, this),
|
|
72524
|
+
" Select mode"
|
|
72525
|
+
]
|
|
72526
|
+
}, undefined, true, undefined, this)
|
|
72527
|
+
]
|
|
72528
|
+
}, undefined, true, undefined, this)
|
|
72529
|
+
]
|
|
72530
|
+
}, undefined, true, undefined, this),
|
|
71904
72531
|
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
71905
72532
|
flexDirection: "row",
|
|
71906
72533
|
width: "100%",
|
|
@@ -74073,12 +74700,13 @@ function runAgent3(opts) {
|
|
|
74073
74700
|
model,
|
|
74074
74701
|
onStepFinish,
|
|
74075
74702
|
abortSignal,
|
|
74703
|
+
sessionConfig,
|
|
74076
74704
|
onSubagentSpawn,
|
|
74077
74705
|
onSubagentMessage,
|
|
74078
74706
|
onSubagentComplete,
|
|
74079
74707
|
session: sessionProp
|
|
74080
74708
|
} = opts;
|
|
74081
|
-
const session = sessionProp || createSession(target);
|
|
74709
|
+
const session = sessionProp || createSession(target, undefined, undefined, sessionConfig);
|
|
74082
74710
|
const logger = new Logger(session);
|
|
74083
74711
|
logger.log(`Created thorough pentest session: ${session.id}`);
|
|
74084
74712
|
logger.log(`Session path: ${session.rootPath}`);
|
|
@@ -74673,7 +75301,7 @@ function useThoroughPentestAgent() {
|
|
|
74673
75301
|
}
|
|
74674
75302
|
}
|
|
74675
75303
|
}
|
|
74676
|
-
async function beginExecution() {
|
|
75304
|
+
async function beginExecution(sessionConfig) {
|
|
74677
75305
|
if (target && !hasStarted) {
|
|
74678
75306
|
setHasStarted(true);
|
|
74679
75307
|
setThinking(true);
|
|
@@ -74685,6 +75313,7 @@ function useThoroughPentestAgent() {
|
|
|
74685
75313
|
target,
|
|
74686
75314
|
model: model.id,
|
|
74687
75315
|
abortSignal: controller.signal,
|
|
75316
|
+
sessionConfig,
|
|
74688
75317
|
onStepFinish: ({ usage }) => {
|
|
74689
75318
|
const stepTokens = (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0);
|
|
74690
75319
|
setTokenCount(stepTokens);
|
|
@@ -74892,6 +75521,16 @@ Mode: Pentest (Orchestrator)`,
|
|
|
74892
75521
|
function ThoroughPentestAgentDisplay() {
|
|
74893
75522
|
const [focusedIndex, setFocusedIndex] = import_react23.useState(0);
|
|
74894
75523
|
const { closeThoroughPentest } = useCommand();
|
|
75524
|
+
const [rps, setRps] = import_react23.useState("");
|
|
75525
|
+
const [headerMode, setHeaderMode] = import_react23.useState("default");
|
|
75526
|
+
const [customHeaders, setCustomHeaders] = import_react23.useState({});
|
|
75527
|
+
const [headerInputName, setHeaderInputName] = import_react23.useState("");
|
|
75528
|
+
const [headerInputValue, setHeaderInputValue] = import_react23.useState("");
|
|
75529
|
+
const [selectedHeaderIndex, setSelectedHeaderIndex] = import_react23.useState(0);
|
|
75530
|
+
const [headerEditMode, setHeaderEditMode] = import_react23.useState("list");
|
|
75531
|
+
const [inputError, setInputError] = import_react23.useState("");
|
|
75532
|
+
const [editingHeaderKey, setEditingHeaderKey] = import_react23.useState(null);
|
|
75533
|
+
const [inputFocusField, setInputFocusField] = import_react23.useState("name");
|
|
74895
75534
|
const {
|
|
74896
75535
|
target,
|
|
74897
75536
|
setTarget,
|
|
@@ -74905,7 +75544,8 @@ function ThoroughPentestAgentDisplay() {
|
|
|
74905
75544
|
beginExecution,
|
|
74906
75545
|
openReport
|
|
74907
75546
|
} = useThoroughPentestAgent();
|
|
74908
|
-
const inputs = ["target", "
|
|
75547
|
+
const inputs = headerMode === "custom" && headerEditMode === "input" ? ["target", "rps", "headerMode", "headerInputName", "headerInputValue"] : ["target", "rps", "headerMode"];
|
|
75548
|
+
const headerEntries = Object.entries(customHeaders);
|
|
74909
75549
|
useKeyboard((key) => {
|
|
74910
75550
|
if (key.name === "escape") {
|
|
74911
75551
|
closeThoroughPentest();
|
|
@@ -74924,6 +75564,107 @@ function ThoroughPentestAgentDisplay() {
|
|
|
74924
75564
|
if (hasStarted) {
|
|
74925
75565
|
return;
|
|
74926
75566
|
}
|
|
75567
|
+
if (focusedIndex === 2 && key.name === "up") {
|
|
75568
|
+
if (headerMode === "custom" && headerEditMode === "list") {
|
|
75569
|
+
if (headerEntries.length > 0) {
|
|
75570
|
+
setSelectedHeaderIndex((prev) => (prev - 1 + headerEntries.length) % headerEntries.length);
|
|
75571
|
+
}
|
|
75572
|
+
} else {
|
|
75573
|
+
const modes = ["none", "default", "custom"];
|
|
75574
|
+
const currentIndex = modes.indexOf(headerMode);
|
|
75575
|
+
const newMode = modes[(currentIndex - 1 + 3) % 3];
|
|
75576
|
+
if (newMode)
|
|
75577
|
+
setHeaderMode(newMode);
|
|
75578
|
+
}
|
|
75579
|
+
return;
|
|
75580
|
+
}
|
|
75581
|
+
if (focusedIndex === 2 && key.name === "down") {
|
|
75582
|
+
if (headerMode === "custom" && headerEditMode === "list") {
|
|
75583
|
+
if (headerEntries.length > 0) {
|
|
75584
|
+
setSelectedHeaderIndex((prev) => (prev + 1) % headerEntries.length);
|
|
75585
|
+
}
|
|
75586
|
+
} else {
|
|
75587
|
+
const modes = ["none", "default", "custom"];
|
|
75588
|
+
const currentIndex = modes.indexOf(headerMode);
|
|
75589
|
+
const newMode = modes[(currentIndex + 1) % 3];
|
|
75590
|
+
if (newMode)
|
|
75591
|
+
setHeaderMode(newMode);
|
|
75592
|
+
}
|
|
75593
|
+
return;
|
|
75594
|
+
}
|
|
75595
|
+
if (headerMode === "custom" && focusedIndex === 2) {
|
|
75596
|
+
if (key.name === "a" && headerEditMode === "list") {
|
|
75597
|
+
setHeaderEditMode("input");
|
|
75598
|
+
setHeaderInputName("");
|
|
75599
|
+
setHeaderInputValue("");
|
|
75600
|
+
setInputError("");
|
|
75601
|
+
setEditingHeaderKey(null);
|
|
75602
|
+
setInputFocusField("name");
|
|
75603
|
+
setFocusedIndex(2);
|
|
75604
|
+
return;
|
|
75605
|
+
}
|
|
75606
|
+
if (key.name === "e" && headerEditMode === "list" && headerEntries.length > 0) {
|
|
75607
|
+
const entry = headerEntries[selectedHeaderIndex];
|
|
75608
|
+
if (entry) {
|
|
75609
|
+
const [key2, value] = entry;
|
|
75610
|
+
setHeaderInputName(key2);
|
|
75611
|
+
setHeaderInputValue(value);
|
|
75612
|
+
setEditingHeaderKey(key2);
|
|
75613
|
+
setHeaderEditMode("input");
|
|
75614
|
+
setInputError("");
|
|
75615
|
+
setInputFocusField("name");
|
|
75616
|
+
setFocusedIndex(2);
|
|
75617
|
+
}
|
|
75618
|
+
return;
|
|
75619
|
+
}
|
|
75620
|
+
if (key.name === "d" && headerEditMode === "list" && headerEntries.length > 0) {
|
|
75621
|
+
const entry = headerEntries[selectedHeaderIndex];
|
|
75622
|
+
if (entry) {
|
|
75623
|
+
const [keyToDelete] = entry;
|
|
75624
|
+
const newHeaders = { ...customHeaders };
|
|
75625
|
+
delete newHeaders[keyToDelete];
|
|
75626
|
+
setCustomHeaders(newHeaders);
|
|
75627
|
+
setSelectedHeaderIndex(Math.max(0, selectedHeaderIndex - 1));
|
|
75628
|
+
}
|
|
75629
|
+
return;
|
|
75630
|
+
}
|
|
75631
|
+
if (key.name === "escape" && headerEditMode === "input") {
|
|
75632
|
+
setHeaderEditMode("list");
|
|
75633
|
+
setHeaderInputName("");
|
|
75634
|
+
setHeaderInputValue("");
|
|
75635
|
+
setInputError("");
|
|
75636
|
+
setEditingHeaderKey(null);
|
|
75637
|
+
setFocusedIndex(1);
|
|
75638
|
+
return;
|
|
75639
|
+
}
|
|
75640
|
+
}
|
|
75641
|
+
if (headerMode === "custom" && focusedIndex === 3 && key.name === "return") {
|
|
75642
|
+
const headerName = headerInputName.trim();
|
|
75643
|
+
const headerValue = headerInputValue.trim();
|
|
75644
|
+
if (!headerName) {
|
|
75645
|
+
setInputError("Header name cannot be empty");
|
|
75646
|
+
return;
|
|
75647
|
+
}
|
|
75648
|
+
if (!/^[A-Za-z][A-Za-z0-9-]*$/.test(headerName)) {
|
|
75649
|
+
setInputError("Invalid header name - Use only letters, numbers, and hyphens");
|
|
75650
|
+
return;
|
|
75651
|
+
}
|
|
75652
|
+
if (editingHeaderKey && editingHeaderKey !== headerName) {
|
|
75653
|
+
const newHeaders = { ...customHeaders };
|
|
75654
|
+
delete newHeaders[editingHeaderKey];
|
|
75655
|
+
newHeaders[headerName] = headerValue;
|
|
75656
|
+
setCustomHeaders(newHeaders);
|
|
75657
|
+
} else {
|
|
75658
|
+
setCustomHeaders({ ...customHeaders, [headerName]: headerValue });
|
|
75659
|
+
}
|
|
75660
|
+
setHeaderEditMode("list");
|
|
75661
|
+
setHeaderInputName("");
|
|
75662
|
+
setHeaderInputValue("");
|
|
75663
|
+
setInputError("");
|
|
75664
|
+
setEditingHeaderKey(null);
|
|
75665
|
+
setFocusedIndex(1);
|
|
75666
|
+
return;
|
|
75667
|
+
}
|
|
74927
75668
|
if (key.name === "tab" && !key.shift) {
|
|
74928
75669
|
setFocusedIndex((prev) => (prev + 1) % inputs.length);
|
|
74929
75670
|
return;
|
|
@@ -74932,9 +75673,21 @@ function ThoroughPentestAgentDisplay() {
|
|
|
74932
75673
|
setFocusedIndex((prev) => (prev - 1 + inputs.length) % inputs.length);
|
|
74933
75674
|
return;
|
|
74934
75675
|
}
|
|
74935
|
-
if (key.name === "return") {
|
|
75676
|
+
if (key.name === "return" && focusedIndex < 3) {
|
|
74936
75677
|
if (target) {
|
|
74937
|
-
|
|
75678
|
+
const parsedRps = rps ? parseInt(rps, 10) : undefined;
|
|
75679
|
+
const sessionConfig = {
|
|
75680
|
+
offensiveHeaders: {
|
|
75681
|
+
mode: headerMode,
|
|
75682
|
+
headers: headerMode === "custom" ? customHeaders : undefined
|
|
75683
|
+
},
|
|
75684
|
+
...parsedRps && !isNaN(parsedRps) && parsedRps > 0 && {
|
|
75685
|
+
rateLimiter: {
|
|
75686
|
+
requestsPerSecond: parsedRps
|
|
75687
|
+
}
|
|
75688
|
+
}
|
|
75689
|
+
};
|
|
75690
|
+
beginExecution(sessionConfig);
|
|
74938
75691
|
}
|
|
74939
75692
|
}
|
|
74940
75693
|
});
|
|
@@ -75050,6 +75803,244 @@ function ThoroughPentestAgentDisplay() {
|
|
|
75050
75803
|
onInput: setTarget,
|
|
75051
75804
|
focused: focusedIndex === 0
|
|
75052
75805
|
}, undefined, false, undefined, this),
|
|
75806
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(Input, {
|
|
75807
|
+
label: "Rate Limit (RPS)",
|
|
75808
|
+
description: "Max requests/sec (leave empty for unlimited)",
|
|
75809
|
+
placeholder: "15 (recommended)",
|
|
75810
|
+
value: rps,
|
|
75811
|
+
onInput: setRps,
|
|
75812
|
+
focused: focusedIndex === 1
|
|
75813
|
+
}, undefined, false, undefined, this),
|
|
75814
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
75815
|
+
border: true,
|
|
75816
|
+
width: "100%",
|
|
75817
|
+
borderStyle: "heavy",
|
|
75818
|
+
backgroundColor: "black",
|
|
75819
|
+
borderColor: focusedIndex === 2 ? "green" : "gray",
|
|
75820
|
+
flexDirection: "column",
|
|
75821
|
+
padding: 1,
|
|
75822
|
+
children: [
|
|
75823
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
75824
|
+
fg: "green",
|
|
75825
|
+
children: "Offensive Request Headers"
|
|
75826
|
+
}, undefined, false, undefined, this),
|
|
75827
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
75828
|
+
fg: "gray",
|
|
75829
|
+
children: "Configure headers for HTTP tools (curl, nmap, nikto, etc.)"
|
|
75830
|
+
}, undefined, false, undefined, this),
|
|
75831
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
75832
|
+
fg: "gray",
|
|
75833
|
+
children: "─────────────────────────────────────────────────"
|
|
75834
|
+
}, undefined, false, undefined, this),
|
|
75835
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
75836
|
+
flexDirection: "column",
|
|
75837
|
+
children: [
|
|
75838
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
75839
|
+
fg: headerMode === "none" ? "green" : "gray",
|
|
75840
|
+
children: [
|
|
75841
|
+
headerMode === "none" ? "●" : "○",
|
|
75842
|
+
" None ",
|
|
75843
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
75844
|
+
fg: "gray",
|
|
75845
|
+
children: "(no custom headers)"
|
|
75846
|
+
}, undefined, false, undefined, this)
|
|
75847
|
+
]
|
|
75848
|
+
}, undefined, true, undefined, this),
|
|
75849
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
75850
|
+
fg: headerMode === "default" ? "green" : "gray",
|
|
75851
|
+
children: [
|
|
75852
|
+
headerMode === "default" ? "●" : "○",
|
|
75853
|
+
" Default ",
|
|
75854
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
75855
|
+
fg: "gray",
|
|
75856
|
+
children: "(User-Agent: pensar-apex)"
|
|
75857
|
+
}, undefined, false, undefined, this)
|
|
75858
|
+
]
|
|
75859
|
+
}, undefined, true, undefined, this),
|
|
75860
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
75861
|
+
fg: headerMode === "custom" ? "green" : "gray",
|
|
75862
|
+
children: [
|
|
75863
|
+
headerMode === "custom" ? "●" : "○",
|
|
75864
|
+
" Custom ",
|
|
75865
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
75866
|
+
fg: "gray",
|
|
75867
|
+
children: "(define headers below)"
|
|
75868
|
+
}, undefined, false, undefined, this)
|
|
75869
|
+
]
|
|
75870
|
+
}, undefined, true, undefined, this)
|
|
75871
|
+
]
|
|
75872
|
+
}, undefined, true, undefined, this),
|
|
75873
|
+
headerMode === "custom" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
75874
|
+
flexDirection: "column",
|
|
75875
|
+
children: [
|
|
75876
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
75877
|
+
fg: "gray",
|
|
75878
|
+
children: "─────────────────────────────────────────────────"
|
|
75879
|
+
}, undefined, false, undefined, this),
|
|
75880
|
+
headerEditMode === "list" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
75881
|
+
flexDirection: "column",
|
|
75882
|
+
children: headerEntries.length > 0 ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
|
|
75883
|
+
children: [
|
|
75884
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
75885
|
+
fg: "green",
|
|
75886
|
+
children: "Configured Headers:"
|
|
75887
|
+
}, undefined, false, undefined, this),
|
|
75888
|
+
headerEntries.map(([key, value], index) => /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
75889
|
+
fg: index === selectedHeaderIndex ? "green" : "gray",
|
|
75890
|
+
children: [
|
|
75891
|
+
index === selectedHeaderIndex ? "▸" : " ",
|
|
75892
|
+
" • ",
|
|
75893
|
+
key,
|
|
75894
|
+
": ",
|
|
75895
|
+
value
|
|
75896
|
+
]
|
|
75897
|
+
}, key, true, undefined, this))
|
|
75898
|
+
]
|
|
75899
|
+
}, undefined, true, undefined, this) : /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
75900
|
+
fg: "gray",
|
|
75901
|
+
children: "No headers configured. Press [A] to add."
|
|
75902
|
+
}, undefined, false, undefined, this)
|
|
75903
|
+
}, undefined, false, undefined, this),
|
|
75904
|
+
headerEditMode === "input" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
75905
|
+
flexDirection: "column",
|
|
75906
|
+
children: [
|
|
75907
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
75908
|
+
fg: "green",
|
|
75909
|
+
children: editingHeaderKey ? "Edit Header" : "Add Header"
|
|
75910
|
+
}, undefined, false, undefined, this),
|
|
75911
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
75912
|
+
flexDirection: "row",
|
|
75913
|
+
children: [
|
|
75914
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
75915
|
+
fg: "gray",
|
|
75916
|
+
children: "Name: "
|
|
75917
|
+
}, undefined, false, undefined, this),
|
|
75918
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("input", {
|
|
75919
|
+
value: headerInputName,
|
|
75920
|
+
onInput: setHeaderInputName,
|
|
75921
|
+
placeholder: "User-Agent",
|
|
75922
|
+
focused: focusedIndex === 2,
|
|
75923
|
+
width: 40,
|
|
75924
|
+
backgroundColor: "black"
|
|
75925
|
+
}, undefined, false, undefined, this)
|
|
75926
|
+
]
|
|
75927
|
+
}, undefined, true, undefined, this),
|
|
75928
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
75929
|
+
flexDirection: "row",
|
|
75930
|
+
children: [
|
|
75931
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
75932
|
+
fg: "gray",
|
|
75933
|
+
children: "Value: "
|
|
75934
|
+
}, undefined, false, undefined, this),
|
|
75935
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("input", {
|
|
75936
|
+
value: headerInputValue,
|
|
75937
|
+
onInput: setHeaderInputValue,
|
|
75938
|
+
placeholder: "pensar-apex_client123",
|
|
75939
|
+
focused: focusedIndex === 3,
|
|
75940
|
+
width: 40,
|
|
75941
|
+
backgroundColor: "black"
|
|
75942
|
+
}, undefined, false, undefined, this)
|
|
75943
|
+
]
|
|
75944
|
+
}, undefined, true, undefined, this),
|
|
75945
|
+
inputError && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
75946
|
+
fg: "red",
|
|
75947
|
+
children: inputError
|
|
75948
|
+
}, undefined, false, undefined, this)
|
|
75949
|
+
]
|
|
75950
|
+
}, undefined, true, undefined, this),
|
|
75951
|
+
headerEntries.length > 0 && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
75952
|
+
flexDirection: "column",
|
|
75953
|
+
children: [
|
|
75954
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
75955
|
+
fg: "gray",
|
|
75956
|
+
children: "─────────────────────────────────────────────────"
|
|
75957
|
+
}, undefined, false, undefined, this),
|
|
75958
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
75959
|
+
fg: "green",
|
|
75960
|
+
children: "Preview:"
|
|
75961
|
+
}, undefined, false, undefined, this),
|
|
75962
|
+
headerEntries.map(([key, value]) => /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
75963
|
+
fg: "gray",
|
|
75964
|
+
children: [
|
|
75965
|
+
key,
|
|
75966
|
+
": ",
|
|
75967
|
+
value
|
|
75968
|
+
]
|
|
75969
|
+
}, key, true, undefined, this))
|
|
75970
|
+
]
|
|
75971
|
+
}, undefined, true, undefined, this),
|
|
75972
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
75973
|
+
fg: "gray",
|
|
75974
|
+
children: "─────────────────────────────────────────────────"
|
|
75975
|
+
}, undefined, false, undefined, this),
|
|
75976
|
+
headerEditMode === "list" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
75977
|
+
fg: "gray",
|
|
75978
|
+
children: [
|
|
75979
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
75980
|
+
fg: "green",
|
|
75981
|
+
children: "[A]"
|
|
75982
|
+
}, undefined, false, undefined, this),
|
|
75983
|
+
" Add ",
|
|
75984
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
75985
|
+
fg: "green",
|
|
75986
|
+
children: "[E]"
|
|
75987
|
+
}, undefined, false, undefined, this),
|
|
75988
|
+
" Edit ",
|
|
75989
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
75990
|
+
fg: "green",
|
|
75991
|
+
children: "[D]"
|
|
75992
|
+
}, undefined, false, undefined, this),
|
|
75993
|
+
" Delete ",
|
|
75994
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
75995
|
+
fg: "green",
|
|
75996
|
+
children: "[↑↓]"
|
|
75997
|
+
}, undefined, false, undefined, this),
|
|
75998
|
+
" Navigate"
|
|
75999
|
+
]
|
|
76000
|
+
}, undefined, true, undefined, this),
|
|
76001
|
+
headerEditMode === "input" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
76002
|
+
fg: "gray",
|
|
76003
|
+
children: [
|
|
76004
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
76005
|
+
fg: "green",
|
|
76006
|
+
children: "[TAB]"
|
|
76007
|
+
}, undefined, false, undefined, this),
|
|
76008
|
+
" Next Field ",
|
|
76009
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
76010
|
+
fg: "green",
|
|
76011
|
+
children: "[ENTER]"
|
|
76012
|
+
}, undefined, false, undefined, this),
|
|
76013
|
+
" Save ",
|
|
76014
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
76015
|
+
fg: "green",
|
|
76016
|
+
children: "[ESC]"
|
|
76017
|
+
}, undefined, false, undefined, this),
|
|
76018
|
+
" Cancel"
|
|
76019
|
+
]
|
|
76020
|
+
}, undefined, true, undefined, this)
|
|
76021
|
+
]
|
|
76022
|
+
}, undefined, true, undefined, this),
|
|
76023
|
+
headerMode !== "custom" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
76024
|
+
flexDirection: "column",
|
|
76025
|
+
children: [
|
|
76026
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
76027
|
+
fg: "gray",
|
|
76028
|
+
children: "─────────────────────────────────────────────────"
|
|
76029
|
+
}, undefined, false, undefined, this),
|
|
76030
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
76031
|
+
fg: "gray",
|
|
76032
|
+
children: [
|
|
76033
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
76034
|
+
fg: "green",
|
|
76035
|
+
children: "[↑↓]"
|
|
76036
|
+
}, undefined, false, undefined, this),
|
|
76037
|
+
" Select mode"
|
|
76038
|
+
]
|
|
76039
|
+
}, undefined, true, undefined, this)
|
|
76040
|
+
]
|
|
76041
|
+
}, undefined, true, undefined, this)
|
|
76042
|
+
]
|
|
76043
|
+
}, undefined, true, undefined, this),
|
|
75053
76044
|
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
75054
76045
|
flexDirection: "row",
|
|
75055
76046
|
width: "100%",
|