feat: engagement objective + out-of-scope context for prompts (#34)

Add two operator inputs that give agents more test context, both
funneled through operator_directives() so they reach every recon/
exploit prompt (web, host, ai, skills):

- objective: WHY the test runs and WHAT counts as impact — rendered
  as high-priority ENGAGEMENT OBJECTIVE context.
- out_of_scope: hosts/paths/techniques to exclude — rendered as a
  HARD CONSTRAINT the agents must skip and never report against.

REPL: /objective and /scope-out commands (accumulating), optional
onboarding prompts, /show + /help + Tab-complete, session.json
persistence (serde default for back-compat).
CLI: neurosploit run --objective --out-of-scope.

Version unchanged (3.6.5).


Claude-Session: https://claude.ai/code/session_018BGLy4j5qsqqid6CoovowC

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Joas A Santos
2026-07-31 15:26:17 -03:00
committed by GitHub
co-authored by Claude Opus 4.8
parent f3da46886f
commit e267afb7b6
4 changed files with 87 additions and 2 deletions
+10 -1
View File
@@ -67,6 +67,13 @@ enum Cmd {
/// Free-text focus, e.g. "injection and broken access control".
#[arg(long)]
focus: Option<String>,
/// Engagement objective / context: WHY the test runs and WHAT matters.
#[arg(long)]
objective: Option<String>,
/// Out-of-scope exclusions (hard constraint): hosts/paths/techniques the
/// agents must not touch. Repeatable or comma/semicolon-separated.
#[arg(long = "out-of-scope")]
out_of_scope: Option<String>,
/// Open a Jira card per finding (needs the jira integration enabled).
#[arg(long)]
jira: bool,
@@ -367,7 +374,7 @@ async fn main() -> anyhow::Result<()> {
}
}
}
Cmd::Run { url, models, max_agents, vote_n, chain_depth, recon, offline, subscription, mcp, creds, focus, jira, verbose } => {
Cmd::Run { url, models, max_agents, vote_n, chain_depth, recon, offline, subscription, mcp, creds, focus, objective, out_of_scope, jira, verbose } => {
let url = if url.starts_with("http") { url } else { format!("https://{url}") };
let mut cfg = RunConfig::new(&url);
cfg.max_agents = max_agents;
@@ -378,6 +385,8 @@ async fn main() -> anyhow::Result<()> {
cfg.subscription = subscription;
cfg.verbose = verbose;
cfg.instructions = focus;
cfg.objective = objective;
cfg.out_of_scope = out_of_scope;
if !models.is_empty() {
cfg.models = models;
}