v4.3.0: web console parity + report redaction + per-finding wire evidence & re-test

Harness / CLI
- redact: credentials become $SECRET_n in every human-facing report
  (md/html/json/sarif/typ, findings.md); findings.json & vault keep raw values.
- poc: `--only <id> --json` re-tests a single finding (powers the web Re-test).
- version bump 4.2.4 → 4.3.0 (Cargo, CLI banner, web).

Web console
- Attack graph replaces "Generative Attack Path Chaining": one tab, findings
  ordered by kill-chain stage, click a finding to open it. Mounted in detail + live.
- Finding modal: Wire evidence — the real request/response pairs behind a finding
  (baseline/attack, identity pair, matrix probes, oracle) with wire provenance,
  the wire-check summary, and recorded flows on the same endpoint.
- Per-finding Re-test with dated history (reproduced/changed/gone/unverifiable).
- Transcript viewer in the Traces tab (navigable blocks; search spans all agents).
- Regression vs the previous run of the same target: new / recurring badges and a
  "fixed since" banner.
- Chains tab: readable formatting (node refs as chips, relations as labels).
- Custom lead: describe-it (Claude writes it) OR paste your own agent/system
  prompt (verbatim); remove a custom lead from the board.
- GDPR added to compliance mapping; LLM API keys tab clarified; Reasoning-budget
  and Authorization layouts fixed; NeuroSploit logo added.

Docs / config
- README rewritten as a concise landing page; TUTORIAL.md updated to v4.3.0 with
  new web/graph/Neo4j/wire sections and first-time configuration.
- .env.example: v4.3.0, Z.ai/Moonshot keys, Neo4j + graph-salt + capability env.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
CyberSecurityUPandClaude Opus 4.8 committed 2026-10-14 19:42:16 -03:00
1 parent 79685cee49
commit e9da74a981
13 files changed
+991 -1036

No files matched your search

+36 -6
View File
@@ -13,8 +13,8 @@ use std::path::{Path, PathBuf};
#[command(
name = "neurosploit",
version,
about = "NeuroSploit v4.2.4 — multi-model autonomous pentest harness",
long_about = "NeuroSploit v4.2.4 — a Rust multi-model harness that drives a pool of LLMs \
about = "NeuroSploit v4.3.0 — multi-model autonomous pentest harness",
long_about = "NeuroSploit v4.3.0 — 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\
@@ -276,6 +276,12 @@ enum Cmd {
/// Write the demoted findings back to findings.json.
#[arg(long = "apply")]
apply: bool,
/// Re-test only this finding id (default: every finding).
#[arg(long = "only")]
only: Option<String>,
/// Emit the results as JSON (one object per finding) instead of a table.
#[arg(long = "json")]
json: bool,
},
/// Assemble/print/verify a run's assurance bundle (P1–P5 in one manifest).
Assurance {
@@ -864,7 +870,7 @@ async fn main() -> anyhow::Result<()> {
Cmd::Graph { run, internal, push, top } => handle_graph(&base, &run, internal.as_deref(), push, top, cli.neo4j.as_deref()).await?,
Cmd::Assurance { run, verify } => handle_assurance(&base, &run, verify)?,
Cmd::Compliance { run, framework, include_leads } => handle_compliance(&base, &run, &framework, include_leads)?,
Cmd::Poc { run, repeats, apply } => handle_poc(&base, &run, repeats, apply).await?,
Cmd::Poc { run, repeats, apply, only, json } => handle_poc(&base, &run, repeats, apply, only, json).await?,
Cmd::Sandbox { cmd } => handle_sandbox(cmd).await?,
Cmd::Capability { cmd } => handle_capability(cmd)?,
Cmd::Provenance { cmd } => handle_provenance(cmd)?,
@@ -1957,16 +1963,40 @@ fn handle_compliance(base: &std::path::Path, run: &str, frameworks: &[String], i
Ok(())
}
async fn handle_poc(base: &std::path::Path, run: &str, repeats: usize, apply: bool) -> anyhow::Result<()> {
async fn handle_poc(base: &std::path::Path, run: &str, repeats: usize, apply: bool, only: Option<String>, json: bool) -> anyhow::Result<()> {
let dir = resolve_run(base, run)?;
let mut findings = load_findings(&dir)?;
// `--only <id>`: re-test a single finding (the web console's per-finding
// Re-test). The scope is still derived from every finding, so the one we
// replay stays inside the same authorized hosts.
if let Some(id) = &only {
if !findings.iter().any(|f| &f.id == id) {
anyhow::bail!("no finding with id `{id}` in {}", dir.display());
}
}
// Scope the replay to the hosts the findings are on — a re-validation run
// must not reach past where the engagement was authorized.
let target = findings.iter().map(|f| harness::scope::host_of(&f.endpoint)).find(|h| !h.is_empty()).unwrap_or_default();
let policy = harness::scope::ScopePolicy::for_target(&format!("https://{target}"));
let validator = harness::poc::PocValidator::new(policy).with_repeats(repeats);
println!(" re-validating {} finding(s)…", findings.len());
let results = validator.validate_all(&findings).await;
let subset: Vec<harness::types::Finding> = match &only {
Some(id) => findings.iter().filter(|f| &f.id == id).cloned().collect(),
None => findings.clone(),
};
let results = validator.validate_all(&subset).await;
if json {
// Machine-readable for the web console; it persists the history itself.
println!("{}", serde_json::to_string(&results)?);
if apply {
let by_id: std::collections::HashMap<&str, &harness::poc::PocResult> = results.iter().map(|r| (r.finding_id.as_str(), r)).collect();
for f in findings.iter_mut() {
if let Some(r) = by_id.get(f.id.as_str()) { harness::poc::apply(f, r); }
}
std::fs::write(dir.join("findings.json"), serde_json::to_string_pretty(&findings)?)?;
}
return Ok(());
}
println!(" re-validating {} finding(s)…", subset.len());
for r in &results {
let color = match r.reproduction {
harness::poc::Reproduction::Reproduced => "1;32",