mirror of
https://github.com/CyberSecurityUP/NeuroSploit.git
synced 2026-09-30 13:09:36 +02:00
feat(report): SARIF 2.1.0 export + stronger cross-object reference mining (v4.2.1)
- new sarif module: projects findings to SARIF 2.1.0 (rules deduped by CWE, security-severity from graded CVSS, endpoint locations, OWASP/MITRE tags) - report::write_all/rebuild now emit report.sarif alongside md/json/html/pdf - `neurosploit sarif <run> [--out]` re-emits on demand; exposed over MCP - assurance: report.sarif added to the known-artifacts manifest - chaining doctrine: harvest every object identifier (ids/UUIDs/tokens/emails) into a reference pool and substitute across identities/endpoints — the core of reliable BOLA/IDOR/mass-assignment discovery - version 4.2.1; 389 tests passing Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
e49595b8bf
commit
5ab6451c15
10 files changed
+304
-8
No files matched your search
@@ -203,6 +203,15 @@ enum Cmd {
|
||||
/// Run id or path.
|
||||
run: String,
|
||||
},
|
||||
/// Emit SARIF 2.1.0 for a finished run so CI code-scanning (GitHub, Azure
|
||||
/// DevOps) can ingest the findings as annotated, severity-coloured alerts.
|
||||
Sarif {
|
||||
/// Run id (`ns-…`) or a path to the run directory.
|
||||
run: String,
|
||||
/// Write to this path instead of the run's `report.sarif`.
|
||||
#[arg(long = "out")]
|
||||
out: Option<String>,
|
||||
},
|
||||
/// Verify a finished run's audit trail — the hash chain and, with --anchor,
|
||||
/// the signed anchors that catch truncation and silent rebuilds.
|
||||
Audit {
|
||||
@@ -808,6 +817,7 @@ async fn main() -> anyhow::Result<()> {
|
||||
}
|
||||
Cmd::Audit { run, anchor } => handle_audit(&base, &run, anchor)?,
|
||||
Cmd::Traffic { run } => handle_traffic(&base, &run)?,
|
||||
Cmd::Sarif { run, out } => handle_sarif(&base, &run, out.as_deref())?,
|
||||
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?,
|
||||
@@ -1657,6 +1667,21 @@ fn handle_traffic(base: &std::path::Path, run: &str) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_sarif(base: &std::path::Path, run: &str, out: Option<&str>) -> anyhow::Result<()> {
|
||||
let dir = resolve_run(base, run)?;
|
||||
let findings = load_findings(&dir)?;
|
||||
let target = std::fs::read_to_string(dir.join("meta.json"))
|
||||
.ok()
|
||||
.and_then(|t| serde_json::from_str::<serde_json::Value>(&t).ok())
|
||||
.and_then(|v| v.get("target").and_then(|x| x.as_str()).map(String::from))
|
||||
.unwrap_or_else(|| run.to_string());
|
||||
let doc = harness::sarif::to_string(&target, &findings);
|
||||
let dest = out.map(std::path::PathBuf::from).unwrap_or_else(|| dir.join("report.sarif"));
|
||||
std::fs::write(&dest, doc)?;
|
||||
println!(" {} finding(s) -> SARIF 2.1.0 at {}", findings.len(), dest.display());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_audit(base: &std::path::Path, run: &str, anchor: bool) -> anyhow::Result<()> {
|
||||
let dir = resolve_run(base, run)?;
|
||||
let log = harness::audit::AuditLog::open(dir.join("audit.jsonl"));
|
||||
|
||||
@@ -99,6 +99,7 @@ fn tool_list() -> Value {
|
||||
{ "name": "neurosploit_findings", "description": "Read a finished run's findings as JSON.", "inputSchema": { "type": "object", "properties": { "run": { "type": "string", "description": "Run id or path" } }, "required": ["run"] } },
|
||||
{ "name": "neurosploit_report", "description": "Read a finished run's Markdown report.", "inputSchema": { "type": "object", "properties": { "run": { "type": "string" } }, "required": ["run"] } },
|
||||
{ "name": "neurosploit_rebuild", "description": "Rebuild a run's report artifacts from its findings (no model calls).", "inputSchema": { "type": "object", "properties": { "run": { "type": "string" } }, "required": ["run"] } },
|
||||
{ "name": "neurosploit_sarif", "description": "Emit SARIF 2.1.0 for a finished run (report.sarif) so CI code-scanning can ingest the findings.", "inputSchema": { "type": "object", "properties": { "run": { "type": "string" } }, "required": ["run"] } },
|
||||
{ "name": "neurosploit_internal", "description": "Internal-network / Active Directory attack-graph analysis: paths to crown jewels and the choke point to fix first.", "inputSchema": { "type": "object", "properties": { "graph": { "type": "string", "description": "Path to a graph JSON" }, "scaffold": { "type": "string", "description": "Domain to scaffold, e.g. corp.local" }, "from": { "type": "string", "description": "Foothold node id" } } } },
|
||||
{ "name": "neurosploit_compliance", "description": "Map a finished run's findings onto PCI-DSS, HIPAA or SOC 2 controls.", "inputSchema": { "type": "object", "properties": { "run": { "type": "string" }, "framework": { "type": "string", "enum": ["pci-dss","hipaa","soc2"] } }, "required": ["run"] } },
|
||||
{ "name": "neurosploit_container", "description": "Scan an OCI container image (repo:tag / tar / Dockerfile) for vulnerable packages, secrets, misconfig and emit an SBOM.", "inputSchema": { "type": "object", "properties": { "image": { "type": "string" }, "model": { "type": "string" }, "subscription": { "type": "boolean" } }, "required": ["image"] } }
|
||||
@@ -138,6 +139,7 @@ fn handle_call(id: Option<Value>, req: &Value, exe: &std::path::Path) -> Value {
|
||||
return read_run_file(id, &run, "report.md");
|
||||
}
|
||||
"neurosploit_rebuild" => { let Some(run) = s("run") else { return tool_err(id, "run is required") }; argv.push("rebuild".into()); argv.push(run); }
|
||||
"neurosploit_sarif" => { let Some(run) = s("run") else { return tool_err(id, "run is required") }; argv.push("sarif".into()); argv.push(run); }
|
||||
"neurosploit_internal" => {
|
||||
argv.push("internal".into());
|
||||
if let Some(g) = s("graph") { argv.push("--graph".into()); argv.push(g); }
|
||||
|
||||
Reference in new issue
Block a user