fix(repl/cli): /target re-derives scope; wildcard target tests subdomains; version banners

Two reported bugs:
1) A scope left over from a previous session persisted in the project session and
   kept denying every new target (DENY_TARGET_OUTSIDE_GRANT ... scope *.example.com
   even after /target zoom.us). With no verified capability, /target now re-derives
   the authorized scope from the new target (preserving excludes + guardrails), so
   the target you pick is the target you test — same model as `neurosploit run <url>`.
2) A wildcard target (`*.zoom.us`) now authorizes the apex AND all subdomains and
   seeds recon with the apex (a literal `*.zoom.us` has no DNS record to probe), so
   subdomain enumeration happens inside the wildcard scope. Applied in both the REPL
   /target and the one-shot `run` path.

Also: the run banner and clap about showed v4.1.0 — now use CARGO_PKG_VERSION / 4.2.1.
421 tests passing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
CyberSecurityUPandClaude Opus 4.8 committed 2026-10-03 01:16:25 -03:00
1 parent 9076d30c59
commit 8a3cb42c1f
2 files changed
+60 -7

No files matched your search

+16 -4
View File
@@ -1,4 +1,4 @@
//! NeuroSploit v4.1.0 — interactive harness + CLI (`run` / `whitebox` / `agents` / `models`).
//! NeuroSploit — interactive harness + CLI (`run` / `whitebox` / `agents` / `models`).
mod rectify;
mod repl;
@@ -13,8 +13,8 @@ use std::path::{Path, PathBuf};
#[command(
name = "neurosploit",
version,
about = "NeuroSploit v4.1.0 — multi-model autonomous pentest harness",
long_about = "NeuroSploit v4.1.0 — a Rust multi-model harness that drives a pool of LLMs \
about = "NeuroSploit v4.2.1 — multi-model autonomous pentest harness",
long_about = "NeuroSploit v4.2.1 — a Rust multi-model harness that drives a pool of LLMs \
(API key or local subscription: Claude/Codex/Gemini/Grok/OpenCode/Hermes) to autonomously test a target. \
After recon it INTELLIGENTLY selects only the agents matching the discovered surface, runs \
them in parallel, then validates every finding by cross-model voting before reporting.\n\n\
@@ -846,6 +846,18 @@ async fn main() -> anyhow::Result<()> {
}
Cmd::Run { url, models, max_agents, vote_n, chain_depth, recon, quick, offline, subscription, mcp, creds, focus, objective, out_of_scope, in_scope, scope_file, environment, policy, budget, token_limit, deep_test_limit, coverage_first, depth_first, sample_per_route, revalidate_poc, compliance, jira, only, verbose } => {
let url = if url.starts_with("http") { url } else { format!("https://{url}") };
// A wildcard target (`*.zoom.us`) is domain-wide: seed recon with the
// apex (a literal `*.zoom.us` has no DNS record to probe) and widen
// the grant to every subdomain so enumeration stays in scope.
let mut in_scope = in_scope;
let url = {
let h = harness::scope::host_of(&url);
if let Some(apex) = h.strip_prefix("*.") {
in_scope.push(format!("*.{apex}"));
if recon < 3 { /* leave as set; recon arg is explicit here */ }
format!("https://{apex}")
} else { url }
};
let mut cfg = RunConfig::new(&url);
cfg.max_agents = max_agents;
cfg.vote_n = vote_n;
@@ -1266,7 +1278,7 @@ pub(crate) fn spawn_engagement(base: &Path, mut cfg: RunConfig, mcp: bool, mode:
println!(" │ ua : {ua}");
write_status(&workdir, "running", &format!("\"target\":{:?}", cfg.target));
println!(" ┌─ NeuroSploit v4.1.0 · by Joas A Santos & Red Team Leaders");
println!(" ┌─ NeuroSploit v{} · by Joas A Santos & Red Team Leaders", env!("CARGO_PKG_VERSION"));
println!(" │ run id : {run_id}");
println!(" │ target : {}", cfg.target);
println!(" │ models : {}", cfg.models.join(", "));
+44 -3
View File
@@ -697,9 +697,50 @@ pub async fn repl(base: &Path, auth: SessionAuth) -> anyhow::Result<()> {
let ts: Vec<String> = arg.split(',').map(|x| x.trim()).filter(|x| !x.is_empty())
.map(|x| crate::rectify::rectify_url(x).unwrap_or_else(|| x.to_string()))
.collect();
s.target = Some(ts.join(","));
if ts.len() > 1 { println!(" targets ({}): {}", ts.len(), ts.join(", ")); println!(" \x1b[2m/run tests them sequentially, one report each\x1b[0m"); }
else { println!(" target: {}", ts.first().cloned().unwrap_or_default()); }
// A wildcard target (`*.zoom.us`) means "the whole domain":
// authorize the apex AND every subdomain, and seed recon with
// the apex (a literal `*.zoom.us` has no DNS record to probe),
// so subdomain enumeration happens inside the wildcard scope.
let mut wildcard_domain: Option<String> = None;
let seeds: Vec<String> = ts.iter().map(|t| {
let h = harness::scope::host_of(t);
if let Some(apex) = h.strip_prefix("*.") {
wildcard_domain = Some(apex.to_string());
format!("https://{apex}")
} else { t.clone() }
}).collect();
s.target = Some(seeds.join(","));
// Re-derive the authorized scope from the NEW target unless a
// verified capability sets the ceiling. Without this, a scope
// left over from a previous session (persisted in the project
// session) keeps denying every new target — the operator sets
// /target zoom.us but the grant still says *.example.com. With
// no capability, the target the operator picks IS the grant
// (same model as `neurosploit run <url>`); explicit excludes
// and guardrails are preserved.
if s.capability.is_none() {
let keep_exclude = s.policy.exclude.clone();
let keep_soft = s.policy.soft.clone();
let mut np = harness::scope::ScopePolicy::for_target(&seeds[0]);
for extra in seeds.iter().skip(1) { np.allow(&harness::scope::host_of(extra)); }
// Each wildcard entry widens the grant to all its subdomains.
for t in &ts {
let h = harness::scope::host_of(t);
if h.starts_with("*.") { np.allow(&h); }
}
np.exclude = keep_exclude;
np.soft = keep_soft;
s.policy = np;
}
if ts.len() > 1 { println!(" targets ({}): {}", ts.len(), seeds.join(", ")); println!(" \x1b[2m/run tests them sequentially, one report each\x1b[0m"); }
else { println!(" target: {}", seeds.first().cloned().unwrap_or_default()); }
if let Some(d) = &wildcard_domain {
println!(" \x1b[2mscope: *.{d} — apex + all subdomains authorized; recon will enumerate subdomains\x1b[0m");
// Nudge recon toward active subdomain discovery for a domain-wide engagement.
if s.recon_intensity < 3 { s.recon_intensity = 3; }
} else if s.capability.is_none() {
println!(" \x1b[2mscope: authorized against this target (add more with /inscope, exclude with /scope-out)\x1b[0m");
}
}
}
"/timeout" | "/idle" => {