[pitboss] phase 05: Track C.2 + Track I.1 quick unlocks — OOB listener wired + golden-verdict fixture runner

This commit is contained in:
pitboss 2026-05-14 05:01:50 -05:00
parent 937eb479e6
commit cdbc7f2d21
50 changed files with 790 additions and 587 deletions

View file

@ -5,6 +5,17 @@
//! URL path. The lifetime of the listener is per-scan: create one
//! [`OobListener`] at scan start, drop it when the scan finishes.
//!
//! # Wiring
//!
//! As of Phase 05 the listener is load-bearing: [`crate::dynamic::verify::VerifyOptions::from_config`]
//! constructs one per scan via [`OobListener::bind`] and threads it into
//! [`crate::dynamic::sandbox::SandboxOptions::oob_listener`]. The runner
//! polls [`OobListener::was_nonce_hit`] after each sandbox run (see
//! `src/dynamic/runner.rs`) and toggles
//! [`crate::dynamic::sandbox::SandboxOutcome::oob_callback_seen`] when a
//! probe arrives — that is the only signal that turns an OOB-only sink
//! (e.g. blind SSRF) into a `Confirmed` verdict.
//!
//! # Nonce URL
//!
//! The caller generates a per-finding nonce (UUID4 hex) and embeds it in

View file

@ -6,6 +6,7 @@
use crate::callgraph::CallGraph;
use crate::commands::scan::Diag;
use crate::dynamic::corpus::{payloads_for, CORPUS_VERSION};
use crate::dynamic::oob::OobListener;
use crate::dynamic::report::{AttemptSummary, VerifyResult, VerifyStatus};
use crate::dynamic::runner::{run_spec, RunError};
use crate::dynamic::sandbox::{toolchain_id_with_digest, SandboxOptions};
@ -54,6 +55,17 @@ pub struct VerifyOptions {
impl VerifyOptions {
/// Build `VerifyOptions` from scanner config.
///
/// Binds a per-scan [`OobListener`] on a free loopback port and attaches
/// it to `sandbox.oob_listener`. The listener is held by `Arc` so every
/// per-finding clone of `VerifyOptions` shares the same accept thread;
/// it is torn down via the `OobListener::Drop` impl once the last
/// `Arc` is released at end of scan.
///
/// If `OobListener::bind` fails (e.g. all loopback ports are in use),
/// the field stays `None`; the runner skips OOB-callback payloads
/// (`src/dynamic/runner.rs` `oob_nonce_slot` branch) while non-OOB
/// payloads continue to run against their existing oracle.
pub fn from_config(config: &Config) -> Self {
use crate::dynamic::sandbox::SandboxBackend;
let backend = match config.scanner.verify_backend.as_str() {
@ -61,9 +73,11 @@ impl VerifyOptions {
"process" => SandboxBackend::Process,
_ => SandboxBackend::Auto,
};
let oob_listener = OobListener::bind().ok().map(Arc::new);
Self {
sandbox: SandboxOptions {
backend,
oob_listener,
..SandboxOptions::default()
},
project_root: None,