diff --git a/README.md b/README.md index b8c36a8..6f43ab4 100755 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -
-
+
@@ -28,16 +28,15 @@
>
> π **New here? Read the [full Tutorial & User Guide β](TUTORIAL.md)** β every mode, flag, config and example explained.
-> π **New in v3.6.3 β resumable interrupted runs + crash-proof browsing:**
-> If a run is interrupted (terminal closed, Ctrl-C, crash), **`/continue` now
-> relaunches it** on the same target and **carries the recovered findings
-> forward** β the offer appears right at launch. And opening **`/results`**,
-> **`/finding`** or **`/report`** while a run streams no longer corrupts the
-> terminal: live output is paused for the picker (still captured in `/logs`) and
-> restored on exit. *(v3.6.2 added live Codex tool-by-tool streaming + the full
-> activity feed in `/logs`/`/status`; v3.6.1 added GPT-5.6 sol/terra/luna and
-> the Codex exit-1 fix; v3.6.0 added AI-agent/LLM/MCP/Skills/n8n testing +
-> onboarding wizard + Cloud scope.)*
+> π **New in v3.6.4 β white-box findings no longer wrongly demoted ([#33](https://github.com/JoasASantos/NeuroSploit/issues/33)):**
+> The grounding gate ran in **empirical** mode for **every** engagement, so
+> white-box SAST & skills-audit findings β whose evidence is a `file:line` code
+> citation, not HTTP/tool output β were demoted as "receipt missing" and dropped
+> from the report even after passing the n-model vote. Grounding is now
+> **mode-aware**: *symbolic* (`file:line` into the reviewed source) for
+> white-box/skills, *empirical* for black-box/host/AI, *either* for grey-box.
+> *(v3.6.3 added resumable interrupted runs + crash-proof mid-run browsing;
+> v3.6.2 live Codex tool-by-tool streaming; v3.6.1 GPT-5.6 sol/terra/luna.)*
> *(v3.5.4 added robust attack chaining + false-positive reduction; v3.5.3
> GitHub/GitLab/Jira **[integrations](TUTORIAL-INTEGRATION.md)**; v3.5.2 the DEPTH
> doctrine + report-hygiene β see [RELEASE.md](RELEASE.md).)*
@@ -71,9 +70,11 @@ Control TUI**.
and "scan more vs exploit now" falls out of belief entropy. The `may_assert`
gate is a **mathematical anti-hallucination rule** (don't claim exploitability
while the belief is diffuse).
-- π§Ύ **Grounding** β hard rule: **no claim without a tool receipt** (raw tool
- output, not paraphrase). Empirical for black-box, symbolic (`file:line`) for
- white-box; ungrounded claims are demoted.
+- π§Ύ **Grounding** β hard rule: **no claim without a receipt** (evidence, not
+ paraphrase). Empirical (raw tool output) for black-box/host/AI, **symbolic**
+ (`file:line` into the reviewed source β a code citation *is* the receipt) for
+ white-box SAST & skills audits, and **either** for grey-box; ungrounded claims
+ are demoted.
- π¬ **Deterministic HTTP probe** β before the model recon, the harness runs a
**real** request/response analysis (status/redirects, security headers, cookie
flags, CORS reflection, tech fingerprint, linked JS, 404 baseline, high-signal
diff --git a/RELEASE.md b/RELEASE.md
index b0b9d85..cfb6c83 100644
--- a/RELEASE.md
+++ b/RELEASE.md
@@ -1,7 +1,7 @@
-# NeuroSploit v3.6.3 β Release Notes
+# NeuroSploit v3.6.4 β Release Notes
**Release Date:** July 2026
-**Codename:** Resume & Recover
+**Codename:** Symbolic Grounding
**License:** MIT
**Credits:** Joas A Santos & Red Team Leaders
@@ -9,6 +9,30 @@
## Highlights
+- **Fix ([#33](https://github.com/JoasASantos/NeuroSploit/issues/33)): white-box
+ findings were silently dropped from the report.** The grounding gate β the
+ anti-hallucination step that demotes any claim lacking a receipt β was running
+ in **empirical** mode for *every* engagement. Empirical grounding looks for raw
+ tool output (HTTP responses, error oracles, shell receipts), which a **SAST
+ finding never has**: its receipt is a `file:line` reference into the reviewed
+ source. So white-box (and skills/n8n audit) findings that had *passed* the
+ n-model vote were then demoted as "receipt missing" and never reported.
+ Grounding is now **mode-aware**:
+ - **Symbolic** β white-box SAST & skills audits: a `file:line` (or
+ `file:section`) reference into the reviewed source, or a quote of code that
+ appears in it, IS the receipt. No live target needed.
+ - **Empirical** β black-box / host / AI endpoints: evidence must resemble raw
+ tool output (unchanged behaviour).
+ - **Either** β grey-box: a source citation OR a tool receipt grounds a finding.
+ The symbolic check is run against the reviewed **source corpus** (not the model
+ transcript), and falls back to a structural `file:line` + code-quote check when
+ the corpus isn't available, so a well-formed SAST finding is never dropped on a
+ technicality. Covered by unit tests (including a regression test for #33).
+
+---
+
+## Previously in v3.6.3
+
- **Interrupted runs are resumable.** When a run is cut off (terminal closed,
Ctrl-C, crash, SSH drop), its findings were already checkpointed live and
recovered as a run on the next launch. Now `/continue` (or `/resume`) also
diff --git a/TUTORIAL.md b/TUTORIAL.md
index 222c87e..fea5fec 100644
--- a/TUTORIAL.md
+++ b/TUTORIAL.md
@@ -1,4 +1,4 @@
-# NeuroSploit β Tutorial & User Guide (v3.6.3)
+# NeuroSploit β Tutorial & User Guide (v3.6.4)
A complete, hands-on guide to installing, configuring and running NeuroSploit β
the autonomous, multi-model penetration-testing harness.
@@ -98,7 +98,7 @@ Agents **degrade gracefully**: if `rustscan` is absent they use `nmap`; if neith
### Verify
```bash
-neurosploit --version # neurosploit 3.6.3
+neurosploit --version # neurosploit 3.6.4
neurosploit agents # {"vulns":196,...,"chains":12,"total":417}
neurosploit models # all providers & models
```
@@ -522,8 +522,10 @@ NeuroSploit treats the target as **partially observable** (a POMDP):
entropy: when a node's belief is diffuse, recon is worth more than exploiting.
- **Anti-hallucination gate** (`may_assert`) β the agent may **not** claim
exploitability while the belief is diffuse; it must observe more first.
-- **Grounding** β **no claim without a tool receipt**: empirical for black-box
- (real HTTP/OOB/error output), symbolic (`file:line`) for white-box. Ungrounded
+- **Grounding** β **no claim without a receipt**: *empirical* for black-box /
+ host / AI (real HTTP/OOB/error output), *symbolic* for white-box SAST & skills
+ audits (a `file:line` reference into the reviewed source β the code citation is
+ the receipt, no live target needed), and *either* for grey-box. Ungrounded
claims are demoted and flagged.
- **Chaining** β confirmed findings are chained into deeper impact, each stage
proven before advancing.
diff --git a/neurosploit-rs/Cargo.lock b/neurosploit-rs/Cargo.lock
index 2510894..c132296 100644
--- a/neurosploit-rs/Cargo.lock
+++ b/neurosploit-rs/Cargo.lock
@@ -871,7 +871,7 @@ dependencies = [
[[package]]
name = "neurosploit"
-version = "3.6.3"
+version = "3.6.4"
dependencies = [
"anyhow",
"clap",
@@ -888,7 +888,7 @@ dependencies = [
[[package]]
name = "neurosploit-harness"
-version = "3.6.3"
+version = "3.6.4"
dependencies = [
"anyhow",
"futures",
diff --git a/neurosploit-rs/Cargo.toml b/neurosploit-rs/Cargo.toml
index 2ef74dc..2c34120 100644
--- a/neurosploit-rs/Cargo.toml
+++ b/neurosploit-rs/Cargo.toml
@@ -3,7 +3,7 @@ members = ["crates/harness", "app"]
resolver = "2"
[workspace.package]
-version = "3.6.3"
+version = "3.6.4"
edition = "2021"
license = "MIT"
repository = "https://github.com/JoasASantos/NeuroSploit"
diff --git a/neurosploit-rs/app/src/main.rs b/neurosploit-rs/app/src/main.rs
index f21e6e1..362d358 100644
--- a/neurosploit-rs/app/src/main.rs
+++ b/neurosploit-rs/app/src/main.rs
@@ -1,4 +1,4 @@
-//! NeuroSploit v3.6.3 β interactive harness + CLI (`run` / `whitebox` / `agents` / `models`).
+//! NeuroSploit v3.6.4 β interactive harness + CLI (`run` / `whitebox` / `agents` / `models`).
mod repl;
mod tui;
@@ -11,8 +11,8 @@ use std::path::{Path, PathBuf};
#[command(
name = "neurosploit",
version,
- about = "NeuroSploit v3.6.3 β multi-model autonomous pentest harness",
- long_about = "NeuroSploit v3.6.3 β a Rust multi-model harness that drives a pool of LLMs \
+ about = "NeuroSploit v3.6.4 β multi-model autonomous pentest harness",
+ long_about = "NeuroSploit v3.6.4 β a Rust multi-model harness that drives a pool of LLMs \
(API key or local subscription: Claude/Codex/Gemini/Grok) 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\
@@ -721,7 +721,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 v3.6.3 Β· by Joas A Santos & Red Team Leaders");
+ println!(" ββ NeuroSploit v3.6.4 Β· by Joas A Santos & Red Team Leaders");
println!(" β run id : {run_id}");
println!(" β target : {}", cfg.target);
println!(" β models : {}", cfg.models.join(", "));
diff --git a/neurosploit-rs/app/src/repl.rs b/neurosploit-rs/app/src/repl.rs
index 8f346a0..44eff4c 100644
--- a/neurosploit-rs/app/src/repl.rs
+++ b/neurosploit-rs/app/src/repl.rs
@@ -1,4 +1,4 @@
-//! NeuroSploit v3.6.3 β interactive session (Claude-Code / Codex / Cursor-CLI style).
+//! NeuroSploit v3.6.4 β interactive session (Claude-Code / Codex / Cursor-CLI style).
//!
//! Launched when `neurosploit` runs with no subcommand. A persistent REPL with
//! real line editing (arrow-key history recall, Ctrl-A/E/K, paste), model
@@ -357,7 +357,7 @@ pub async fn repl(base: &Path) -> anyhow::Result<()> {
let backends = harness::installed_cli_backends();
println!("\x1b[1m");
println!(" ββββ ββββββββββββββ ββββββββββ βββββββ");
- println!(" βββββ ββββββββββββββ ββββββββββββββββββββ NeuroSploit v3.6.3");
+ println!(" βββββ ββββββββββββββ ββββββββββββββββββββ NeuroSploit v3.6.4");
println!(" ββββββ βββββββββ βββ ββββββββββββββ βββ interactive harness");
println!(" ββββββββββββββββ βββ ββββββββββββββ βββ by Joas A Santos");
println!(" βββ ββββββββββββββββββββββββββ ββββββββββββ & Red Team Leaders");
diff --git a/neurosploit-rs/app/src/tui.rs b/neurosploit-rs/app/src/tui.rs
index 762fcea..dee5b55 100644
--- a/neurosploit-rs/app/src/tui.rs
+++ b/neurosploit-rs/app/src/tui.rs
@@ -1,4 +1,4 @@
-//! NeuroSploit v3.6.3 β TUI "Mission Control" mode.
+//! NeuroSploit v3.6.4 β TUI "Mission Control" mode.
//!
//! Concurrent panels that update live while the engagement runs in the
//! background, with a composer input that stays active during execution:
diff --git a/neurosploit-rs/crates/harness/src/belief.rs b/neurosploit-rs/crates/harness/src/belief.rs
index 4da71c6..540b4e1 100644
--- a/neurosploit-rs/crates/harness/src/belief.rs
+++ b/neurosploit-rs/crates/harness/src/belief.rs
@@ -1,4 +1,4 @@
-//! POMDP belief-state world model (v3.6.3).
+//! POMDP belief-state world model (v3.6.4).
//!
//! The target is only partially observable, so we don't track booleans β we
//! track a **belief**: a property graph whose nodes (host / service / vuln /
diff --git a/neurosploit-rs/crates/harness/src/grounding.rs b/neurosploit-rs/crates/harness/src/grounding.rs
index 288e408..cebe9da 100644
--- a/neurosploit-rs/crates/harness/src/grounding.rs
+++ b/neurosploit-rs/crates/harness/src/grounding.rs
@@ -1,20 +1,36 @@
-//! Verification / grounding engine (v3.6.3).
+//! Verification / grounding engine (v3.6.4).
//!
-//! Hard rule: **no claim enters the world model without a tool receipt** β raw
-//! tool output, not the LLM's paraphrase. This is the empirical anti-hallucination
-//! anchor that complements the POMDP belief gate:
+//! Hard rule: **no claim enters the world model without a receipt** β evidence,
+//! not the LLM's bare assertion. This is the anti-hallucination anchor that
+//! complements the POMDP belief gate. What counts as a receipt depends on the
+//! engagement, so grounding runs in one of three modes:
//!
-//! - **Black-box**: grounding is empirical β the finding's evidence must look
-//! like raw tool output (an HTTP response, an OOB callback, an error oracle),
-//! not prose.
-//! - **White-box**: grounding is symbolic β a file:line reference into the
-//! reviewed source (reachability/taint), checked against the collected context.
+//! - **Empirical** (black-box / host / AI-endpoint): the finding's evidence must
+//! look like raw tool output (an HTTP response, an OOB callback, an error
+//! oracle, a shell receipt) β not prose.
+//! - **Symbolic** (white-box SAST / skills audit): the receipt is a `file:line`
+//! (or `file:section`) reference into the reviewed source, or a quote of code
+//! that actually appears in it. There is NO live target to hit, so requiring an
+//! HTTP-style receipt here is wrong β a code citation IS the receipt.
+//! - **Either** (grey-box): both worlds are present (source review + a running
+//! app), so a finding is grounded if it has a symbolic OR an empirical receipt.
//!
//! Ungrounded claims are flagged (`receipt_missing`) so the reward layer can
//! penalize them (the "claim without receipt" term).
use crate::types::Finding;
+/// How a finding must be grounded, per engagement type.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum GroundMode {
+ /// Black-box / host / AI endpoint: evidence must resemble raw tool output.
+ Empirical,
+ /// White-box SAST / skills audit: evidence must reference the reviewed source.
+ Symbolic,
+ /// Grey-box: accept either a source citation or an empirical receipt.
+ Either,
+}
+
/// Verdict of grounding a single finding.
pub struct Grounded {
pub ok: bool,
@@ -35,47 +51,91 @@ fn looks_empirical(evidence: &str) -> bool {
}
/// White-box: evidence should reference a source location present in `context`.
+/// `context` is the reviewed SOURCE (not the model transcript). When the source
+/// context is unavailable, fall back to structural checks so a well-formed
+/// `file:line` + code quote still grounds (a SAST finding must never be silently
+/// dropped just because the caller couldn't supply the corpus).
fn looks_symbolic(f: &Finding, context: &str) -> bool {
- // endpoint like file.ext:line, and the file appears in the reviewed source.
- let loc = &f.endpoint;
- if let Some((file, _)) = loc.rsplit_once(':') {
- let base = file.rsplit('/').next().unwrap_or(file);
- if !base.is_empty() && context.contains(base) {
- return true;
+ let loc = f.endpoint.trim();
+ // A file:line / file:section reference is the canonical symbolic receipt.
+ let has_file_ref = loc.rsplit_once(':')
+ .map(|(file, tail)| {
+ let base = file.rsplit(['/', '\\']).next().unwrap_or(file);
+ // looks like a path/file (has an extension or a separator) and a
+ // line/section follows β i.e. not a "host:port" style endpoint.
+ !base.is_empty()
+ && (base.contains('.') || file.contains('/'))
+ && !tail.trim().is_empty()
+ })
+ .unwrap_or(false);
+
+ if !context.is_empty() {
+ // Strongest: the referenced file actually appears in the reviewed source.
+ if let Some((file, _)) = loc.rsplit_once(':') {
+ let base = file.rsplit(['/', '\\']).next().unwrap_or(file);
+ if !base.is_empty() && context.contains(base) {
+ return true;
+ }
}
- }
- // or the evidence quotes code that is actually in the context
- !f.evidence.trim().is_empty()
- && f.evidence.split_whitespace().take(6).collect::
NeuroSploit Penetration Test Report
\
- \
+ \
Findings ({n})
{body}\
-