mirror of
https://github.com/CyberSecurityUP/NeuroSploit.git
synced 2026-09-30 13:09:36 +02:00
feat(scope): --scope-file YAML loader + web Scoping/Guardrails UI
Hard scoping was already enforced in code (every request passes
ScopePolicy::check_request; exclude beats allowlist; capability token caps
it; out-of-scope findings withheld + audited). What was missing was a way to
author that boundary from a file or the web form instead of only CLI flags.
- scope.rs: ScopePolicy::from_yaml / from_file — a dependency-free parser for
the friendly string format (app.example.com, *.wildcard, CIDR, url-prefix),
the same strings Pattern::parse already takes, NOT the raw serde {kind,value}
shape. Strict in one direction: an unreadable file errors, an empty hard list
authorizes nothing (a safe failure, but the operator's choice, not a typo).
- CLI: --scope-file <yaml>. Loaded before authorization so --in-scope adds to
it and the capability grant still caps it.
- Web: a full Scoping & Guardrails section in the Authorization tab — hard
scope, exclusions, observe-only, destructive-method + account-creation
toggles, max accounts, rate limit, forbidden payloads, notes. The server
materializes a scope YAML and passes --scope-file; notes stay labelled
"guidance, NOT enforced" so prose is never mistaken for a control.
- examples/scope.example.yaml documents the format.
End-to-end verified: web form -> YAML -> Rust loader -> enforced boundary.
332 tests (+4).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
f1fb6b8bc7
commit
8894649ccb
8 files changed
+413
-3
No files matched your search
@@ -123,6 +123,11 @@ enum Cmd {
|
||||
/// Without this the engagement is authorized against the target and nothing else.
|
||||
#[arg(long = "in-scope")]
|
||||
in_scope: Vec<String>,
|
||||
/// Load the hard scope + guardrails from a YAML file (see
|
||||
/// examples/scope.example.yaml). Its `hard` list is the boundary;
|
||||
/// --in-scope adds to it and a capability token still caps it.
|
||||
#[arg(long = "scope-file")]
|
||||
scope_file: Option<String>,
|
||||
/// Environment, which scales every risk score: lab · development ·
|
||||
/// staging · production · ot-production (aliases: ics, scada).
|
||||
#[arg(long = "environment", default_value = "production")]
|
||||
@@ -577,7 +582,7 @@ async fn main() -> anyhow::Result<()> {
|
||||
Cmd::Internal { graph, scaffold, from, expand, mermaid, save } => {
|
||||
handle_internal(graph.as_deref(), scaffold.as_deref(), &from, expand, mermaid, save.as_deref())?
|
||||
}
|
||||
Cmd::Run { url, models, max_agents, vote_n, chain_depth, recon, offline, subscription, mcp, creds, focus, objective, out_of_scope, in_scope, environment, policy, budget, token_limit, deep_test_limit, coverage_first, depth_first, sample_per_route, revalidate_poc, compliance, jira, only, verbose } => {
|
||||
Cmd::Run { url, models, max_agents, vote_n, chain_depth, recon, 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}") };
|
||||
let mut cfg = RunConfig::new(&url);
|
||||
cfg.max_agents = max_agents;
|
||||
@@ -591,6 +596,16 @@ async fn main() -> anyhow::Result<()> {
|
||||
cfg.objective = objective;
|
||||
cfg.out_of_scope = out_of_scope;
|
||||
cfg.pinned = parse_only(&only);
|
||||
if let Some(path) = scope_file.as_deref() {
|
||||
let sp = harness::scope::ScopePolicy::from_file(std::path::Path::new(path))
|
||||
.map_err(|e| anyhow::anyhow!("scope-file {path}: {e}"))?;
|
||||
if sp.hard.is_empty() {
|
||||
println!(" \x1b[33m⚠ {path} sets no hard scope — nothing would be authorized; ignoring it\x1b[0m");
|
||||
} else {
|
||||
println!(" \x1b[2mscope-file: {} host rule(s), {} exclusion(s), rate {}rpm\x1b[0m", sp.hard.len(), sp.exclude.len(), sp.soft.max_requests_per_minute);
|
||||
cfg.scope = sp;
|
||||
}
|
||||
}
|
||||
apply_authorization(&mut cfg, &in_scope, cli.capability_token.clone(), &environment, &policy)?;
|
||||
apply_budget(&mut cfg, budget.as_deref(), token_limit, deep_test_limit, coverage_first, depth_first, sample_per_route)?;
|
||||
apply_network(&mut cfg, &cli)?;
|
||||
|
||||
Reference in new issue
Block a user