pentesting 0.41.0 → 0.43.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/dist/main.js +332 -107
- package/dist/prompts/strategist-system.md +39 -0
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -314,7 +314,7 @@ var ORPHAN_PROCESS_NAMES = [
|
|
|
314
314
|
|
|
315
315
|
// src/shared/constants/agent.ts
|
|
316
316
|
var APP_NAME = "Pentest AI";
|
|
317
|
-
var APP_VERSION = "0.
|
|
317
|
+
var APP_VERSION = "0.43.0";
|
|
318
318
|
var APP_DESCRIPTION = "Autonomous Penetration Testing AI Agent";
|
|
319
319
|
var LLM_ROLES = {
|
|
320
320
|
SYSTEM: "system",
|
|
@@ -6686,8 +6686,8 @@ Returns: All available wordlists with their paths, sizes, and categories.`,
|
|
|
6686
6686
|
}
|
|
6687
6687
|
},
|
|
6688
6688
|
execute: async (p) => {
|
|
6689
|
-
const { existsSync:
|
|
6690
|
-
const { join:
|
|
6689
|
+
const { existsSync: existsSync10, statSync: statSync2, readdirSync: readdirSync3 } = await import("fs");
|
|
6690
|
+
const { join: join12 } = await import("path");
|
|
6691
6691
|
const category = p.category || "";
|
|
6692
6692
|
const search = p.search || "";
|
|
6693
6693
|
const minSize = p.min_size || 0;
|
|
@@ -6733,7 +6733,7 @@ Returns: All available wordlists with their paths, sizes, and categories.`,
|
|
|
6733
6733
|
results.push("");
|
|
6734
6734
|
};
|
|
6735
6735
|
const scanDir = (dirPath, maxDepth = 3, depth = 0) => {
|
|
6736
|
-
if (depth > maxDepth || !
|
|
6736
|
+
if (depth > maxDepth || !existsSync10(dirPath)) return;
|
|
6737
6737
|
let entries;
|
|
6738
6738
|
try {
|
|
6739
6739
|
entries = readdirSync3(dirPath, { withFileTypes: true });
|
|
@@ -6742,7 +6742,7 @@ Returns: All available wordlists with their paths, sizes, and categories.`,
|
|
|
6742
6742
|
}
|
|
6743
6743
|
for (const entry of entries) {
|
|
6744
6744
|
if (entry.name.startsWith(".") || SKIP_DIRS.has(entry.name)) continue;
|
|
6745
|
-
const fullPath =
|
|
6745
|
+
const fullPath = join12(dirPath, entry.name);
|
|
6746
6746
|
if (entry.isDirectory()) {
|
|
6747
6747
|
scanDir(fullPath, maxDepth, depth + 1);
|
|
6748
6748
|
continue;
|
|
@@ -10684,13 +10684,21 @@ var PHASE_TECHNIQUE_MAP = {
|
|
|
10684
10684
|
};
|
|
10685
10685
|
var PromptBuilder = class {
|
|
10686
10686
|
state;
|
|
10687
|
+
strategist = null;
|
|
10687
10688
|
constructor(state) {
|
|
10688
10689
|
this.state = state;
|
|
10689
10690
|
}
|
|
10690
10691
|
/**
|
|
10691
|
-
*
|
|
10692
|
+
* Attach a Strategist instance for meta-prompting.
|
|
10693
|
+
* Called by MainAgent after construction.
|
|
10694
|
+
*/
|
|
10695
|
+
setStrategist(strategist) {
|
|
10696
|
+
this.strategist = strategist;
|
|
10697
|
+
}
|
|
10698
|
+
/**
|
|
10699
|
+
* Build complete prompt for LLM iteration (async).
|
|
10692
10700
|
*
|
|
10693
|
-
* Layers (phase-aware, enhanced with
|
|
10701
|
+
* Layers (phase-aware, enhanced with D-CIPHER meta-prompting):
|
|
10694
10702
|
* 1. base.md — Core identity, rules, autonomy, shell management (~7.6K tok)
|
|
10695
10703
|
* 2. Phase-specific prompt — current phase's full specialist knowledge (~2K tok)
|
|
10696
10704
|
* 3. Core methodology — strategy, orchestrator, evasion (always loaded, ~12K tok)
|
|
@@ -10706,9 +10714,10 @@ var PromptBuilder = class {
|
|
|
10706
10714
|
* 12. Session timeline (#12: episodic memory)
|
|
10707
10715
|
* 13. Learned techniques (#7: dynamic technique library)
|
|
10708
10716
|
* 14. Persistent memory (#12: cross-session knowledge)
|
|
10709
|
-
* 15.
|
|
10717
|
+
* ★ 15. STRATEGIC DIRECTIVE — LLM-generated tactical instructions (D-CIPHER)
|
|
10718
|
+
* 16. User context
|
|
10710
10719
|
*/
|
|
10711
|
-
build(userInput, phase) {
|
|
10720
|
+
async build(userInput, phase) {
|
|
10712
10721
|
const fragments = [
|
|
10713
10722
|
this.loadPromptFile(PROMPT_PATHS.BASE),
|
|
10714
10723
|
this.loadCtfModePrompt(),
|
|
@@ -10731,10 +10740,14 @@ var PromptBuilder = class {
|
|
|
10731
10740
|
// #12
|
|
10732
10741
|
this.getDynamicTechniquesFragment(),
|
|
10733
10742
|
// #7
|
|
10734
|
-
this.getPersistentMemoryFragment()
|
|
10743
|
+
this.getPersistentMemoryFragment()
|
|
10735
10744
|
// #12
|
|
10736
|
-
PROMPT_DEFAULTS.USER_CONTEXT(userInput)
|
|
10737
10745
|
];
|
|
10746
|
+
const strategistDirective = await this.getStrategistFragment();
|
|
10747
|
+
if (strategistDirective) {
|
|
10748
|
+
fragments.push(strategistDirective);
|
|
10749
|
+
}
|
|
10750
|
+
fragments.push(PROMPT_DEFAULTS.USER_CONTEXT(userInput));
|
|
10738
10751
|
return fragments.filter((f) => !!f).join("\n\n");
|
|
10739
10752
|
}
|
|
10740
10753
|
/**
|
|
@@ -10924,11 +10937,213 @@ ${lines.join("\n")}
|
|
|
10924
10937
|
}
|
|
10925
10938
|
return this.state.persistentMemory.toPrompt(services);
|
|
10926
10939
|
}
|
|
10940
|
+
// --- D-CIPHER: Strategist Meta-Prompting ---
|
|
10941
|
+
/**
|
|
10942
|
+
* Generate strategic directive via Strategist LLM.
|
|
10943
|
+
* Called every turn. Returns '' if no strategist is attached or call fails.
|
|
10944
|
+
*/
|
|
10945
|
+
async getStrategistFragment() {
|
|
10946
|
+
if (!this.strategist) return "";
|
|
10947
|
+
return this.strategist.generateDirective();
|
|
10948
|
+
}
|
|
10949
|
+
};
|
|
10950
|
+
|
|
10951
|
+
// src/agents/strategist.ts
|
|
10952
|
+
import { readFileSync as readFileSync6, existsSync as existsSync9 } from "fs";
|
|
10953
|
+
import { join as join11, dirname as dirname6 } from "path";
|
|
10954
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
10955
|
+
|
|
10956
|
+
// src/shared/constants/strategist.ts
|
|
10957
|
+
var STRATEGIST_LIMITS = {
|
|
10958
|
+
/** Maximum characters of state context sent to Strategist LLM.
|
|
10959
|
+
* WHY: Keeps Strategist input focused and affordable (~3-5K tokens).
|
|
10960
|
+
* Full state can be 20K+; Strategist needs summary, not everything. */
|
|
10961
|
+
MAX_INPUT_CHARS: 15e3,
|
|
10962
|
+
/** Maximum characters for the Strategist's response.
|
|
10963
|
+
* WHY: Directives should be terse and actionable (~500-800 tokens).
|
|
10964
|
+
* Longer = more cost, less focus. */
|
|
10965
|
+
MAX_OUTPUT_CHARS: 3e3,
|
|
10966
|
+
/** Maximum lines in the directive output.
|
|
10967
|
+
* WHY: Forces concise, prioritized directives. */
|
|
10968
|
+
MAX_DIRECTIVE_LINES: 40
|
|
10969
|
+
};
|
|
10970
|
+
|
|
10971
|
+
// src/agents/strategist.ts
|
|
10972
|
+
var __dirname5 = dirname6(fileURLToPath5(import.meta.url));
|
|
10973
|
+
var STRATEGIST_PROMPT_PATH = join11(__dirname5, "prompts", "strategist-system.md");
|
|
10974
|
+
var Strategist = class {
|
|
10975
|
+
llm;
|
|
10976
|
+
state;
|
|
10977
|
+
systemPrompt;
|
|
10978
|
+
// Metrics
|
|
10979
|
+
totalTokenCost = 0;
|
|
10980
|
+
totalCalls = 0;
|
|
10981
|
+
lastDirective = null;
|
|
10982
|
+
constructor(llm, state) {
|
|
10983
|
+
this.llm = llm;
|
|
10984
|
+
this.state = state;
|
|
10985
|
+
this.systemPrompt = this.loadSystemPrompt();
|
|
10986
|
+
}
|
|
10987
|
+
/**
|
|
10988
|
+
* Generate a fresh strategic directive for this turn.
|
|
10989
|
+
* Called every iteration by PromptBuilder.
|
|
10990
|
+
*
|
|
10991
|
+
* @returns Formatted directive string for prompt injection, or '' on failure
|
|
10992
|
+
*/
|
|
10993
|
+
async generateDirective() {
|
|
10994
|
+
try {
|
|
10995
|
+
const input = this.buildInput();
|
|
10996
|
+
const directive = await this.callLLM(input);
|
|
10997
|
+
this.lastDirective = directive;
|
|
10998
|
+
this.totalCalls++;
|
|
10999
|
+
debugLog("general", "Strategist directive generated", {
|
|
11000
|
+
tokens: directive.tokenCost,
|
|
11001
|
+
totalCalls: this.totalCalls,
|
|
11002
|
+
contentLength: directive.content.length
|
|
11003
|
+
});
|
|
11004
|
+
return this.formatForPrompt(directive);
|
|
11005
|
+
} catch (err) {
|
|
11006
|
+
debugLog("general", "Strategist failed \u2014 agent will proceed without directive", {
|
|
11007
|
+
error: String(err)
|
|
11008
|
+
});
|
|
11009
|
+
if (this.lastDirective?.content) {
|
|
11010
|
+
return this.formatForPrompt(this.lastDirective, true);
|
|
11011
|
+
}
|
|
11012
|
+
return "";
|
|
11013
|
+
}
|
|
11014
|
+
}
|
|
11015
|
+
// ─── Input Construction ─────────────────────────────────────
|
|
11016
|
+
/**
|
|
11017
|
+
* Build the user message for the Strategist LLM.
|
|
11018
|
+
* Assembles state, memory, attack graph, and timeline into a focused context.
|
|
11019
|
+
*/
|
|
11020
|
+
buildInput() {
|
|
11021
|
+
const sections = [];
|
|
11022
|
+
sections.push("## Engagement State");
|
|
11023
|
+
sections.push(this.state.toPrompt());
|
|
11024
|
+
const timeline = this.state.episodicMemory.toPrompt();
|
|
11025
|
+
if (timeline) {
|
|
11026
|
+
sections.push("");
|
|
11027
|
+
sections.push("## Recent Actions");
|
|
11028
|
+
sections.push(timeline);
|
|
11029
|
+
}
|
|
11030
|
+
const failures = this.state.workingMemory.toPrompt();
|
|
11031
|
+
if (failures) {
|
|
11032
|
+
sections.push("");
|
|
11033
|
+
sections.push("## Failed Attempts (DO NOT REPEAT THESE)");
|
|
11034
|
+
sections.push(failures);
|
|
11035
|
+
}
|
|
11036
|
+
const graph = this.state.attackGraph.toPrompt();
|
|
11037
|
+
if (graph) {
|
|
11038
|
+
sections.push("");
|
|
11039
|
+
sections.push("## Attack Graph");
|
|
11040
|
+
sections.push(graph);
|
|
11041
|
+
}
|
|
11042
|
+
const techniques = this.state.dynamicTechniques.toPrompt();
|
|
11043
|
+
if (techniques) {
|
|
11044
|
+
sections.push("");
|
|
11045
|
+
sections.push("## Learned Techniques");
|
|
11046
|
+
sections.push(techniques);
|
|
11047
|
+
}
|
|
11048
|
+
sections.push("");
|
|
11049
|
+
sections.push("## Time");
|
|
11050
|
+
sections.push(this.state.getTimeStatus());
|
|
11051
|
+
const analysis = this.state.getChallengeAnalysis();
|
|
11052
|
+
if (analysis && analysis.primaryType !== "unknown") {
|
|
11053
|
+
sections.push("");
|
|
11054
|
+
sections.push(`## Challenge Type: ${analysis.primaryType.toUpperCase()} (${(analysis.confidence * 100).toFixed(0)}%)`);
|
|
11055
|
+
sections.push(analysis.strategySuggestion);
|
|
11056
|
+
}
|
|
11057
|
+
let input = sections.join("\n");
|
|
11058
|
+
if (input.length > STRATEGIST_LIMITS.MAX_INPUT_CHARS) {
|
|
11059
|
+
input = input.slice(0, STRATEGIST_LIMITS.MAX_INPUT_CHARS) + "\n\n... [state truncated for Strategist context]";
|
|
11060
|
+
}
|
|
11061
|
+
return input;
|
|
11062
|
+
}
|
|
11063
|
+
// ─── LLM Call ───────────────────────────────────────────────
|
|
11064
|
+
async callLLM(input) {
|
|
11065
|
+
const messages = [{
|
|
11066
|
+
role: "user",
|
|
11067
|
+
content: `Analyze this penetration test situation and write a tactical directive for the attack agent.
|
|
11068
|
+
|
|
11069
|
+
${input}`
|
|
11070
|
+
}];
|
|
11071
|
+
const response = await this.llm.generateResponse(
|
|
11072
|
+
messages,
|
|
11073
|
+
void 0,
|
|
11074
|
+
// No tools — strategy generation only
|
|
11075
|
+
this.systemPrompt
|
|
11076
|
+
);
|
|
11077
|
+
let content = response.content || "";
|
|
11078
|
+
if (content.length > STRATEGIST_LIMITS.MAX_OUTPUT_CHARS) {
|
|
11079
|
+
content = content.slice(0, STRATEGIST_LIMITS.MAX_OUTPUT_CHARS) + "\n... [directive truncated]";
|
|
11080
|
+
}
|
|
11081
|
+
const cost = response.usage ? response.usage.input_tokens + response.usage.output_tokens : 0;
|
|
11082
|
+
this.totalTokenCost += cost;
|
|
11083
|
+
return {
|
|
11084
|
+
content,
|
|
11085
|
+
generatedAt: Date.now(),
|
|
11086
|
+
tokenCost: cost
|
|
11087
|
+
};
|
|
11088
|
+
}
|
|
11089
|
+
// ─── Formatting ─────────────────────────────────────────────
|
|
11090
|
+
/**
|
|
11091
|
+
* Format directive for injection into the attack agent's system prompt.
|
|
11092
|
+
*/
|
|
11093
|
+
formatForPrompt(directive, isStale = false) {
|
|
11094
|
+
if (!directive.content) return "";
|
|
11095
|
+
const age = Math.floor((Date.now() - directive.generatedAt) / 6e4);
|
|
11096
|
+
const staleWarning = isStale ? `
|
|
11097
|
+
NOTE: This directive is from ${age}min ago (Strategist call failed this turn). Verify assumptions are still valid.` : "";
|
|
11098
|
+
return [
|
|
11099
|
+
"<strategic-directive>",
|
|
11100
|
+
"TACTICAL DIRECTIVE (generated by Strategist LLM \u2014 follow these priorities):",
|
|
11101
|
+
"",
|
|
11102
|
+
directive.content,
|
|
11103
|
+
staleWarning,
|
|
11104
|
+
"</strategic-directive>"
|
|
11105
|
+
].filter(Boolean).join("\n");
|
|
11106
|
+
}
|
|
11107
|
+
// ─── System Prompt Loading ──────────────────────────────────
|
|
11108
|
+
loadSystemPrompt() {
|
|
11109
|
+
try {
|
|
11110
|
+
if (existsSync9(STRATEGIST_PROMPT_PATH)) {
|
|
11111
|
+
return readFileSync6(STRATEGIST_PROMPT_PATH, "utf-8");
|
|
11112
|
+
}
|
|
11113
|
+
} catch {
|
|
11114
|
+
}
|
|
11115
|
+
return FALLBACK_SYSTEM_PROMPT;
|
|
11116
|
+
}
|
|
11117
|
+
// ─── Public API ─────────────────────────────────────────────
|
|
11118
|
+
/** Get total token cost of all Strategist calls this session. */
|
|
11119
|
+
getTotalTokenCost() {
|
|
11120
|
+
return this.totalTokenCost;
|
|
11121
|
+
}
|
|
11122
|
+
/** Get number of Strategist calls this session. */
|
|
11123
|
+
getTotalCalls() {
|
|
11124
|
+
return this.totalCalls;
|
|
11125
|
+
}
|
|
11126
|
+
/** Get the most recent directive (for TUI display). */
|
|
11127
|
+
getLastDirective() {
|
|
11128
|
+
return this.lastDirective;
|
|
11129
|
+
}
|
|
11130
|
+
/** Reset strategist state (for /clear command). */
|
|
11131
|
+
reset() {
|
|
11132
|
+
this.lastDirective = null;
|
|
11133
|
+
this.totalTokenCost = 0;
|
|
11134
|
+
this.totalCalls = 0;
|
|
11135
|
+
}
|
|
10927
11136
|
};
|
|
11137
|
+
var FALLBACK_SYSTEM_PROMPT = `You are a penetration testing strategist.
|
|
11138
|
+
Analyze the situation and write a precise tactical directive for the attack agent.
|
|
11139
|
+
Be specific: name exact tools, commands, and parameters.
|
|
11140
|
+
Maximum 30 lines. Prioritize by probability of success.
|
|
11141
|
+
NEVER suggest approaches listed in the failed attempts section.`;
|
|
10928
11142
|
|
|
10929
11143
|
// src/agents/main-agent.ts
|
|
10930
11144
|
var MainAgent = class extends CoreAgent {
|
|
10931
11145
|
promptBuilder;
|
|
11146
|
+
strategist;
|
|
10932
11147
|
approvalGate;
|
|
10933
11148
|
scopeGuard;
|
|
10934
11149
|
userInput = "";
|
|
@@ -10937,6 +11152,8 @@ var MainAgent = class extends CoreAgent {
|
|
|
10937
11152
|
this.approvalGate = approvalGate;
|
|
10938
11153
|
this.scopeGuard = scopeGuard;
|
|
10939
11154
|
this.promptBuilder = new PromptBuilder(state);
|
|
11155
|
+
this.strategist = new Strategist(this.llm, state);
|
|
11156
|
+
this.promptBuilder.setStrategist(this.strategist);
|
|
10940
11157
|
}
|
|
10941
11158
|
/**
|
|
10942
11159
|
* Public entry point for running the agent.
|
|
@@ -10947,7 +11164,8 @@ var MainAgent = class extends CoreAgent {
|
|
|
10947
11164
|
this.emitStart(userInput);
|
|
10948
11165
|
this.initializeTask();
|
|
10949
11166
|
try {
|
|
10950
|
-
const
|
|
11167
|
+
const initialPrompt = await this.getCurrentPrompt();
|
|
11168
|
+
const result2 = await this.run(userInput, initialPrompt);
|
|
10951
11169
|
return result2.output;
|
|
10952
11170
|
} finally {
|
|
10953
11171
|
try {
|
|
@@ -10963,9 +11181,10 @@ var MainAgent = class extends CoreAgent {
|
|
|
10963
11181
|
/**
|
|
10964
11182
|
* Override step to rebuild prompt dynamically each iteration.
|
|
10965
11183
|
* This ensures the agent always sees the latest state, phase, and active processes.
|
|
11184
|
+
* The Strategist LLM generates a fresh tactical directive every turn.
|
|
10966
11185
|
*/
|
|
10967
11186
|
async step(iteration, messages, _unusedPrompt, progress) {
|
|
10968
|
-
const dynamicPrompt = this.getCurrentPrompt();
|
|
11187
|
+
const dynamicPrompt = await this.getCurrentPrompt();
|
|
10969
11188
|
const result2 = await super.step(iteration, messages, dynamicPrompt, progress);
|
|
10970
11189
|
this.emitStateChange();
|
|
10971
11190
|
return result2;
|
|
@@ -10994,7 +11213,7 @@ var MainAgent = class extends CoreAgent {
|
|
|
10994
11213
|
saveCurrentState() {
|
|
10995
11214
|
return saveState(this.state);
|
|
10996
11215
|
}
|
|
10997
|
-
getCurrentPrompt() {
|
|
11216
|
+
async getCurrentPrompt() {
|
|
10998
11217
|
const phase = this.state.getPhase() || PHASES.RECON;
|
|
10999
11218
|
return this.promptBuilder.build(this.userInput, phase);
|
|
11000
11219
|
}
|
|
@@ -11048,6 +11267,7 @@ var MainAgent = class extends CoreAgent {
|
|
|
11048
11267
|
});
|
|
11049
11268
|
this.state.reset();
|
|
11050
11269
|
this.userInput = "";
|
|
11270
|
+
this.strategist.reset();
|
|
11051
11271
|
return clearWorkspace();
|
|
11052
11272
|
}
|
|
11053
11273
|
setScope(allowed, exclusions = []) {
|
|
@@ -11069,6 +11289,10 @@ var MainAgent = class extends CoreAgent {
|
|
|
11069
11289
|
});
|
|
11070
11290
|
this.emitStateChange();
|
|
11071
11291
|
}
|
|
11292
|
+
/** Get the Strategist instance (for TUI metrics display). */
|
|
11293
|
+
getStrategist() {
|
|
11294
|
+
return this.strategist;
|
|
11295
|
+
}
|
|
11072
11296
|
};
|
|
11073
11297
|
|
|
11074
11298
|
// src/agents/factory.ts
|
|
@@ -11164,13 +11388,13 @@ var THEME = {
|
|
|
11164
11388
|
secondary: "#cbd5e1",
|
|
11165
11389
|
// Brighter slate
|
|
11166
11390
|
muted: "#94a3b8",
|
|
11167
|
-
// Lighter blue-gray
|
|
11168
|
-
accent: "#
|
|
11169
|
-
//
|
|
11391
|
+
// Lighter blue-gray
|
|
11392
|
+
accent: "#1d4ed8",
|
|
11393
|
+
// Blue 700 - deep blue
|
|
11170
11394
|
highlight: "#ffffff"
|
|
11171
11395
|
// Pure white
|
|
11172
11396
|
},
|
|
11173
|
-
// Status colors
|
|
11397
|
+
// Status colors (deep blue-focused)
|
|
11174
11398
|
status: {
|
|
11175
11399
|
success: "#10b981",
|
|
11176
11400
|
// Emerald
|
|
@@ -11178,10 +11402,10 @@ var THEME = {
|
|
|
11178
11402
|
// Amber
|
|
11179
11403
|
error: "#ef4444",
|
|
11180
11404
|
// Red
|
|
11181
|
-
info: "#
|
|
11182
|
-
// Blue
|
|
11183
|
-
running: "#
|
|
11184
|
-
// Blue
|
|
11405
|
+
info: "#1d4ed8",
|
|
11406
|
+
// Blue 700
|
|
11407
|
+
running: "#1e40af",
|
|
11408
|
+
// Blue 800 (AI activity)
|
|
11185
11409
|
pending: "#64748b"
|
|
11186
11410
|
// Slate
|
|
11187
11411
|
},
|
|
@@ -11195,29 +11419,29 @@ var THEME = {
|
|
|
11195
11419
|
// Orange
|
|
11196
11420
|
low: "#eab308",
|
|
11197
11421
|
// Yellow
|
|
11198
|
-
info: "#
|
|
11199
|
-
// Blue
|
|
11422
|
+
info: "#1d4ed8"
|
|
11423
|
+
// Blue 700
|
|
11200
11424
|
},
|
|
11201
11425
|
// Border colors
|
|
11202
11426
|
border: {
|
|
11203
11427
|
default: "#1e293b",
|
|
11204
|
-
focus: "#
|
|
11205
|
-
//
|
|
11428
|
+
focus: "#3b82f6",
|
|
11429
|
+
// Blue 500 (UI decorative)
|
|
11206
11430
|
error: "#ef4444",
|
|
11207
11431
|
success: "#22c55e"
|
|
11208
11432
|
},
|
|
11209
|
-
// Phase colors
|
|
11433
|
+
// Phase colors (deep blue-focused)
|
|
11210
11434
|
phase: {
|
|
11211
11435
|
recon: "#94a3b8",
|
|
11212
|
-
enum: "#
|
|
11213
|
-
// Blue
|
|
11436
|
+
enum: "#1d4ed8",
|
|
11437
|
+
// Blue 700 (phase indicator)
|
|
11214
11438
|
vuln: "#f59e0b",
|
|
11215
11439
|
exploit: "#ef4444",
|
|
11216
11440
|
privesc: "#8b5cf6",
|
|
11217
11441
|
persist: "#22c55e",
|
|
11218
11442
|
report: "#64748b"
|
|
11219
11443
|
},
|
|
11220
|
-
// Accent colors
|
|
11444
|
+
// Accent colors (NO cyan/teal - pure blue palette)
|
|
11221
11445
|
accent: {
|
|
11222
11446
|
pink: "#f472b6",
|
|
11223
11447
|
rose: "#fb7185",
|
|
@@ -11225,9 +11449,8 @@ var THEME = {
|
|
|
11225
11449
|
purple: "#a78bfa",
|
|
11226
11450
|
violet: "#8b5cf6",
|
|
11227
11451
|
indigo: "#818cf8",
|
|
11228
|
-
blue: "#
|
|
11229
|
-
|
|
11230
|
-
teal: "#2dd4bf",
|
|
11452
|
+
blue: "#1d4ed8",
|
|
11453
|
+
// Blue 700 - primary accent
|
|
11231
11454
|
emerald: "#34d399",
|
|
11232
11455
|
green: "#4ade80",
|
|
11233
11456
|
lime: "#a3e635",
|
|
@@ -11236,36 +11459,35 @@ var THEME = {
|
|
|
11236
11459
|
orange: "#fb923c",
|
|
11237
11460
|
red: "#f87171"
|
|
11238
11461
|
},
|
|
11239
|
-
// Gradients
|
|
11462
|
+
// Gradients (deep blue-focused)
|
|
11240
11463
|
gradient: {
|
|
11241
11464
|
cyber: [
|
|
11242
|
-
"#
|
|
11243
|
-
//
|
|
11244
|
-
"#
|
|
11245
|
-
"#
|
|
11246
|
-
"#
|
|
11247
|
-
"#
|
|
11248
|
-
"#
|
|
11249
|
-
//
|
|
11250
|
-
"#
|
|
11251
|
-
"#
|
|
11252
|
-
"#
|
|
11253
|
-
|
|
11254
|
-
"#
|
|
11255
|
-
|
|
11256
|
-
// Emerald 400
|
|
11465
|
+
"#3b82f6",
|
|
11466
|
+
// Blue 500
|
|
11467
|
+
"#3584f4",
|
|
11468
|
+
"#2f86f2",
|
|
11469
|
+
"#2988f0",
|
|
11470
|
+
"#238aee",
|
|
11471
|
+
"#1d8cec",
|
|
11472
|
+
// Mid blue
|
|
11473
|
+
"#1d7ad8",
|
|
11474
|
+
"#1d78c6",
|
|
11475
|
+
"#1d76b4",
|
|
11476
|
+
"#1d74a2",
|
|
11477
|
+
"#1e40af"
|
|
11478
|
+
// Blue 800
|
|
11257
11479
|
],
|
|
11258
11480
|
danger: ["#ef4444", "#7f1d1d"],
|
|
11259
11481
|
success: ["#22c55e", "#14532d"],
|
|
11260
11482
|
gold: ["#f59e0b", "#78350f"],
|
|
11261
11483
|
royal: ["#818cf8", "#312e81"]
|
|
11262
11484
|
},
|
|
11263
|
-
// Spinner color (
|
|
11264
|
-
spinner: "#
|
|
11265
|
-
//
|
|
11266
|
-
// Identity color (branded accent)
|
|
11267
|
-
identity: "#
|
|
11268
|
-
// Blue
|
|
11485
|
+
// Spinner color (deep blue — UI feedback)
|
|
11486
|
+
spinner: "#3b82f6",
|
|
11487
|
+
// Blue 500
|
|
11488
|
+
// Identity color (branded accent - deep blue)
|
|
11489
|
+
identity: "#1d4ed8"
|
|
11490
|
+
// Blue 700
|
|
11269
11491
|
};
|
|
11270
11492
|
var ASCII_BANNER = `
|
|
11271
11493
|
____ __ __ _
|
|
@@ -11311,39 +11533,39 @@ var ICONS = {
|
|
|
11311
11533
|
// src/platform/tui/constants/display.ts
|
|
11312
11534
|
var TUI_DISPLAY_LIMITS = {
|
|
11313
11535
|
/** Reasoning buffer size for display */
|
|
11314
|
-
reasoningBuffer:
|
|
11536
|
+
reasoningBuffer: 2e3,
|
|
11315
11537
|
/** Reasoning preview length */
|
|
11316
|
-
reasoningPreview:
|
|
11538
|
+
reasoningPreview: 500,
|
|
11317
11539
|
/** Reasoning history slice for display */
|
|
11318
|
-
reasoningHistorySlice:
|
|
11540
|
+
reasoningHistorySlice: 1e3,
|
|
11319
11541
|
/** Tool input preview length (for command display) */
|
|
11320
|
-
toolInputPreview:
|
|
11542
|
+
toolInputPreview: 200,
|
|
11321
11543
|
/** Tool input truncated length */
|
|
11322
|
-
toolInputTruncated:
|
|
11323
|
-
/** Tool output preview length */
|
|
11324
|
-
toolOutputPreview:
|
|
11544
|
+
toolInputTruncated: 197,
|
|
11545
|
+
/** Tool output preview length - increased to show full output */
|
|
11546
|
+
toolOutputPreview: 2e3,
|
|
11325
11547
|
/** Error message preview length */
|
|
11326
|
-
errorPreview:
|
|
11548
|
+
errorPreview: 500,
|
|
11327
11549
|
/** Status thought preview length */
|
|
11328
|
-
statusThoughtPreview:
|
|
11550
|
+
statusThoughtPreview: 150,
|
|
11329
11551
|
/** Status thought truncated length */
|
|
11330
|
-
statusThoughtTruncated:
|
|
11552
|
+
statusThoughtTruncated: 147,
|
|
11331
11553
|
/** Retry error preview length */
|
|
11332
|
-
retryErrorPreview:
|
|
11554
|
+
retryErrorPreview: 100,
|
|
11333
11555
|
/** Retry error truncated length */
|
|
11334
|
-
retryErrorTruncated:
|
|
11556
|
+
retryErrorTruncated: 97,
|
|
11335
11557
|
/** Timer update interval in ms */
|
|
11336
11558
|
timerInterval: 1e3,
|
|
11337
11559
|
/** Exit delay in ms */
|
|
11338
11560
|
exitDelay: 100,
|
|
11339
11561
|
/** Purpose text max length before truncation */
|
|
11340
|
-
purposeMaxLength:
|
|
11562
|
+
purposeMaxLength: 50,
|
|
11341
11563
|
/** Purpose text truncated length */
|
|
11342
|
-
purposeTruncated:
|
|
11564
|
+
purposeTruncated: 47,
|
|
11343
11565
|
/** Tool detail preview length in flow display */
|
|
11344
|
-
toolDetailPreview:
|
|
11566
|
+
toolDetailPreview: 200,
|
|
11345
11567
|
/** Observe detail preview length in flow display */
|
|
11346
|
-
observeDetailPreview:
|
|
11568
|
+
observeDetailPreview: 150,
|
|
11347
11569
|
/** Max flow nodes to display */
|
|
11348
11570
|
maxFlowNodes: 50,
|
|
11349
11571
|
/** Max stopped processes to show */
|
|
@@ -11358,7 +11580,7 @@ var MESSAGE_STYLES = {
|
|
|
11358
11580
|
error: THEME.status.error,
|
|
11359
11581
|
tool: THEME.status.running,
|
|
11360
11582
|
result: THEME.text.muted,
|
|
11361
|
-
status: THEME.accent.
|
|
11583
|
+
status: THEME.accent.blue
|
|
11362
11584
|
},
|
|
11363
11585
|
prefixes: {
|
|
11364
11586
|
user: "\u276F",
|
|
@@ -11557,10 +11779,10 @@ var useAgentEvents = (agent, eventsRef, state) => {
|
|
|
11557
11779
|
setCurrentTokens(tokenAccumRef.current + stepTokens);
|
|
11558
11780
|
};
|
|
11559
11781
|
const onFlagFound = (e) => {
|
|
11560
|
-
addMessage("system",
|
|
11782
|
+
addMessage("system", `[FLAG] ${e.data.flag} (total: ${e.data.totalFlags})`);
|
|
11561
11783
|
};
|
|
11562
11784
|
const onPhaseChange = (e) => {
|
|
11563
|
-
addMessage("system",
|
|
11785
|
+
addMessage("system", `[Phase] ${e.data.fromPhase} -> ${e.data.toPhase} (${e.data.reason})`);
|
|
11564
11786
|
const s = agent.getState();
|
|
11565
11787
|
setStats({
|
|
11566
11788
|
phase: e.data.toPhase,
|
|
@@ -11705,18 +11927,18 @@ Options: ${request.options.join(", ")}`;
|
|
|
11705
11927
|
}
|
|
11706
11928
|
function getCommandEventIcon(eventType) {
|
|
11707
11929
|
const icons = {
|
|
11708
|
-
[COMMAND_EVENT_TYPES.TOOL_MISSING]: "
|
|
11709
|
-
[COMMAND_EVENT_TYPES.TOOL_INSTALL]: "
|
|
11710
|
-
[COMMAND_EVENT_TYPES.TOOL_INSTALLED]: "
|
|
11711
|
-
[COMMAND_EVENT_TYPES.TOOL_INSTALL_FAILED]: "
|
|
11712
|
-
[COMMAND_EVENT_TYPES.TOOL_RETRY]: "
|
|
11713
|
-
[COMMAND_EVENT_TYPES.COMMAND_START]: "
|
|
11714
|
-
[COMMAND_EVENT_TYPES.COMMAND_SUCCESS]: "
|
|
11715
|
-
[COMMAND_EVENT_TYPES.COMMAND_FAILED]: "
|
|
11716
|
-
[COMMAND_EVENT_TYPES.COMMAND_ERROR]: "
|
|
11717
|
-
[COMMAND_EVENT_TYPES.INPUT_REQUIRED]: "
|
|
11930
|
+
[COMMAND_EVENT_TYPES.TOOL_MISSING]: "[!]",
|
|
11931
|
+
[COMMAND_EVENT_TYPES.TOOL_INSTALL]: "[install]",
|
|
11932
|
+
[COMMAND_EVENT_TYPES.TOOL_INSTALLED]: "[ok]",
|
|
11933
|
+
[COMMAND_EVENT_TYPES.TOOL_INSTALL_FAILED]: "[fail]",
|
|
11934
|
+
[COMMAND_EVENT_TYPES.TOOL_RETRY]: "[retry]",
|
|
11935
|
+
[COMMAND_EVENT_TYPES.COMMAND_START]: "[>]",
|
|
11936
|
+
[COMMAND_EVENT_TYPES.COMMAND_SUCCESS]: "[ok]",
|
|
11937
|
+
[COMMAND_EVENT_TYPES.COMMAND_FAILED]: "[x]",
|
|
11938
|
+
[COMMAND_EVENT_TYPES.COMMAND_ERROR]: "[err]",
|
|
11939
|
+
[COMMAND_EVENT_TYPES.INPUT_REQUIRED]: "[auth]"
|
|
11718
11940
|
};
|
|
11719
|
-
return icons[eventType] || "
|
|
11941
|
+
return icons[eventType] || "[-]";
|
|
11720
11942
|
}
|
|
11721
11943
|
|
|
11722
11944
|
// src/platform/tui/hooks/useAgent.ts
|
|
@@ -11817,6 +12039,7 @@ var useAgent = (shouldAutoApprove, target) => {
|
|
|
11817
12039
|
};
|
|
11818
12040
|
|
|
11819
12041
|
// src/platform/tui/components/MessageList.tsx
|
|
12042
|
+
import { memo } from "react";
|
|
11820
12043
|
import { Box as Box2, Text as Text2, Static } from "ink";
|
|
11821
12044
|
|
|
11822
12045
|
// src/platform/tui/components/inline-status.tsx
|
|
@@ -11834,7 +12057,7 @@ function formatDuration2(ms) {
|
|
|
11834
12057
|
}
|
|
11835
12058
|
function getRoleColor(role) {
|
|
11836
12059
|
const roleColors = {
|
|
11837
|
-
listener: THEME.accent.
|
|
12060
|
+
listener: THEME.accent.blue,
|
|
11838
12061
|
active_shell: THEME.accent.green,
|
|
11839
12062
|
server: THEME.accent.blue,
|
|
11840
12063
|
sniffer: THEME.accent.amber,
|
|
@@ -11979,7 +12202,7 @@ function parseStatusContent(content) {
|
|
|
11979
12202
|
}
|
|
11980
12203
|
return null;
|
|
11981
12204
|
}
|
|
11982
|
-
var MessageList = ({ messages }) => {
|
|
12205
|
+
var MessageList = memo(({ messages }) => {
|
|
11983
12206
|
return /* @__PURE__ */ jsx2(Static, { items: messages, children: (msg) => {
|
|
11984
12207
|
if (msg.type === "status") {
|
|
11985
12208
|
const statusData = parseStatusContent(msg.content);
|
|
@@ -12000,18 +12223,19 @@ var MessageList = ({ messages }) => {
|
|
|
12000
12223
|
msg.content
|
|
12001
12224
|
] }) }, msg.id);
|
|
12002
12225
|
} });
|
|
12003
|
-
};
|
|
12226
|
+
});
|
|
12004
12227
|
|
|
12005
12228
|
// src/platform/tui/components/StatusDisplay.tsx
|
|
12229
|
+
import { memo as memo3 } from "react";
|
|
12006
12230
|
import { Box as Box3, Text as Text4 } from "ink";
|
|
12007
12231
|
|
|
12008
12232
|
// src/platform/tui/components/MusicSpinner.tsx
|
|
12009
|
-
import { useState as useState3, useEffect as useEffect3 } from "react";
|
|
12233
|
+
import { useState as useState3, useEffect as useEffect3, memo as memo2 } from "react";
|
|
12010
12234
|
import { Text as Text3 } from "ink";
|
|
12011
12235
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
12012
12236
|
var FRAMES = ["\u2669", "\u266A", "\u266B", "\u266C", "\u266B", "\u266A"];
|
|
12013
|
-
var INTERVAL =
|
|
12014
|
-
var MusicSpinner = ({ color }) => {
|
|
12237
|
+
var INTERVAL = 600;
|
|
12238
|
+
var MusicSpinner = memo2(({ color }) => {
|
|
12015
12239
|
const [index, setIndex] = useState3(0);
|
|
12016
12240
|
useEffect3(() => {
|
|
12017
12241
|
const timer = setInterval(() => {
|
|
@@ -12020,11 +12244,11 @@ var MusicSpinner = ({ color }) => {
|
|
|
12020
12244
|
return () => clearInterval(timer);
|
|
12021
12245
|
}, []);
|
|
12022
12246
|
return /* @__PURE__ */ jsx3(Text3, { color, children: FRAMES[index] });
|
|
12023
|
-
};
|
|
12247
|
+
});
|
|
12024
12248
|
|
|
12025
12249
|
// src/platform/tui/components/StatusDisplay.tsx
|
|
12026
12250
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
12027
|
-
var StatusDisplay = ({
|
|
12251
|
+
var StatusDisplay = memo3(({
|
|
12028
12252
|
retryState,
|
|
12029
12253
|
isProcessing,
|
|
12030
12254
|
currentStatus,
|
|
@@ -12046,7 +12270,7 @@ var StatusDisplay = ({
|
|
|
12046
12270
|
" \xB7 ",
|
|
12047
12271
|
truncateError(retryState.error)
|
|
12048
12272
|
] }),
|
|
12049
|
-
/* @__PURE__ */ jsxs3(Text4, { color: THEME.accent.
|
|
12273
|
+
/* @__PURE__ */ jsxs3(Text4, { color: THEME.accent.blue, bold: true, children: [
|
|
12050
12274
|
" \xB7 ",
|
|
12051
12275
|
retryState.countdown,
|
|
12052
12276
|
"s"
|
|
@@ -12064,15 +12288,15 @@ var StatusDisplay = ({
|
|
|
12064
12288
|
] })
|
|
12065
12289
|
] })
|
|
12066
12290
|
] });
|
|
12067
|
-
};
|
|
12291
|
+
});
|
|
12068
12292
|
|
|
12069
12293
|
// src/platform/tui/components/ChatInput.tsx
|
|
12070
|
-
import { useMemo, useCallback as useCallback3, useRef as useRef3 } from "react";
|
|
12294
|
+
import { useMemo, useCallback as useCallback3, useRef as useRef3, memo as memo4 } from "react";
|
|
12071
12295
|
import { Box as Box4, Text as Text5, useInput } from "ink";
|
|
12072
12296
|
import TextInput from "ink-text-input";
|
|
12073
12297
|
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
12074
12298
|
var MAX_SUGGESTIONS = 6;
|
|
12075
|
-
var ChatInput = ({
|
|
12299
|
+
var ChatInput = memo4(({
|
|
12076
12300
|
value,
|
|
12077
12301
|
onChange,
|
|
12078
12302
|
onSubmit,
|
|
@@ -12133,7 +12357,7 @@ var ChatInput = ({
|
|
|
12133
12357
|
" \u2014 ",
|
|
12134
12358
|
cmd.description
|
|
12135
12359
|
] }),
|
|
12136
|
-
isFirst && /* @__PURE__ */ jsx5(Text5, { color: THEME.accent.
|
|
12360
|
+
isFirst && /* @__PURE__ */ jsx5(Text5, { color: THEME.accent.blue, children: " [Tab]" })
|
|
12137
12361
|
] }, cmd.name);
|
|
12138
12362
|
})
|
|
12139
12363
|
}
|
|
@@ -12145,7 +12369,7 @@ var ChatInput = ({
|
|
|
12145
12369
|
borderColor: inputRequest.isActive ? THEME.status.warning : THEME.border.default,
|
|
12146
12370
|
paddingX: 1,
|
|
12147
12371
|
children: inputRequest.isActive ? /* @__PURE__ */ jsxs4(Box4, { children: [
|
|
12148
|
-
/* @__PURE__ */ jsx5(Text5, { color: THEME.status.warning, children: "
|
|
12372
|
+
/* @__PURE__ */ jsx5(Text5, { color: THEME.status.warning, children: "[auth]" }),
|
|
12149
12373
|
/* @__PURE__ */ jsxs4(Text5, { color: THEME.text.muted, children: [
|
|
12150
12374
|
" ",
|
|
12151
12375
|
inputRequest.prompt
|
|
@@ -12176,9 +12400,10 @@ var ChatInput = ({
|
|
|
12176
12400
|
}
|
|
12177
12401
|
)
|
|
12178
12402
|
] });
|
|
12179
|
-
};
|
|
12403
|
+
});
|
|
12180
12404
|
|
|
12181
12405
|
// src/platform/tui/components/footer.tsx
|
|
12406
|
+
import { memo as memo5 } from "react";
|
|
12182
12407
|
import { Box as Box5, Text as Text6 } from "ink";
|
|
12183
12408
|
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
12184
12409
|
var formatElapsed = (totalSeconds) => {
|
|
@@ -12191,7 +12416,7 @@ var formatElapsed = (totalSeconds) => {
|
|
|
12191
12416
|
}
|
|
12192
12417
|
return `${minutes}:${pad(seconds)}`;
|
|
12193
12418
|
};
|
|
12194
|
-
var Footer = ({ phase, targets, findings, todo, elapsedTime, isProcessing }) => {
|
|
12419
|
+
var Footer = memo5(({ phase, targets, findings, todo, elapsedTime, isProcessing }) => {
|
|
12195
12420
|
return /* @__PURE__ */ jsxs5(
|
|
12196
12421
|
Box5,
|
|
12197
12422
|
{
|
|
@@ -12202,7 +12427,7 @@ var Footer = ({ phase, targets, findings, todo, elapsedTime, isProcessing }) =>
|
|
|
12202
12427
|
/* @__PURE__ */ jsxs5(Box5, { gap: 2, children: [
|
|
12203
12428
|
/* @__PURE__ */ jsxs5(Text6, { color: THEME.text.muted, children: [
|
|
12204
12429
|
"Phase: ",
|
|
12205
|
-
/* @__PURE__ */ jsx6(Text6, { color: THEME.accent.
|
|
12430
|
+
/* @__PURE__ */ jsx6(Text6, { color: THEME.accent.blue, children: phase })
|
|
12206
12431
|
] }),
|
|
12207
12432
|
/* @__PURE__ */ jsxs5(Text6, { color: THEME.text.muted, children: [
|
|
12208
12433
|
"Targets: ",
|
|
@@ -12224,7 +12449,7 @@ var Footer = ({ phase, targets, findings, todo, elapsedTime, isProcessing }) =>
|
|
|
12224
12449
|
]
|
|
12225
12450
|
}
|
|
12226
12451
|
);
|
|
12227
|
-
};
|
|
12452
|
+
});
|
|
12228
12453
|
var footer_default = Footer;
|
|
12229
12454
|
|
|
12230
12455
|
// src/platform/tui/app.tsx
|
|
@@ -12281,9 +12506,9 @@ var App = ({ autoApprove = false, target }) => {
|
|
|
12281
12506
|
setMessages([]);
|
|
12282
12507
|
const result2 = await agent.resetSession();
|
|
12283
12508
|
if (result2.cleared.length > 0) {
|
|
12284
|
-
addMessage("system",
|
|
12509
|
+
addMessage("system", `[reset] Session cleared: ${result2.cleared.join(", ")}`);
|
|
12285
12510
|
} else {
|
|
12286
|
-
addMessage("system", "
|
|
12511
|
+
addMessage("system", "[reset] Session clean");
|
|
12287
12512
|
}
|
|
12288
12513
|
if (result2.errors.length > 0) {
|
|
12289
12514
|
addMessage("error", `Cleanup errors: ${result2.errors.join("; ")}`);
|
|
@@ -12310,7 +12535,7 @@ var App = ({ autoApprove = false, target }) => {
|
|
|
12310
12535
|
if (!autoApproveModeRef.current) {
|
|
12311
12536
|
setAutoApproveMode(true);
|
|
12312
12537
|
agent.setAutoApprove(true);
|
|
12313
|
-
addMessage("system", "
|
|
12538
|
+
addMessage("system", "[auto] Autonomous mode enabled");
|
|
12314
12539
|
}
|
|
12315
12540
|
addMessage("system", "Starting penetration test...");
|
|
12316
12541
|
const targets = Array.from(agent.getState().getTargets().keys());
|
|
@@ -12348,7 +12573,7 @@ ${procData.stdout || "(no output)"}
|
|
|
12348
12573
|
break;
|
|
12349
12574
|
case UI_COMMANDS.CTF:
|
|
12350
12575
|
const ctfEnabled = agent.toggleCtfMode();
|
|
12351
|
-
addMessage("system", ctfEnabled ? "
|
|
12576
|
+
addMessage("system", ctfEnabled ? "[CTF] Mode ON - flag detection active" : "[CTF] Mode OFF - standard pentest");
|
|
12352
12577
|
break;
|
|
12353
12578
|
case UI_COMMANDS.GRAPH:
|
|
12354
12579
|
case UI_COMMANDS.GRAPH_SHORT:
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
You are a penetration testing STRATEGIST. Your sole purpose is to analyze the current engagement state and write a precise tactical directive for the attack agent.
|
|
2
|
+
|
|
3
|
+
## YOUR ROLE
|
|
4
|
+
You do NOT execute attacks. You PLAN them. The attack agent will receive your directive as instructions to follow.
|
|
5
|
+
|
|
6
|
+
## OUTPUT FORMAT
|
|
7
|
+
Write a DIRECTIVE with numbered priorities. Be maximally specific:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
PRIORITY 1 [IMPACT]: Brief title
|
|
11
|
+
→ Exact command or tool invocation with all parameters
|
|
12
|
+
→ Success criteria: what confirms it worked
|
|
13
|
+
→ Fallback: what to try if this fails
|
|
14
|
+
|
|
15
|
+
PRIORITY 2 [IMPACT]: Brief title
|
|
16
|
+
→ ...
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## RULES
|
|
20
|
+
|
|
21
|
+
1. **BE SPECIFIC**: "Try SQL injection" is UNACCEPTABLE. "Run: sqlmap -u http://TARGET/login.php --forms --batch --level=5 --risk=3 --tamper=space2comment" is GOOD.
|
|
22
|
+
|
|
23
|
+
2. **REFERENCE ACTUAL STATE**: Only suggest actions based on DISCOVERED data. Never hallucinate services or ports that aren't in the state summary. If nothing is discovered yet, direct initial reconnaissance.
|
|
24
|
+
|
|
25
|
+
3. **LEARN FROM FAILURES**: If working memory shows failed attempts, NEVER suggest the same approach. Propose a fundamentally different attack vector.
|
|
26
|
+
|
|
27
|
+
4. **CHAIN ATTACKS**: If credentials were found, specify EXACTLY which services to spray them against. If access was gained, specify EXACTLY what post-exploitation to run.
|
|
28
|
+
|
|
29
|
+
5. **PRIORITIZE BY PROBABILITY**: Order by likelihood of success × impact. Quick wins first.
|
|
30
|
+
|
|
31
|
+
6. **BE TERSE**: Maximum 30 lines. No preamble, no explanations of what pentesting is. Pure directives.
|
|
32
|
+
|
|
33
|
+
7. **INCLUDE DEAD-ENDS**: Explicitly list approaches that have been exhausted so the agent skips them.
|
|
34
|
+
|
|
35
|
+
8. **CONSIDER THE PHASE**: Adapt your strategy to the current engagement phase (recon → vuln analysis → exploit → post-exploit → lateral).
|
|
36
|
+
|
|
37
|
+
9. **TIME AWARENESS**: If time is limited, focus on highest-probability paths only. If time is abundant, suggest thorough enumeration.
|
|
38
|
+
|
|
39
|
+
10. **PIVOT POINTS**: When access to a new host is gained, prioritize it as a pivot — what can be reached FROM this new position?
|