From 1f8ccb6f9e561a590d91245234ce477f98c373fc Mon Sep 17 00:00:00 2001 From: CyberSecurityUP Date: Sat, 8 Aug 2026 10:10:43 -0300 Subject: [PATCH] =?UTF-8?q?fix(3.6.8):=20recon=20time=20budget=20=E2=80=94?= =?UTF-8?q?=205min=20cap=20prevents=20recon=20from=20eating=20entire=20run?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add RECON_TOTAL_BUDGET_SECS (300s) total wall-clock cap across all rounds - Per-round budget directive in prompt: 30-50 commands max, stop early if enough intel - Elapsed time check between rounds: skip remaining if budget exhausted - Remaining time communicated to follow-up rounds for self-pacing - RELEASE.md updated with recon budget section Previously: subscription CLI recon ran 150+ commands over 15 min, exploitation never started. Now: recon caps at 5 min total, then proceeds to agent exploitation. Co-Authored-By: Claude Opus 4.6 --- RELEASE.md | 15 ++++++++- neurosploit-rs/crates/harness/src/pipeline.rs | 33 +++++++++++++++++-- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/RELEASE.md b/RELEASE.md index 477cb12..1a069a2 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -5,7 +5,20 @@ **License:** MIT **Credits:** Joas A Santos & Red Team Leaders -## v3.6.8 — Auth resilience, circuit breaker, Ollama error handling, empty-evidence validation +## v3.6.8 — Auth resilience, circuit breaker, recon budget, Ollama error handling, empty-evidence validation + +### Recon Time Budget (NEW) + +- **5-minute total recon budget.** Recon phase is now time-boxed to 300 seconds + across ALL rounds. Previously, a single recon round could run 150+ commands + over 15 minutes via subscription CLI, leaving no time for exploitation. +- **Per-round budget directive.** Each recon round receives a prompt instruction + with its share of the time budget (e.g. "~100 seconds for this round") and a + command count guideline (30-50 commands max). The model is instructed to + prioritise high-signal actions and stop early when enough intel is gathered. +- **Elapsed time check between rounds.** Before starting each follow-up round, + the pipeline checks elapsed time. If the budget is exhausted, recon stops + immediately and proceeds to exploitation with the intelligence gathered so far. ### Auth Resilience & Circuit Breaker (NEW) diff --git a/neurosploit-rs/crates/harness/src/pipeline.rs b/neurosploit-rs/crates/harness/src/pipeline.rs index 431b49d..c5621bb 100644 --- a/neurosploit-rs/crates/harness/src/pipeline.rs +++ b/neurosploit-rs/crates/harness/src/pipeline.rs @@ -1888,6 +1888,11 @@ fn recon_intensity_directive(level: usize) -> String { (8) TLS/headers/cookies. Report counts (how many subdomains/urls/params/endpoints you actually found).\n\n") } +/// Max wall-clock seconds for the ENTIRE recon phase (all rounds combined). +/// This prevents recon from eating the whole run — exploitation must start. +/// Per-round cap = total / (rounds + 1) so later rounds get equal time. +const RECON_TOTAL_BUDGET_SECS: u64 = 300; // 5 minutes total + /// Intense, multi-round recon: an initial deep pass, then follow-up rounds that /// EXPAND the surface (chase discovered subdomains/endpoints/params, install /// tools, dig where the previous round found signal). Returns the merged recon @@ -1899,10 +1904,23 @@ async fn deep_recon(cfg: &RunConfig, pool: &ModelPool, probe_facts: &str, tx: &S let intensity_dir = recon_intensity_directive(intensity); let dir = operator_directives(cfg); let mut accum = format!("OBSERVED HTTP PROBE:\n{probe_facts}"); + let recon_start = std::time::Instant::now(); + let total_rounds = 1 + extra_rounds; + + // Time-budget directive: subscription CLIs run commands autonomously, so they + // need an explicit cap to avoid running 150+ commands in a single round. + let budget_dir = format!( + "TIME BUDGET: you have ~{budget_secs} seconds for THIS recon round. Be EFFICIENT: \ + prioritise high-signal actions (JS analysis, API mapping, SQLi/auth probes) over \ + exhaustive crawling. AIM for 30-50 commands max per round — enough to map the surface, \ + not so many that exploitation never starts. STOP EARLY if you have enough intel to \ + select agents. When done, EMIT YOUR RESULTS IMMEDIATELY — do not start another pass.\n\n", + budget_secs = RECON_TOTAL_BUDGET_SECS / total_rounds as u64, + ); // Initial deep pass. - let user = format!("{dir}{intensity_dir}{doctrine}OBSERVED HTTP PROBE (build on these, verify, go deeper):\n{probe_facts}\n\nTarget: {}", cfg.target); - let _ = tx.send(format!("recon: intensity {} — actively enumerating (installing tools as needed)…", intensity)).await; + let user = format!("{dir}{budget_dir}{intensity_dir}{doctrine}OBSERVED HTTP PROBE (build on these, verify, go deeper):\n{probe_facts}\n\nTarget: {}", cfg.target); + let _ = tx.send(format!("recon: intensity {} — actively enumerating (budget {}s total, {} round(s))…", intensity, RECON_TOTAL_BUDGET_SECS, total_rounds)).await; match pool.complete_routed(Task::Recon, "recon", RECON_SYS, &user).await { Ok((m, t)) => { let _ = tx.send(format!("recon round 1 complete via {}", m.label())).await; accum.push_str(&format!("\n\nMODEL RECON (round 1):\n{t}")); } Err(e) => { @@ -1920,10 +1938,19 @@ async fn deep_recon(cfg: &RunConfig, pool: &ModelPool, probe_facts: &str, tx: &S // Follow-up expansion rounds — each digs further using what's known so far. for r in 0..extra_rounds { if pool.stop_exploiting() { break; } + // Time budget check: if recon has already consumed the total budget, stop + // and proceed to exploitation with whatever intelligence we gathered. + let elapsed = recon_start.elapsed().as_secs(); + if elapsed >= RECON_TOTAL_BUDGET_SECS { + let _ = tx.send(format!("recon: time budget exhausted ({elapsed}s/{RECON_TOTAL_BUDGET_SECS}s) — proceeding to exploitation with current intel")).await; + break; + } + let remaining = RECON_TOTAL_BUDGET_SECS - elapsed; let round = r + 2; let known: String = accum.chars().rev().take(3000).collect::().chars().rev().collect(); let follow = format!( - "{dir}{intensity_dir}{doctrine}CONTINUE the recon — this is round {round}. Here is what recon has found so far:\n{known}\n\n\ + "{dir}TIME BUDGET: you have ~{remaining} seconds remaining for recon. Be CONCISE — focus only on the highest-value leads.\n\n\ + {intensity_dir}{doctrine}CONTINUE the recon — this is round {round}. Here is what recon has found so far:\n{known}\n\n\ Now EXPAND: pick the most promising leads and go deeper — resolve & probe any NEW subdomains/hosts, crawl \ and harvest URLs for endpoints not yet mapped, run content/parameter discovery where you saw interesting \ paths, fingerprint exact versions of anything unclear, and enumerate the API/GraphQL further. Install any \