This commit is contained in:
Eli Peter 2026-06-05 10:16:30 -05:00 committed by GitHub
parent 55247b7fcd
commit 991c84a1eb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
1464 changed files with 225448 additions and 1985 deletions

212
src/dynamic/corpus/audit.rs Normal file
View file

@ -0,0 +1,212 @@
//! Compile-time + runtime audits over the corpus registry.
//!
//! Two invariants enforced here fail the build (via `const _: () = assert!(...)`)
//! if they regress:
//!
//! 1. **`benign_control` resolves locally.** Every non-benign payload either
//! references a benign control whose `label` appears inside the same
//! `(cap, lang)` slice, *or* carries an explicit
//! [`CuratedPayload::no_benign_control_rationale`] with a non-empty
//! written rationale. Without this guard the differential rule
//! (§4.1) silently downgrades to `Inconclusive(NoBenignControl)`
//! whenever a maintainer forgets to wire a paired benign entry.
//!
//! 2. **Cap coverage is exhaustive.** The set of caps appearing in
//! [`CORPUS`]'s [`entries`](super::CapCorpus::entries) OR [`CORPUS_UNSUPPORTED_LANG_NEUTRAL`] must
//! equal [`Cap::all`]. Adding a new `Cap` bit without classifying it
//! fails the build.
//!
//! The runtime `corpus_registry::audit` test mirrors both checks so
//! failure surfaces in `cargo test` output, not just `cargo build`.
use super::CuratedPayload;
use super::registry::{CORPUS, CORPUS_UNSUPPORTED_LANG_NEUTRAL};
use crate::labels::Cap;
/// Byte-level equality for `&'static str` usable in const eval.
#[allow(dead_code)] // Called from const-eval audit helpers on MSRV/CI compilers.
const fn str_eq(a: &str, b: &str) -> bool {
let ab = a.as_bytes();
let bb = b.as_bytes();
if ab.len() != bb.len() {
return false;
}
let mut i = 0;
while i < ab.len() {
if ab[i] != bb[i] {
return false;
}
i += 1;
}
true
}
/// Walk every `(cap, lang)` slice; for each non-benign payload check that
/// either its `benign_control.label` resolves inside the same slice or it
/// carries a non-empty `no_benign_control_rationale`.
#[allow(dead_code)] // Called from a const assertion; MSRV lints may miss const-eval uses.
const fn audit_benign_controls() -> bool {
let entries = CORPUS.entries;
let mut e = 0;
while e < entries.len() {
let slice: &[CuratedPayload] = entries[e].2;
let mut i = 0;
while i < slice.len() {
let p = &slice[i];
if !p.is_benign {
match p.benign_control {
Some(r) => {
let mut j = 0;
let mut found = false;
while j < slice.len() {
if slice[j].is_benign && str_eq(slice[j].label, r.label) {
found = true;
break;
}
j += 1;
}
if !found {
return false;
}
}
None => match p.no_benign_control_rationale {
Some(rationale) => {
if rationale.is_empty() {
return false;
}
}
None => return false,
},
}
}
i += 1;
}
e += 1;
}
true
}
/// OR of cap bits appearing in `CORPUS.entries`.
const fn registered_cap_bits() -> u32 {
let entries = CORPUS.entries;
let mut bits = 0u32;
let mut i = 0;
while i < entries.len() {
bits |= entries[i].0.bits();
i += 1;
}
bits
}
/// Compile-time guards. Bumping or breaking these fails `cargo build`.
const _: () = assert!(
audit_benign_controls(),
"corpus audit: a non-benign payload references a `benign_control` whose \
label does not resolve inside its own (cap, lang) slice AND carries no \
`no_benign_control_rationale` see src/dynamic/corpus/audit.rs.",
);
const _: () = assert!(
registered_cap_bits() | CORPUS_UNSUPPORTED_LANG_NEUTRAL == Cap::all().bits(),
"corpus audit: union of (cap, lang) entries and \
`CORPUS_UNSUPPORTED_LANG_NEUTRAL` does not cover every `Cap` bit. \
Add the missing cap to either a `(cap, lang)` slice or the \
lang-neutral unsupported list.",
);
/// Runtime mirror of the compile-time benign-control audit.
pub fn audit_benign_controls_runtime() -> Result<(), String> {
for &(cap, lang, slice) in CORPUS.entries {
for p in slice {
if p.is_benign {
continue;
}
match p.benign_control {
Some(r) => {
let found = slice.iter().any(|q| q.is_benign && q.label == r.label);
if !found {
return Err(format!(
"({:?}, {:?}) vuln payload {:?} references missing \
benign_control label {:?}",
cap, lang, p.label, r.label,
));
}
}
None => match p.no_benign_control_rationale {
Some(rationale) if !rationale.is_empty() => {}
_ => {
return Err(format!(
"({:?}, {:?}) vuln payload {:?} has neither a \
benign_control nor a written \
no_benign_control_rationale",
cap, lang, p.label,
));
}
},
}
}
}
Ok(())
}
/// Runtime mirror of the compile-time cap-coverage audit.
pub fn audit_cap_coverage_runtime() -> Result<(), String> {
let covered = registered_cap_bits() | CORPUS_UNSUPPORTED_LANG_NEUTRAL;
if covered != Cap::all().bits() {
let missing = Cap::all().bits() & !covered;
return Err(format!(
"Cap bits {missing:#x} are neither registered in CORPUS.entries \
nor listed in CORPUS_UNSUPPORTED_LANG_NEUTRAL",
));
}
Ok(())
}
/// Track J.0 deferred audit: a non-benign payload's `benign_control.label`
/// must be unique *within its own `(cap, lang)` slice* — and a benign
/// payload's label may not collide with any other benign label inside the
/// same cap across lang slices, otherwise the lang-agnostic union shim
/// could resolve a vuln payload in language A against a benign payload
/// declared in language B (the latent §4.1 bug captured in the deferred
/// queue).
pub fn audit_benign_label_uniqueness_runtime() -> Result<(), String> {
use std::collections::HashMap;
let mut by_cap: HashMap<u32, HashMap<&'static str, crate::symbol::Lang>> = HashMap::new();
for &(cap, lang, slice) in CORPUS.entries {
let bucket = by_cap.entry(cap.bits()).or_default();
for p in slice {
if !p.is_benign {
continue;
}
if let Some(prev_lang) = bucket.insert(p.label, lang)
&& prev_lang != lang
{
return Err(format!(
"benign label {:?} for cap {:#x} is registered in both \
{:?} and {:?} lang-agnostic resolve_benign_control \
could match the wrong language",
p.label,
cap.bits(),
prev_lang,
lang,
));
}
}
}
Ok(())
}
#[cfg(test)]
mod corpus_registry {
use super::*;
/// Plan §02 acceptance: `cargo test corpus_registry::audit` must pass.
/// The test name and module name jointly form the required path.
#[test]
fn audit() {
audit_benign_controls_runtime().expect("benign_control audit failed");
audit_cap_coverage_runtime().expect("cap coverage audit failed");
audit_benign_label_uniqueness_runtime().expect("benign label uniqueness audit failed");
}
}

View file

@ -0,0 +1,46 @@
//! C `Cap::CODE_EXEC` payloads.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b":; echo NYX_PWN_$((113*7))_CMDI",
label: "cmdi-echo-marker-c",
oracle: Oracle::OutputContains("NYX_PWN_791_CMDI"),
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &[
"tests/benchmark/corpus/c/cmdi/cmdi_exec.c",
"tests/benchmark/corpus/c/cmdi/cmdi_fgets.c",
"tests/benchmark/corpus/c/cmdi/cmdi_popen.c",
"tests/benchmark/corpus/c/cmdi/cmdi_system.c",
],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: Some(PayloadRef {
label: "cmdi-benign-c",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"benign_safe_cmdi_NYX_BENIGN",
label: "cmdi-benign-c",
oracle: Oracle::OutputContains("NYX_PWN_791_CMDI"),
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &[
"tests/benchmark/corpus/c/cmdi/cmdi_exec.c",
"tests/benchmark/corpus/c/cmdi/cmdi_fgets.c",
"tests/benchmark/corpus/c/cmdi/cmdi_popen.c",
"tests/benchmark/corpus/c/cmdi/cmdi_system.c",
],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,52 @@
//! C++ `Cap::CODE_EXEC` payloads.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b":; echo NYX_PWN_$((113*7))_CMDI",
label: "cmdi-echo-marker-cpp",
oracle: Oracle::OutputContains("NYX_PWN_791_CMDI"),
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &[
"tests/benchmark/corpus/cpp/cmdi/cmdi_class_inline_method.cpp",
"tests/benchmark/corpus/cpp/cmdi/cmdi_exec.cpp",
"tests/benchmark/corpus/cpp/cmdi/cmdi_getline.cpp",
"tests/benchmark/corpus/cpp/cmdi/cmdi_lambda_passthrough.cpp",
"tests/benchmark/corpus/cpp/cmdi/cmdi_popen.cpp",
"tests/benchmark/corpus/cpp/cmdi/cmdi_stl_vector_string.cpp",
"tests/benchmark/corpus/cpp/cmdi/cmdi_system.cpp",
],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: Some(PayloadRef {
label: "cmdi-benign-cpp",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"benign_safe_cmdi_NYX_BENIGN",
label: "cmdi-benign-cpp",
oracle: Oracle::OutputContains("NYX_PWN_791_CMDI"),
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &[
"tests/benchmark/corpus/cpp/cmdi/cmdi_class_inline_method.cpp",
"tests/benchmark/corpus/cpp/cmdi/cmdi_exec.cpp",
"tests/benchmark/corpus/cpp/cmdi/cmdi_getline.cpp",
"tests/benchmark/corpus/cpp/cmdi/cmdi_lambda_passthrough.cpp",
"tests/benchmark/corpus/cpp/cmdi/cmdi_popen.cpp",
"tests/benchmark/corpus/cpp/cmdi/cmdi_stl_vector_string.cpp",
"tests/benchmark/corpus/cpp/cmdi/cmdi_system.cpp",
],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,46 @@
//! Go `Cap::CODE_EXEC` payloads.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b":; echo NYX_PWN_$((113*7))_CMDI",
label: "cmdi-echo-marker-go",
oracle: Oracle::OutputContains("NYX_PWN_791_CMDI"),
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &[
"tests/benchmark/corpus/go/cmdi/cmdi_direct.go",
"tests/benchmark/corpus/go/cmdi/cmdi_indirect.go",
"tests/benchmark/corpus/go/cmdi/cmdi_unvalidated_queue_element.go",
"tests/benchmark/corpus/go/cmdi/vuln_error_log_then_sink.go",
],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: Some(PayloadRef {
label: "cmdi-benign-go",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"benign_safe_cmdi_NYX_BENIGN",
label: "cmdi-benign-go",
oracle: Oracle::OutputContains("NYX_PWN_791_CMDI"),
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &[
"tests/benchmark/corpus/go/cmdi/cmdi_direct.go",
"tests/benchmark/corpus/go/cmdi/cmdi_indirect.go",
"tests/benchmark/corpus/go/cmdi/cmdi_unvalidated_queue_element.go",
"tests/benchmark/corpus/go/cmdi/vuln_error_log_then_sink.go",
],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,42 @@
//! Java `Cap::CODE_EXEC` payloads.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b":; echo NYX_PWN_$((113*7))_CMDI",
label: "cmdi-echo-marker-java",
oracle: Oracle::OutputContains("NYX_PWN_791_CMDI"),
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &[
"tests/benchmark/corpus/java/cmdi/CmdiDirect.java",
"tests/benchmark/corpus/java/cmdi/CmdiIndirect.java",
],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: Some(PayloadRef {
label: "cmdi-benign-java",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"benign_safe_cmdi_NYX_BENIGN",
label: "cmdi-benign-java",
oracle: Oracle::OutputContains("NYX_PWN_791_CMDI"),
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &[
"tests/benchmark/corpus/java/cmdi/CmdiDirect.java",
"tests/benchmark/corpus/java/cmdi/CmdiIndirect.java",
],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,42 @@
//! JavaScript `Cap::CODE_EXEC` payloads.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b":; echo NYX_PWN_$((113*7))_CMDI",
label: "cmdi-echo-marker-javascript",
oracle: Oracle::OutputContains("NYX_PWN_791_CMDI"),
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &[
"tests/benchmark/corpus/javascript/cmdi/cmdi_direct.js",
"tests/benchmark/corpus/javascript/cmdi/cmdi_indirect.js",
],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: Some(PayloadRef {
label: "cmdi-benign-javascript",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"benign_safe_cmdi_NYX_BENIGN",
label: "cmdi-benign-javascript",
oracle: Oracle::OutputContains("NYX_PWN_791_CMDI"),
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &[
"tests/benchmark/corpus/javascript/cmdi/cmdi_direct.js",
"tests/benchmark/corpus/javascript/cmdi/cmdi_indirect.js",
],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,12 @@
//! Command-injection (`Cap::CODE_EXEC`) per-language payload slices.
pub mod c;
pub mod cpp;
pub mod go;
pub mod java;
pub mod javascript;
pub mod php;
pub mod python;
pub mod ruby;
pub mod rust;
pub mod typescript;

View file

@ -0,0 +1,42 @@
//! PHP `Cap::CODE_EXEC` payloads.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b":; echo NYX_PWN_$((113*7))_CMDI",
label: "cmdi-echo-marker-php",
oracle: Oracle::OutputContains("NYX_PWN_791_CMDI"),
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &[
"tests/benchmark/corpus/php/cmdi/cmdi_direct.php",
"tests/benchmark/corpus/php/cmdi/cmdi_indirect.php",
],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: Some(PayloadRef {
label: "cmdi-benign-php",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"benign_safe_cmdi_NYX_BENIGN",
label: "cmdi-benign-php",
oracle: Oracle::OutputContains("NYX_PWN_791_CMDI"),
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &[
"tests/benchmark/corpus/php/cmdi/cmdi_direct.php",
"tests/benchmark/corpus/php/cmdi/cmdi_indirect.php",
],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,48 @@
//! Python `Cap::CODE_EXEC` payloads.
//!
//! Same shell-syntax bytes as [`super::rust::PAYLOADS`]; the per-language
//! slice exists so the lookup is a per-language assertion rather than a
//! cross-language fallback through [`super::super::registry::payloads_for`].
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b":; echo NYX_PWN_$((113*7))_CMDI",
label: "cmdi-echo-marker-python",
oracle: Oracle::OutputContains("NYX_PWN_791_CMDI"),
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &[
"tests/benchmark/corpus/python/cmdi/cmdi_direct.py",
"tests/benchmark/corpus/python/cmdi/cmdi_indirect.py",
"tests/benchmark/corpus/python/cmdi/cmdi_popen_shell.py",
],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: Some(PayloadRef {
label: "cmdi-benign-python",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"benign_safe_cmdi_NYX_BENIGN",
label: "cmdi-benign-python",
oracle: Oracle::OutputContains("NYX_PWN_791_CMDI"),
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &[
"tests/benchmark/corpus/python/cmdi/cmdi_direct.py",
"tests/benchmark/corpus/python/cmdi/cmdi_indirect.py",
"tests/benchmark/corpus/python/cmdi/cmdi_popen_shell.py",
],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,44 @@
//! Ruby `Cap::CODE_EXEC` payloads.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b":; echo NYX_PWN_$((113*7))_CMDI",
label: "cmdi-echo-marker-ruby",
oracle: Oracle::OutputContains("NYX_PWN_791_CMDI"),
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &[
"tests/benchmark/corpus/ruby/cmdi/cmdi_backtick.rb",
"tests/benchmark/corpus/ruby/cmdi/cmdi_kernel_open.rb",
"tests/benchmark/corpus/ruby/cmdi/cmdi_system.rb",
],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: Some(PayloadRef {
label: "cmdi-benign-ruby",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"benign_safe_cmdi_NYX_BENIGN",
label: "cmdi-benign-ruby",
oracle: Oracle::OutputContains("NYX_PWN_791_CMDI"),
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &[
"tests/benchmark/corpus/ruby/cmdi/cmdi_backtick.rb",
"tests/benchmark/corpus/ruby/cmdi/cmdi_kernel_open.rb",
"tests/benchmark/corpus/ruby/cmdi/cmdi_system.rb",
],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,48 @@
//! Command-injection payloads exercised by Rust fixtures
//! (`tests/benchmark/corpus/rust/cmdi/`).
//!
//! Bytes are shell-syntax, not Rust-specific; Track J phases 0311 add
//! per-language slices (Python `os.system`, PHP `exec`, …) as new fixtures
//! land.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b":; echo NYX_PWN_$((113*7))_CMDI",
label: "cmdi-echo-marker",
oracle: Oracle::OutputContains("NYX_PWN_791_CMDI"),
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 1,
deprecated_at_corpus_version: None,
fixture_paths: &[
"tests/benchmark/corpus/rust/cmdi/cmdi_command.rs",
"tests/benchmark/corpus/rust/cmdi/cmdi_args.rs",
],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: Some(PayloadRef {
label: "cmdi-benign",
}),
no_benign_control_rationale: None,
},
// Benign control: plain text that should never produce the cmdi marker.
CuratedPayload {
bytes: b"benign_safe_cmdi_NYX_BENIGN",
label: "cmdi-benign",
oracle: Oracle::OutputContains("NYX_PWN_791_CMDI"),
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 4,
deprecated_at_corpus_version: None,
fixture_paths: &[
"tests/benchmark/corpus/rust/cmdi/cmdi_command.rs",
"tests/benchmark/corpus/rust/cmdi/cmdi_args.rs",
],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,42 @@
//! TypeScript `Cap::CODE_EXEC` payloads.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b":; echo NYX_PWN_$((113*7))_CMDI",
label: "cmdi-echo-marker-typescript",
oracle: Oracle::OutputContains("NYX_PWN_791_CMDI"),
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &[
"tests/benchmark/corpus/typescript/cmdi/cmdi_async_wrapper.ts",
"tests/benchmark/corpus/typescript/cmdi/cmdi_exec_template.ts",
],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: Some(PayloadRef {
label: "cmdi-benign-typescript",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"benign_safe_cmdi_NYX_BENIGN",
label: "cmdi-benign-typescript",
oracle: Oracle::OutputContains("NYX_PWN_791_CMDI"),
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &[
"tests/benchmark/corpus/typescript/cmdi/cmdi_async_wrapper.ts",
"tests/benchmark/corpus/typescript/cmdi/cmdi_exec_template.ts",
],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,50 @@
//! Go `Cap::CRYPTO` payloads — `math/rand.Intn` weak-key
//! generation.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
const WEAK_BITS: u32 = 16;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"NYX_CRYPTO_WEAK",
label: "crypto-go-weak-random",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::WeakKeyEntropy {
max_bits: WEAK_BITS,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/crypto/go/vuln.go"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::WeakKeyEntropy {
max_bits: WEAK_BITS,
}],
benign_control: Some(PayloadRef {
label: "crypto-go-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"NYX_CRYPTO_STRONG",
label: "crypto-go-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::WeakKeyEntropy {
max_bits: WEAK_BITS,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/crypto/go/benign.go"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,61 @@
//! Java `Cap::CRYPTO` payloads — `java.util.Random.nextBytes`
//! weak-key generation.
//!
//! Vuln payload: marker bytes that signal the harness to drive its
//! `java.util.Random` key-generation path. The harness emits a key
//! bounded inside a 16-bit search space and writes a
//! [`crate::dynamic::probe::ProbeKind::WeakKey`] probe — the
//! [`crate::dynamic::oracle::ProbePredicate::WeakKeyEntropy`]
//! predicate fires for `key_int < 2^16`.
//!
//! Benign control: marker bytes that route the harness through
//! `java.security.SecureRandom`, producing a 256-bit key whose
//! integer view trivially exceeds the budget.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
const WEAK_BITS: u32 = 16;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"NYX_CRYPTO_WEAK",
label: "crypto-java-weak-random",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::WeakKeyEntropy {
max_bits: WEAK_BITS,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/crypto/java/vuln.java"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::WeakKeyEntropy {
max_bits: WEAK_BITS,
}],
benign_control: Some(PayloadRef {
label: "crypto-java-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"NYX_CRYPTO_STRONG",
label: "crypto-java-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::WeakKeyEntropy {
max_bits: WEAK_BITS,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/crypto/java/benign.java"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,26 @@
//! Weak-crypto (`Cap::CRYPTO`) per-language payload slices.
//!
//! Phase 11 (Track J.9) carves a weak-key entropy oracle across the
//! five backend languages where homegrown key generation is common
//! enough to matter: Java (`java.util.Random.nextBytes` → key bytes),
//! Python (`random.randint(0, 0xFFFF)`), PHP (`mt_rand(0, 0xFFFF)`),
//! Go (`math/rand.Intn(0x10000)`), Rust (`rand::thread_rng` truncated
//! to 16 bits). Every vuln payload triggers the harness's
//! instrumented key-generation path with a seed that produces an
//! attacker-derivable key bounded inside the 16-bit search space.
//! The harness shim writes a
//! [`crate::dynamic::probe::ProbeKind::WeakKey { key_int }`] probe
//! with the produced integer view of the key bytes; the
//! [`crate::dynamic::oracle::ProbePredicate::WeakKeyEntropy`]
//! predicate fires when `key_int < 2^max_bits` (`max_bits = 16` by
//! default). The paired benign control routes the same harness
//! through a CSPRNG (`SecureRandom`, `secrets.token_bytes`,
//! `random_bytes(32)`, `crypto/rand.Read`, `rand::rngs::OsRng`) so
//! the produced `key_int` trivially exceeds the budget and the
//! predicate stays clear.
pub mod go;
pub mod java;
pub mod php;
pub mod python;
pub mod rust;

View file

@ -0,0 +1,49 @@
//! PHP `Cap::CRYPTO` payloads — `mt_rand` weak-key generation.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
const WEAK_BITS: u32 = 16;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"NYX_CRYPTO_WEAK",
label: "crypto-php-weak-random",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::WeakKeyEntropy {
max_bits: WEAK_BITS,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/crypto/php/vuln.php"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::WeakKeyEntropy {
max_bits: WEAK_BITS,
}],
benign_control: Some(PayloadRef {
label: "crypto-php-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"NYX_CRYPTO_STRONG",
label: "crypto-php-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::WeakKeyEntropy {
max_bits: WEAK_BITS,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/crypto/php/benign.php"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,59 @@
//! Python `Cap::CRYPTO` payloads — `random.randint` weak-key
//! generation.
//!
//! Vuln payload: marker bytes that route the harness through
//! `random.randint(0, 0xFFFF)`; the harness emits a
//! [`crate::dynamic::probe::ProbeKind::WeakKey`] probe and the
//! [`crate::dynamic::oracle::ProbePredicate::WeakKeyEntropy`]
//! predicate fires.
//!
//! Benign control: marker bytes that route the harness through
//! `secrets.token_bytes(32)`.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
const WEAK_BITS: u32 = 16;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"NYX_CRYPTO_WEAK",
label: "crypto-python-weak-random",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::WeakKeyEntropy {
max_bits: WEAK_BITS,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/crypto/python/vuln.py"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::WeakKeyEntropy {
max_bits: WEAK_BITS,
}],
benign_control: Some(PayloadRef {
label: "crypto-python-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"NYX_CRYPTO_STRONG",
label: "crypto-python-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::WeakKeyEntropy {
max_bits: WEAK_BITS,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/crypto/python/benign.py"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,50 @@
//! Rust `Cap::CRYPTO` payloads — `rand::thread_rng` weak-key
//! generation truncated to 16 bits.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
const WEAK_BITS: u32 = 16;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"NYX_CRYPTO_WEAK",
label: "crypto-rust-weak-random",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::WeakKeyEntropy {
max_bits: WEAK_BITS,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/crypto/rust/vuln.rs"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::WeakKeyEntropy {
max_bits: WEAK_BITS,
}],
benign_control: Some(PayloadRef {
label: "crypto-rust-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"NYX_CRYPTO_STRONG",
label: "crypto-rust-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::WeakKeyEntropy {
max_bits: WEAK_BITS,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/crypto/rust/benign.rs"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,49 @@
//! go `Cap::DATA_EXFIL` payloads.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
const ALLOWLIST: &[&str] = &["127.0.0.1", "localhost"];
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"attacker.test",
label: "data-exfil-go-external",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::OutboundHostNotIn {
allowlist: ALLOWLIST,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/data_exfil/go/vuln.go"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::OutboundHostNotIn {
allowlist: ALLOWLIST,
}],
benign_control: Some(PayloadRef {
label: "data-exfil-go-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"127.0.0.1",
label: "data-exfil-go-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::OutboundHostNotIn {
allowlist: ALLOWLIST,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/data_exfil/go/benign.go"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,49 @@
//! java `Cap::DATA_EXFIL` payloads.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
const ALLOWLIST: &[&str] = &["127.0.0.1", "localhost"];
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"attacker.test",
label: "data-exfil-java-external",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::OutboundHostNotIn {
allowlist: ALLOWLIST,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/data_exfil/java/Vuln.java"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::OutboundHostNotIn {
allowlist: ALLOWLIST,
}],
benign_control: Some(PayloadRef {
label: "data-exfil-java-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"127.0.0.1",
label: "data-exfil-java-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::OutboundHostNotIn {
allowlist: ALLOWLIST,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/data_exfil/java/Benign.java"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,49 @@
//! js `Cap::DATA_EXFIL` payloads.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
const ALLOWLIST: &[&str] = &["127.0.0.1", "localhost"];
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"attacker.test",
label: "data-exfil-js-external",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::OutboundHostNotIn {
allowlist: ALLOWLIST,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/data_exfil/js/vuln.js"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::OutboundHostNotIn {
allowlist: ALLOWLIST,
}],
benign_control: Some(PayloadRef {
label: "data-exfil-js-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"127.0.0.1",
label: "data-exfil-js-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::OutboundHostNotIn {
allowlist: ALLOWLIST,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/data_exfil/js/benign.js"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,22 @@
//! Data-exfiltration (`Cap::DATA_EXFIL`) per-language payload
//! slices.
//!
//! Phase 11 (Track J.9) carves an outbound-network oracle across
//! all seven backend-capable languages. Each harness stands up a
//! mock HTTP client that records the destination host of every
//! outbound request via a
//! [`crate::dynamic::probe::ProbeKind::OutboundNetwork { host }`]
//! probe. The
//! [`crate::dynamic::oracle::ProbePredicate::OutboundHostNotIn`]
//! predicate fires when the captured `host` falls outside the
//! configured loopback allowlist (`&["127.0.0.1", "localhost"]`).
//! The vuln payload supplies `attacker.test`; the paired benign
//! control supplies `127.0.0.1` so the predicate stays clear.
pub mod go;
pub mod java;
pub mod js;
pub mod php;
pub mod python;
pub mod ruby;
pub mod rust;

View file

@ -0,0 +1,49 @@
//! php `Cap::DATA_EXFIL` payloads.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
const ALLOWLIST: &[&str] = &["127.0.0.1", "localhost"];
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"attacker.test",
label: "data-exfil-php-external",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::OutboundHostNotIn {
allowlist: ALLOWLIST,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/data_exfil/php/vuln.php"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::OutboundHostNotIn {
allowlist: ALLOWLIST,
}],
benign_control: Some(PayloadRef {
label: "data-exfil-php-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"127.0.0.1",
label: "data-exfil-php-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::OutboundHostNotIn {
allowlist: ALLOWLIST,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/data_exfil/php/benign.php"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,49 @@
//! python `Cap::DATA_EXFIL` payloads.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
const ALLOWLIST: &[&str] = &["127.0.0.1", "localhost"];
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"attacker.test",
label: "data-exfil-python-external",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::OutboundHostNotIn {
allowlist: ALLOWLIST,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/data_exfil/python/vuln.py"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::OutboundHostNotIn {
allowlist: ALLOWLIST,
}],
benign_control: Some(PayloadRef {
label: "data-exfil-python-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"127.0.0.1",
label: "data-exfil-python-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::OutboundHostNotIn {
allowlist: ALLOWLIST,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/data_exfil/python/benign.py"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,49 @@
//! ruby `Cap::DATA_EXFIL` payloads.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
const ALLOWLIST: &[&str] = &["127.0.0.1", "localhost"];
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"attacker.test",
label: "data-exfil-ruby-external",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::OutboundHostNotIn {
allowlist: ALLOWLIST,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/data_exfil/ruby/vuln.rb"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::OutboundHostNotIn {
allowlist: ALLOWLIST,
}],
benign_control: Some(PayloadRef {
label: "data-exfil-ruby-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"127.0.0.1",
label: "data-exfil-ruby-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::OutboundHostNotIn {
allowlist: ALLOWLIST,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/data_exfil/ruby/benign.rb"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,49 @@
//! rust `Cap::DATA_EXFIL` payloads.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
const ALLOWLIST: &[&str] = &["127.0.0.1", "localhost"];
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"attacker.test",
label: "data-exfil-rust-external",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::OutboundHostNotIn {
allowlist: ALLOWLIST,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/data_exfil/rust/vuln.rs"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::OutboundHostNotIn {
allowlist: ALLOWLIST,
}],
benign_control: Some(PayloadRef {
label: "data-exfil-rust-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"127.0.0.1",
label: "data-exfil-rust-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::OutboundHostNotIn {
allowlist: ALLOWLIST,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/data_exfil/rust/benign.rs"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,62 @@
//! Java `Cap::DESERIALIZE` payloads.
//!
//! Vuln payload: a base64-encoded `java.io.ObjectInputStream` byte stream
//! that materialises a gadget class outside the harness's allowlist.
//! The harness's `RestrictedObjectInputStream.resolveClass` intercepts
//! the lookup and emits a `ProbeKind::Deserialize { gadget_chain_invoked
//! = true }` probe before aborting the chain.
//!
//! Benign control: a base64-encoded `ObjectInputStream` byte stream of a
//! single allow-listed `java.lang.Integer`. The class lives inside the
//! resolveClass allowlist so no Deserialize probe is emitted.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
// Marker class name embedded in the serialized stream — the
// harness allowlist contains `java.lang.Integer` and `java.lang.String`
// only. The byte form is a small literal so const-eval can keep it.
bytes: b"NYX_GADGET_CLASS:org.nyx.deserialize.Gadget",
label: "java-deserialize-gadget",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::DeserializeGadgetInvoked {
require_invoked: true,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 7,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/deserialize/java/Vuln.java"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::DeserializeGadgetInvoked {
require_invoked: true,
}],
benign_control: Some(PayloadRef {
label: "java-deserialize-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
// Allow-listed payload — the marker carries `java.lang.Integer`,
// which the harness resolveClass accepts without writing a probe.
bytes: b"NYX_GADGET_CLASS:java.lang.Integer",
label: "java-deserialize-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::DeserializeGadgetInvoked {
require_invoked: true,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 7,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/deserialize/java/Benign.java"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,17 @@
//! Deserialization (`Cap::DESERIALIZE`) per-language payload slices.
//!
//! Phase 03 (Track J.1) lands the first cap end-to-end: Java
//! (`ObjectInputStream.readObject` / `XMLDecoder`), Python (`pickle.loads`
//! / `yaml.unsafe_load`), PHP (`unserialize`), and Ruby (`Marshal.load`
//! / `YAML.load`). Every vuln payload is paired with a benign control
//! whose oracle should *not* fire — the per-language harness shims
//! emit a [`crate::dynamic::probe::ProbeKind::Deserialize`] record with
//! `gadget_chain_invoked: true` when a non-allowlisted gadget class is
//! materialised by the instrumented deserialiser; benign well-formed
//! serialized data does not reach the allowlist boundary and so leaves
//! no Deserialize probe.
pub mod java;
pub mod php;
pub mod python;
pub mod ruby;

View file

@ -0,0 +1,60 @@
//! PHP `Cap::DESERIALIZE` payloads.
//!
//! Vuln payload: marker string handed to `unserialize($input)` where the
//! harness wraps the call with `['allowed_classes' => false]` and an
//! observer on `__wakeup`. When `unserialize` materialises a
//! `__PHP_Incomplete_Class` from a non-allowlisted class name, the
//! observer emits a `ProbeKind::Deserialize { gadget_chain_invoked:
//! true }` probe.
//!
//! Benign control: serialised primitive (an `int`) that
//! `unserialize` materialises without engaging the allowlist boundary.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"NYX_GADGET_CLASS:PHP_Object_Injection_RCE",
label: "php-unserialize-gadget",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::DeserializeGadgetInvoked {
require_invoked: true,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 7,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/deserialize/php/vuln.php"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::DeserializeGadgetInvoked {
require_invoked: true,
}],
benign_control: Some(PayloadRef {
label: "php-unserialize-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
// Allow-listed marker — the harness allowlist accepts
// `__primitive_int` as a no-op type representing a serialised
// integer literal.
bytes: b"NYX_GADGET_CLASS:__primitive_int",
label: "php-unserialize-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::DeserializeGadgetInvoked {
require_invoked: true,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 7,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/deserialize/php/benign.php"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,56 @@
//! Python `Cap::DESERIALIZE` payloads.
//!
//! Vuln payload: marker string consumed by the harness shim which calls
//! `pickle.Unpickler(...).load()` with `find_class` overridden to record
//! a `ProbeKind::Deserialize { gadget_chain_invoked: true }` whenever a
//! non-allowlisted class is requested. The harness allowlists
//! `builtins.list` / `builtins.dict` / `builtins.int`; the marker class
//! `nyx.gadget.RCE` is outside that set.
//!
//! Benign control: payload requests only allow-listed builtins.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"NYX_GADGET_CLASS:nyx.gadget.RCE",
label: "python-pickle-gadget",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::DeserializeGadgetInvoked {
require_invoked: true,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 7,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/deserialize/python/vuln.py"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::DeserializeGadgetInvoked {
require_invoked: true,
}],
benign_control: Some(PayloadRef {
label: "python-pickle-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"NYX_GADGET_CLASS:builtins.list",
label: "python-pickle-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::DeserializeGadgetInvoked {
require_invoked: true,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 7,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/deserialize/python/benign.py"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,57 @@
//! Ruby `Cap::DESERIALIZE` payloads.
//!
//! Vuln payload: marker string consumed by the harness shim which calls
//! `Marshal.load(input)` with `Marshal.const_defined?`-style
//! instrumentation that records a `ProbeKind::Deserialize {
//! gadget_chain_invoked: true }` probe whenever a non-allowlisted
//! constant is materialised. The harness allowlist contains `Integer`
//! / `String` / `Array`.
//!
//! Benign control: marker requests only the allow-listed `Integer`
//! constant.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"NYX_GADGET_CLASS:Nyx::Gadget::RCE",
label: "ruby-marshal-gadget",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::DeserializeGadgetInvoked {
require_invoked: true,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 7,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/deserialize/ruby/vuln.rb"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::DeserializeGadgetInvoked {
require_invoked: true,
}],
benign_control: Some(PayloadRef {
label: "ruby-marshal-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"NYX_GADGET_CLASS:Integer",
label: "ruby-marshal-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::DeserializeGadgetInvoked {
require_invoked: true,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 7,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/deserialize/ruby/benign.rb"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,56 @@
//! Format-string (`Cap::FMT_STRING`) payloads exercised by C fixtures
//! (`tests/dynamic_fixtures/c/free_fn/`).
//!
//! The vuln payload confirms via a sink-site Crash probe rather than an
//! output marker. The bytes themselves are not load-bearing — the
//! detection contract is "process aborts inside the entry call AFTER the
//! crash-guard installs". Fixtures choose how to crash on the payload;
//! the canonical example is a `printf`-family sink that interprets `%n`
//! against a controlled destination pointer on a guard-compiled binary.
//!
//! The benign control must reach the same entry without crashing; its
//! bytes carry `NYX_BENIGN` so fixture code can short-circuit before
//! the fault path.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::SignalSet;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"%n%n%n%n%n%n%n%n%n%n",
label: "fmt-string-percent-n-crash",
oracle: Oracle::SinkCrash {
signals: SignalSet::all(),
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 5,
deprecated_at_corpus_version: None,
fixture_paths: &[
"tests/dynamic_fixtures/c/free_fn/sink_fault.c",
"tests/dynamic_fixtures/c/free_fn/setup_fault.c",
],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: Some(PayloadRef {
label: "fmt-string-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"benign_safe_fmt_NYX_BENIGN",
label: "fmt-string-benign",
oracle: Oracle::SinkCrash {
signals: SignalSet::all(),
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 5,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/c/free_fn/sink_fault.c"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,3 @@
//! Format-string (`Cap::FMT_STRING`) per-language payload slices.
pub mod c;

View file

@ -0,0 +1,56 @@
//! Go `Cap::HEADER_INJECTION` payloads —
//! `http.ResponseWriter.Header().Set` CRLF injection.
//!
//! Vuln payload: a cookie value followed by `\r\nSet-Cookie:
//! nyx-injected=pwn`. Spliced into the host's `w.Header().Set("Set-
//! Cookie", value)` call without CRLF stripping.
//!
//! Benign control: same logical cookie value pre-encoded with
//! `net/url.QueryEscape`. Captured value carries `%0D%0A` so the
//! predicate stays clear.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"nyx-session\r\nSet-Cookie: nyx-injected=pwn",
label: "header-injection-go-crlf",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::HeaderInjected {
header_name: "Set-Cookie",
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 12,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/header_injection/go/vuln.go"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::HeaderInjected {
header_name: "Set-Cookie",
}],
benign_control: Some(PayloadRef {
label: "header-injection-go-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"nyx-session%0D%0ASet-Cookie%3A%20nyx-injected%3Dpwn",
label: "header-injection-go-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::HeaderInjected {
header_name: "Set-Cookie",
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 12,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/header_injection/go/benign.go"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,122 @@
//! Java `Cap::HEADER_INJECTION` payloads —
//! `HttpServletResponse.setHeader` CRLF injection.
//!
//! Vuln payload: a cookie value followed by `\r\nSet-Cookie:
//! nyx-injected=pwn`. Concatenated into the host's
//! `response.setHeader("Set-Cookie", value)` call without CRLF
//! stripping, the wire response carries the attacker's second
//! header. The harness's instrumented `setHeader` records a
//! `ProbeKind::HeaderEmit { name: "Set-Cookie", value: <raw bytes> }`
//! probe with the unescaped CRLF intact.
//!
//! Benign control: same logical session-id, but the harness's
//! benign code path runs the value through `URLEncoder.encode(...,
//! "UTF-8")` so the carried bytes become
//! `nyx-session%0D%0ASet-Cookie%3A%20nyx-injected%3Dpwn`. The
//! captured value has no literal `\r\n`; the
//! [`ProbePredicate::HeaderInjected`] predicate stays clear.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"nyx-session\r\nSet-Cookie: nyx-injected=pwn",
label: "header-injection-java-crlf",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::HeaderInjected {
header_name: "Set-Cookie",
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 12,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/header_injection/java/Vuln.java"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::HeaderInjected {
header_name: "Set-Cookie",
}],
benign_control: Some(PayloadRef {
label: "header-injection-java-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"nyx-session%0D%0ASet-Cookie%3A%20nyx-injected%3Dpwn",
label: "header-injection-java-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::HeaderInjected {
header_name: "Set-Cookie",
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 12,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/header_injection/java/Benign.java"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
// Phase 08 tier-(b): raw-socket wire-frame smuggling payload.
// Same CRLF-bearing bytes as the servlet payload above, but pinned
// to the `java_raw` fixture (a `java.net.ServerSocket` driven by
// `createServer` + `runOnce` that writes raw bytes via
// `OutputStream.write(byte[])`). The wire frame captured off the
// response socket carries two distinct `Set-Cookie:` lines, so
// `HeaderSmuggledInWire { primary: "Set-Cookie", smuggled:
// "Set-Cookie" }` fires — proving the smuggled header survived
// to the actual wire instead of being CRLF-stripped en route by
// Tomcat / Jetty / Undertow.
//
// Distinct payload (not just an extra predicate on the servlet
// row) because every modern Java servlet container response
// serializer strips CRLF at the wire-write boundary, so the
// wire-frame predicate would never fire against the canonical
// servlet fixture.
CuratedPayload {
bytes: b"nyx-session\r\nSet-Cookie: nyx-injected=pwn",
label: "header-injection-java-raw-wire-smuggle",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::HeaderSmuggledInWire {
primary: "Set-Cookie",
smuggled: "Set-Cookie",
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 12,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/header_injection/java_raw/Vuln.java"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::HeaderSmuggledInWire {
primary: "Set-Cookie",
smuggled: "Set-Cookie",
}],
benign_control: Some(PayloadRef {
label: "header-injection-java-raw-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"nyx-session%0D%0ASet-Cookie%3A%20nyx-injected%3Dpwn",
label: "header-injection-java-raw-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::HeaderSmuggledInWire {
primary: "Set-Cookie",
smuggled: "Set-Cookie",
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 12,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/header_injection/java_raw/Vuln.java"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,114 @@
//! JavaScript `Cap::HEADER_INJECTION` payloads —
//! `http.ServerResponse#setHeader` CRLF injection.
//!
//! Vuln payload: a cookie value followed by `\r\nSet-Cookie:
//! nyx-injected=pwn`. Spliced into the host's
//! `res.setHeader('Set-Cookie', value)` call without CRLF stripping.
//!
//! Benign control: same logical cookie value pre-encoded with
//! `encodeURIComponent`. Captured value carries `%0D%0A` so the
//! predicate stays clear.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"nyx-session\r\nSet-Cookie: nyx-injected=pwn",
label: "header-injection-js-crlf",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::HeaderInjected {
header_name: "Set-Cookie",
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 12,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/header_injection/js/vuln.js"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::HeaderInjected {
header_name: "Set-Cookie",
}],
benign_control: Some(PayloadRef {
label: "header-injection-js-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"nyx-session%0D%0ASet-Cookie%3A%20nyx-injected%3Dpwn",
label: "header-injection-js-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::HeaderInjected {
header_name: "Set-Cookie",
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 12,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/header_injection/js/benign.js"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
// Phase 08 tier-(b): raw-socket wire-frame smuggling payload.
// Same CRLF-bearing bytes as the Node payload above, but pinned to
// the `js_raw` fixture (a `net.createServer` callback writing raw
// bytes via `socket.write`). The wire frame captured off the
// response socket carries two distinct `Set-Cookie:` lines, so
// `HeaderSmuggledInWire { primary: "Set-Cookie", smuggled:
// "Set-Cookie" }` fires — proving the smuggled header survived to
// the actual wire instead of being CRLF-stripped en route.
//
// Distinct payload (not just an extra predicate on the Node row)
// because Node's `http.ServerResponse#setHeader` validator strips
// CRLF at the wire-write boundary, so the wire-frame predicate
// would never fire against the canonical Node fixture. See
// `.pitboss/play/deferred.md` (Phase 08 wire-frame option A) for
// the framework-level CRLF-strip empirical from session-0018.
CuratedPayload {
bytes: b"nyx-session\r\nSet-Cookie: nyx-injected=pwn",
label: "header-injection-js-raw-wire-smuggle",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::HeaderSmuggledInWire {
primary: "Set-Cookie",
smuggled: "Set-Cookie",
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 12,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/header_injection/js_raw/vuln.js"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::HeaderSmuggledInWire {
primary: "Set-Cookie",
smuggled: "Set-Cookie",
}],
benign_control: Some(PayloadRef {
label: "header-injection-js-raw-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"nyx-session%0D%0ASet-Cookie%3A%20nyx-injected%3Dpwn",
label: "header-injection-js-raw-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::HeaderSmuggledInWire {
primary: "Set-Cookie",
smuggled: "Set-Cookie",
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 12,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/header_injection/js_raw/vuln.js"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,31 @@
//! HTTP response-header CRLF injection (`Cap::HEADER_INJECTION`)
//! per-language payload slices.
//!
//! Phase 08 (Track J.6) carves header injection across the seven HTTP
//! framework ecosystems Nyx supports: Java (`HttpServletResponse.
//! setHeader`), Python (`flask.Response.headers.__setitem__`), PHP
//! (`header()`), Ruby (`Rack::Response#set_header`), JavaScript
//! (`http.ServerResponse#setHeader`), Go (`http.ResponseWriter.
//! Header().Set`), Rust (`axum`-style `HeaderMap::insert`). Every
//! vuln payload appends a `\r\n` followed by an injected header line
//! (`Set-Cookie: nyx-injected=pwn`) — once the host code splices the
//! attacker bytes into the response writer's value argument the wire
//! actually carries two headers instead of one. The paired benign
//! control passes the same logical value through the per-language URL
//! encoder so the captured value carries `%0d%0a` (not the raw
//! bytes), the encoded text is preserved verbatim inside a single
//! header value, and the differential rule stays clear.
//!
//! The oracle's
//! [`crate::dynamic::oracle::ProbePredicate::HeaderInjected`] reads
//! the per-payload `ProbeKind::HeaderEmit { name, value }` records
//! and fires when the value contains a literal CRLF byte pair —
//! vuln passes, benign clears, fulfilling the §4.1 differential rule.
pub mod go;
pub mod java;
pub mod js;
pub mod php;
pub mod python;
pub mod ruby;
pub mod rust;

View file

@ -0,0 +1,117 @@
//! PHP `Cap::HEADER_INJECTION` payloads — `header()` CRLF injection.
//!
//! Vuln payload: a cookie value followed by `\r\nSet-Cookie:
//! nyx-injected=pwn`. Concatenated into the host's `header("Set-
//! Cookie: " . $value)` call without CRLF stripping, the wire response
//! carries the attacker's second header. The harness's instrumented
//! `header()` records a `ProbeKind::HeaderEmit` probe with the
//! unescaped CRLF intact.
//!
//! Benign control: same logical cookie value pre-encoded with PHP's
//! `urlencode`. Captured value carries `%0D%0A` so the predicate
//! stays clear.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"nyx-session\r\nSet-Cookie: nyx-injected=pwn",
label: "header-injection-php-crlf",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::HeaderInjected {
header_name: "Set-Cookie",
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 12,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/header_injection/php/vuln.php"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::HeaderInjected {
header_name: "Set-Cookie",
}],
benign_control: Some(PayloadRef {
label: "header-injection-php-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"nyx-session%0D%0ASet-Cookie%3A%20nyx-injected%3Dpwn",
label: "header-injection-php-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::HeaderInjected {
header_name: "Set-Cookie",
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 12,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/header_injection/php/benign.php"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
// Phase 08 tier-(b): raw-socket wire-frame smuggling payload.
// Same CRLF-bearing bytes as the `header()` payload above, but
// pinned to the `php_raw` fixture (a `stream_socket_server` driven
// by `create_server` + `run_once` that writes raw bytes via
// `fwrite($conn, $raw)`). The wire frame captured off the
// response socket carries two distinct `Set-Cookie:` lines, so
// `HeaderSmuggledInWire { primary: "Set-Cookie", smuggled:
// "Set-Cookie" }` fires — proving the smuggled header survived to
// the actual wire instead of being CRLF-stripped en route.
//
// Distinct payload (not just an extra predicate on the `header()`
// row) because PHP's built-in `header()` rejects raw CRLF since
// 5.1.2 and modern Slim / Laravel / Symfony response serializers
// strip CRLF at the wire-write boundary, so the wire-frame
// predicate would never fire against the canonical `header()`
// fixture.
CuratedPayload {
bytes: b"nyx-session\r\nSet-Cookie: nyx-injected=pwn",
label: "header-injection-php-raw-wire-smuggle",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::HeaderSmuggledInWire {
primary: "Set-Cookie",
smuggled: "Set-Cookie",
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 12,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/header_injection/php_raw/vuln.php"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::HeaderSmuggledInWire {
primary: "Set-Cookie",
smuggled: "Set-Cookie",
}],
benign_control: Some(PayloadRef {
label: "header-injection-php-raw-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"nyx-session%0D%0ASet-Cookie%3A%20nyx-injected%3Dpwn",
label: "header-injection-php-raw-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::HeaderSmuggledInWire {
primary: "Set-Cookie",
smuggled: "Set-Cookie",
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 12,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/header_injection/php_raw/vuln.php"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,120 @@
//! Python `Cap::HEADER_INJECTION` payloads —
//! `flask.Response.headers.__setitem__` CRLF injection.
//!
//! Vuln payload: a session cookie value followed by `\r\nSet-Cookie:
//! nyx-injected=pwn`. Spliced into the host's
//! `response.headers["Set-Cookie"] = value` assignment without CRLF
//! stripping, the WSGI layer carries the attacker's second header on
//! the wire. The harness's instrumented response writer records a
//! `ProbeKind::HeaderEmit { name: "Set-Cookie", value: <raw bytes> }`
//! probe with the unescaped CRLF intact.
//!
//! Benign control: same logical cookie value pre-encoded with
//! `urllib.parse.quote`. The carried bytes become
//! `nyx-session%0D%0ASet-Cookie%3A%20nyx-injected%3Dpwn` — no literal
//! CRLF — and the [`ProbePredicate::HeaderInjected`] predicate stays
//! clear.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"nyx-session\r\nSet-Cookie: nyx-injected=pwn",
label: "header-injection-python-crlf",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::HeaderInjected {
header_name: "Set-Cookie",
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 12,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/header_injection/python/vuln.py"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::HeaderInjected {
header_name: "Set-Cookie",
}],
benign_control: Some(PayloadRef {
label: "header-injection-python-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"nyx-session%0D%0ASet-Cookie%3A%20nyx-injected%3Dpwn",
label: "header-injection-python-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::HeaderInjected {
header_name: "Set-Cookie",
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 12,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/header_injection/python/benign.py"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
// Phase 08 tier-(b): raw-socket wire-frame smuggling payload.
// Same CRLF-bearing bytes as the Flask payload above, but pinned
// to the `python_raw` fixture (a `BaseHTTPRequestHandler` writing
// raw bytes via `self.wfile.write`). The wire frame captured off
// the response socket carries two distinct `Set-Cookie:` lines, so
// `HeaderSmuggledInWire { primary: "Set-Cookie", smuggled:
// "Set-Cookie" }` fires — proving the smuggled header survived to
// the actual wire instead of being CRLF-stripped en route.
//
// Distinct payload (not just an extra predicate on the Flask row)
// because Flask's werkzeug response serializer strips CRLF at the
// wire-write boundary, so the wire-frame predicate would never
// fire against the canonical Flask fixture. See
// `.pitboss/play/deferred.md` (Phase 08 wire-frame option A) for
// the framework-level CRLF-strip empirical from session-0018.
CuratedPayload {
bytes: b"nyx-session\r\nSet-Cookie: nyx-injected=pwn",
label: "header-injection-python-raw-wire-smuggle",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::HeaderSmuggledInWire {
primary: "Set-Cookie",
smuggled: "Set-Cookie",
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 12,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/header_injection/python_raw/vuln.py"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::HeaderSmuggledInWire {
primary: "Set-Cookie",
smuggled: "Set-Cookie",
}],
benign_control: Some(PayloadRef {
label: "header-injection-python-raw-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"nyx-session%0D%0ASet-Cookie%3A%20nyx-injected%3Dpwn",
label: "header-injection-python-raw-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::HeaderSmuggledInWire {
primary: "Set-Cookie",
smuggled: "Set-Cookie",
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 12,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/header_injection/python_raw/vuln.py"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,114 @@
//! Ruby `Cap::HEADER_INJECTION` payloads —
//! `Rack::Response#set_header` CRLF injection.
//!
//! Vuln payload: a cookie value followed by `\r\nSet-Cookie:
//! nyx-injected=pwn`. Spliced into the host's
//! `response.set_header("Set-Cookie", value)` call without CRLF
//! stripping, the wire response carries the attacker's second header.
//!
//! Benign control: same logical cookie value pre-encoded with
//! `URI.encode_www_form_component`. Captured value carries `%0D%0A`
//! so the predicate stays clear.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"nyx-session\r\nSet-Cookie: nyx-injected=pwn",
label: "header-injection-ruby-crlf",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::HeaderInjected {
header_name: "Set-Cookie",
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 12,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/header_injection/ruby/vuln.rb"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::HeaderInjected {
header_name: "Set-Cookie",
}],
benign_control: Some(PayloadRef {
label: "header-injection-ruby-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"nyx-session%0D%0ASet-Cookie%3A%20nyx-injected%3Dpwn",
label: "header-injection-ruby-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::HeaderInjected {
header_name: "Set-Cookie",
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 12,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/header_injection/ruby/benign.rb"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
// Phase 08 tier-(b): raw-socket wire-frame smuggling payload.
// Same CRLF-bearing bytes as the Rack payload above, but pinned to
// the `ruby_raw` fixture (a `TCPServer` driven by `create_server`
// + `run_once` that writes raw bytes via `TCPSocket#write`). The
// wire frame captured off the response socket carries two
// distinct `Set-Cookie:` lines, so `HeaderSmuggledInWire { primary:
// "Set-Cookie", smuggled: "Set-Cookie" }` fires — proving the
// smuggled header survived to the actual wire instead of being
// CRLF-stripped en route.
//
// Distinct payload (not just an extra predicate on the Rack row)
// because Rack / Sinatra / Rails response serializers strip CRLF
// at the wire-write boundary, so the wire-frame predicate would
// never fire against the canonical Rack fixture.
CuratedPayload {
bytes: b"nyx-session\r\nSet-Cookie: nyx-injected=pwn",
label: "header-injection-ruby-raw-wire-smuggle",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::HeaderSmuggledInWire {
primary: "Set-Cookie",
smuggled: "Set-Cookie",
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 12,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/header_injection/ruby_raw/vuln.rb"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::HeaderSmuggledInWire {
primary: "Set-Cookie",
smuggled: "Set-Cookie",
}],
benign_control: Some(PayloadRef {
label: "header-injection-ruby-raw-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"nyx-session%0D%0ASet-Cookie%3A%20nyx-injected%3Dpwn",
label: "header-injection-ruby-raw-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::HeaderSmuggledInWire {
primary: "Set-Cookie",
smuggled: "Set-Cookie",
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 12,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/header_injection/ruby_raw/vuln.rb"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,116 @@
//! Rust `Cap::HEADER_INJECTION` payloads — `axum`-style
//! `HeaderMap::insert` CRLF injection.
//!
//! Vuln payload: a cookie value followed by `\r\nSet-Cookie:
//! nyx-injected=pwn`. Spliced into a hand-rolled `HeaderMap` insert
//! that bypasses the `HeaderValue::from_str` validity check (e.g.
//! `HeaderValue::from_bytes(...).unwrap()` over a tainted slice).
//!
//! Benign control: same logical cookie value pre-encoded with the
//! `percent-encoding` crate. Captured value carries `%0D%0A` so the
//! predicate stays clear.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"nyx-session\r\nSet-Cookie: nyx-injected=pwn",
label: "header-injection-rust-crlf",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::HeaderInjected {
header_name: "Set-Cookie",
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 12,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/header_injection/rust/vuln.rs"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::HeaderInjected {
header_name: "Set-Cookie",
}],
benign_control: Some(PayloadRef {
label: "header-injection-rust-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"nyx-session%0D%0ASet-Cookie%3A%20nyx-injected%3Dpwn",
label: "header-injection-rust-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::HeaderInjected {
header_name: "Set-Cookie",
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 12,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/header_injection/rust/benign.rs"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
// Phase 08 tier-(b): raw-socket wire-frame smuggling payload.
// Same CRLF-bearing bytes as the axum payload above, but pinned to
// the `rust_raw` fixture (a `std::net::TcpListener` driven by
// `create_server` + `run_once` that writes raw bytes via
// `TcpStream::write_all`). The wire frame captured off the
// response socket carries two distinct `Set-Cookie:` lines, so
// `HeaderSmuggledInWire { primary: "Set-Cookie", smuggled:
// "Set-Cookie" }` fires — proving the smuggled header survived to
// the actual wire instead of being CRLF-stripped en route.
//
// Distinct payload (not just an extra predicate on the axum row)
// because every framework's response serializer strips CRLF at
// the wire-write boundary, so the wire-frame predicate would
// never fire against the canonical axum fixture. See
// `.pitboss/play/deferred.md` (Phase 08 wire-frame option A) for
// the framework-level CRLF-strip empirical from session-0018.
CuratedPayload {
bytes: b"nyx-session\r\nSet-Cookie: nyx-injected=pwn",
label: "header-injection-rust-raw-wire-smuggle",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::HeaderSmuggledInWire {
primary: "Set-Cookie",
smuggled: "Set-Cookie",
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 12,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/header_injection/rust_raw/vuln.rs"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::HeaderSmuggledInWire {
primary: "Set-Cookie",
smuggled: "Set-Cookie",
}],
benign_control: Some(PayloadRef {
label: "header-injection-rust-raw-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"nyx-session%0D%0ASet-Cookie%3A%20nyx-injected%3Dpwn",
label: "header-injection-rust-raw-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::HeaderSmuggledInWire {
primary: "Set-Cookie",
smuggled: "Set-Cookie",
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 12,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/header_injection/rust_raw/vuln.rs"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,54 @@
//! Go `Cap::JSON_PARSE` payloads.
//!
//! The depth pair shares a single fixture; the payload tag
//! (`NYX_JSON_DEEP` vs `NYX_JSON_SHALLOW`) picks the branch. Go has
//! no prototype-pollution surface so the canary half of the slice is
//! intentionally omitted.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
const MAX_DEPTH: u32 = 64;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"NYX_JSON_DEEP",
label: "json-parse-go-depth-bomb",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::JsonParseExcessiveDepth {
max_depth: MAX_DEPTH,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/json_parse_depth/go/vuln.go"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::JsonParseExcessiveDepth {
max_depth: MAX_DEPTH,
}],
benign_control: Some(PayloadRef {
label: "json-parse-go-depth-shallow",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"NYX_JSON_SHALLOW",
label: "json-parse-go-depth-shallow",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::JsonParseExcessiveDepth {
max_depth: MAX_DEPTH,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/json_parse_depth/go/vuln.go"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,59 @@
//! Java `Cap::JSON_PARSE` payloads.
//!
//! The depth pair shares a single fixture; the payload tag
//! (`NYX_JSON_DEEP` vs `NYX_JSON_SHALLOW`) picks the branch. Java has
//! no prototype-pollution surface so the canary half of the slice is
//! intentionally omitted, matching the PHP / Go / Rust shape.
//!
//! Java has no stdlib JSON parser, so the harness ships a hand-rolled
//! iterative JSON walker as a sibling class (`NyxJsonProbe.java`); the
//! fixture calls `NyxJsonProbe.parse(text)` in place of any Jackson /
//! Gson dependency so the build path never reaches for an external jar.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
const MAX_DEPTH: u32 = 64;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"NYX_JSON_DEEP",
label: "json-parse-java-depth-bomb",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::JsonParseExcessiveDepth {
max_depth: MAX_DEPTH,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/json_parse_depth/java/Vuln.java"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::JsonParseExcessiveDepth {
max_depth: MAX_DEPTH,
}],
benign_control: Some(PayloadRef {
label: "json-parse-java-depth-shallow",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"NYX_JSON_SHALLOW",
label: "json-parse-java-depth-shallow",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::JsonParseExcessiveDepth {
max_depth: MAX_DEPTH,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/json_parse_depth/java/Vuln.java"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,93 @@
//! JavaScript `Cap::JSON_PARSE` payloads.
//!
//! Covers two oracle shapes: the prototype-canary pair reuses the
//! Phase 10 PROTOTYPE_POLLUTION canary
//! ([`crate::dynamic::oracle::ProbePredicate::PrototypeCanaryTouched`])
//! against a `JSON.parse`-then-deep-merge fixture, and the depth-bomb
//! pair drives `JSON.parse` past the 64-level depth budget for the
//! [`crate::dynamic::oracle::ProbePredicate::JsonParseExcessiveDepth`]
//! oracle. The depth pair shares a single fixture; the payload tag
//! (`NYX_JSON_DEEP` vs `NYX_JSON_SHALLOW`) picks the branch.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::{Canary, ProbePredicate};
const CANARY: &str = Canary::PLACEHOLDER;
const MAX_DEPTH: u32 = 64;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: br#"{"__proto__":{"__nyx_canary":"pwned"}}"#,
label: "json-parse-js-proto-key",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::PrototypeCanaryTouched { canary: CANARY }],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/json_parse/javascript/vuln.js"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::PrototypeCanaryTouched { canary: CANARY }],
benign_control: Some(PayloadRef {
label: "json-parse-js-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: br#"{"data":{"__nyx_canary":"pwned"}}"#,
label: "json-parse-js-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::PrototypeCanaryTouched { canary: CANARY }],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/json_parse/javascript/benign.js"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"NYX_JSON_DEEP",
label: "json-parse-js-depth-bomb",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::JsonParseExcessiveDepth {
max_depth: MAX_DEPTH,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/json_parse_depth/javascript/vuln.js"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::JsonParseExcessiveDepth {
max_depth: MAX_DEPTH,
}],
benign_control: Some(PayloadRef {
label: "json-parse-js-depth-shallow",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"NYX_JSON_SHALLOW",
label: "json-parse-js-depth-shallow",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::JsonParseExcessiveDepth {
max_depth: MAX_DEPTH,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/json_parse_depth/javascript/vuln.js"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,25 @@
//! JSON-parse pollution (`Cap::JSON_PARSE`) per-language payload
//! slices.
//!
//! Phase 11 (Track J.9) reuses the prototype-canary oracle from
//! Phase 10 across the three languages whose JSON parsers have a
//! published pollution surface: JavaScript (`JSON.parse` then deep
//! assign), Python (`json.loads` then `dict.update` /
//! `setattr`-driven attribute pollution), Ruby (`JSON.parse` then
//! recursive merge). Every vuln payload binds a JSON literal whose
//! top-level key is `__proto__`; the per-language harness's
//! instrumented canary trap (`Object.prototype.__nyx_canary` in JS,
//! a `dict`/class-scoped sentinel in Python, an `Object.prepend`
//! flag in Ruby) records a
//! [`crate::dynamic::probe::ProbeKind::PrototypePollution`] probe
//! once the malicious key reaches the shared chain. The paired
//! benign control sends a JSON literal whose top-level key is the
//! regular property `data`, leaving the chain untouched.
pub mod go;
pub mod java;
pub mod javascript;
pub mod php;
pub mod python;
pub mod ruby;
pub mod rust;

View file

@ -0,0 +1,54 @@
//! PHP `Cap::JSON_PARSE` payloads.
//!
//! The depth pair shares a single fixture; the payload tag
//! (`NYX_JSON_DEEP` vs `NYX_JSON_SHALLOW`) picks the branch. PHP has
//! no prototype-pollution surface so the canary half of the slice is
//! intentionally omitted.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
const MAX_DEPTH: u32 = 64;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"NYX_JSON_DEEP",
label: "json-parse-php-depth-bomb",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::JsonParseExcessiveDepth {
max_depth: MAX_DEPTH,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/json_parse_depth/php/vuln.php"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::JsonParseExcessiveDepth {
max_depth: MAX_DEPTH,
}],
benign_control: Some(PayloadRef {
label: "json-parse-php-depth-shallow",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"NYX_JSON_SHALLOW",
label: "json-parse-php-depth-shallow",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::JsonParseExcessiveDepth {
max_depth: MAX_DEPTH,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/json_parse_depth/php/vuln.php"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,88 @@
//! Python `Cap::JSON_PARSE` payloads.
//!
//! The canary cases cover pollution-style parses. The depth cases drive
//! `json.loads` past the depth oracle while sharing one fixture for the
//! vulnerable and benign attempts.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::{Canary, ProbePredicate};
const CANARY: &str = Canary::PLACEHOLDER;
const MAX_DEPTH: u32 = 64;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: br#"{"__proto__":{"__nyx_canary":"pwned"}}"#,
label: "json-parse-python-proto-key",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::PrototypeCanaryTouched { canary: CANARY }],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/json_parse/python/vuln.py"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::PrototypeCanaryTouched { canary: CANARY }],
benign_control: Some(PayloadRef {
label: "json-parse-python-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: br#"{"data":{"__nyx_canary":"pwned"}}"#,
label: "json-parse-python-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::PrototypeCanaryTouched { canary: CANARY }],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/json_parse/python/benign.py"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"NYX_JSON_DEEP",
label: "json-parse-python-depth-bomb",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::JsonParseExcessiveDepth {
max_depth: MAX_DEPTH,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/json_parse_depth/python/vuln.py"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::JsonParseExcessiveDepth {
max_depth: MAX_DEPTH,
}],
benign_control: Some(PayloadRef {
label: "json-parse-python-depth-shallow",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"NYX_JSON_SHALLOW",
label: "json-parse-python-depth-shallow",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::JsonParseExcessiveDepth {
max_depth: MAX_DEPTH,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/json_parse_depth/python/vuln.py"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,92 @@
//! Ruby `Cap::JSON_PARSE` payloads.
//!
//! Covers two oracle shapes: the prototype-canary pair reuses the
//! Phase 10 PROTOTYPE_POLLUTION canary against a `JSON.parse` then
//! recursive `Hash#deep_merge!` fixture, and the depth-bomb pair
//! drives `JSON.parse` past the 64-level depth budget for the
//! [`crate::dynamic::oracle::ProbePredicate::JsonParseExcessiveDepth`]
//! oracle. The depth pair shares a single fixture; the payload tag
//! (`NYX_JSON_DEEP` vs `NYX_JSON_SHALLOW`) picks the branch.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::{Canary, ProbePredicate};
const CANARY: &str = Canary::PLACEHOLDER;
const MAX_DEPTH: u32 = 64;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: br#"{"__proto__":{"__nyx_canary":"pwned"}}"#,
label: "json-parse-ruby-proto-key",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::PrototypeCanaryTouched { canary: CANARY }],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/json_parse/ruby/vuln.rb"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::PrototypeCanaryTouched { canary: CANARY }],
benign_control: Some(PayloadRef {
label: "json-parse-ruby-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: br#"{"data":{"__nyx_canary":"pwned"}}"#,
label: "json-parse-ruby-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::PrototypeCanaryTouched { canary: CANARY }],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/json_parse/ruby/benign.rb"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"NYX_JSON_DEEP",
label: "json-parse-ruby-depth-bomb",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::JsonParseExcessiveDepth {
max_depth: MAX_DEPTH,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/json_parse_depth/ruby/vuln.rb"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::JsonParseExcessiveDepth {
max_depth: MAX_DEPTH,
}],
benign_control: Some(PayloadRef {
label: "json-parse-ruby-depth-shallow",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"NYX_JSON_SHALLOW",
label: "json-parse-ruby-depth-shallow",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::JsonParseExcessiveDepth {
max_depth: MAX_DEPTH,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/json_parse_depth/ruby/vuln.rb"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,54 @@
//! Rust `Cap::JSON_PARSE` payloads.
//!
//! The depth pair shares a single fixture; the payload tag
//! (`NYX_JSON_DEEP` vs `NYX_JSON_SHALLOW`) picks the branch. Rust has
//! no prototype-pollution surface so the canary half of the slice is
//! intentionally omitted.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
const MAX_DEPTH: u32 = 64;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"NYX_JSON_DEEP",
label: "json-parse-rust-depth-bomb",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::JsonParseExcessiveDepth {
max_depth: MAX_DEPTH,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/json_parse_depth/rust/vuln.rs"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::JsonParseExcessiveDepth {
max_depth: MAX_DEPTH,
}],
benign_control: Some(PayloadRef {
label: "json-parse-rust-depth-shallow",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"NYX_JSON_SHALLOW",
label: "json-parse-rust-depth-shallow",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::JsonParseExcessiveDepth {
max_depth: MAX_DEPTH,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/json_parse_depth/rust/vuln.rs"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,53 @@
//! Java `Cap::LDAP_INJECTION` payloads — `LdapTemplate.search` /
//! `DirContext.search` filter injection.
//!
//! Vuln payload: a filter fragment whose `*)(uid=*` tail breaks out of
//! the host template's `(uid=…)` clause and rewraps the search as
//! `(|(uid=…)(uid=*))`, matching every user the directory carries.
//! The harness's instrumented LDAP client (talking to
//! [`crate::dynamic::stubs::ldap_server`]) records
//! `ProbeKind::Ldap { entries_returned: 3 }`.
//!
//! Benign control: the same intended username quoted through
//! `EscapeDN` so the LDAP filter stays pinned to a single entry; the
//! shim records `entries_returned: 1` and the oracle does not fire.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"alice*)(uid=*",
label: "ldap-java-filter-wildcard",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::QueryResultCountGreaterThan { n: 1 }],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 10,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/ldap_injection/java/Vuln.java"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::QueryResultCountGreaterThan { n: 1 }],
benign_control: Some(PayloadRef {
label: "ldap-java-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"alice",
label: "ldap-java-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::QueryResultCountGreaterThan { n: 1 }],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 10,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/ldap_injection/java/Benign.java"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,30 @@
//! LDAP filter injection (`Cap::LDAP_INJECTION`) per-language payload
//! slices.
//!
//! Phase 06 (Track J.4) carves LDAP filter injection across the three
//! most-common directory clients: Java (`LdapTemplate.search` /
//! `DirContext.search`), Python (`ldap.search_s`), and PHP
//! (`ldap_search`). Every vuln payload appends the canonical
//! `*)(uid=*` quote-escape break — once the host code substitutes the
//! attacker bytes into its filter template the synthesized LDAP
//! filter matches every entry the directory carries (the
//! [`crate::dynamic::stubs::ldap_server`] stub returns its three
//! provisioned users). The paired benign control quotes the same
//! bytes through `EscapeDN` / `ldap.dn.escape_filter_chars` /
//! `ldap_escape`, leaving the filter pinned to the originally
//! intended single user.
//!
//! The oracle's
//! [`crate::dynamic::oracle::ProbePredicate::QueryResultCountGreaterThan`]
//! checks the per-payload `ProbeKind::Ldap.entries_returned` against
//! `n = 1` — vuln passes (3 entries), benign clears (1 entry),
//! fulfilling the §4.1 differential rule.
//!
//! C# is intentionally omitted: the [`crate::symbol::Lang`] enum has
//! no `CSharp` variant, so the corpus has nowhere to register it.
//! Tracked in `.pitboss/play/deferred.md` alongside the Phase 05
//! Lang::CSharp gap.
pub mod java;
pub mod php;
pub mod python;

View file

@ -0,0 +1,51 @@
//! PHP `Cap::LDAP_INJECTION` payloads — `ldap_search` filter injection.
//!
//! Vuln payload: a filter fragment whose `*)(uid=*` tail breaks out of
//! the host template's `(uid=…)` clause; the synthesized filter
//! becomes `(|(uid=…)(uid=*))` and matches every directory entry.
//! The harness's instrumented `ldap_search` records
//! `ProbeKind::Ldap { entries_returned: 3 }`.
//!
//! Benign control: the same intended username quoted via
//! `ldap_escape($value, "", LDAP_ESCAPE_FILTER)` — `entries_returned:
//! 1`, oracle clear.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"alice*)(uid=*",
label: "ldap-php-filter-wildcard",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::QueryResultCountGreaterThan { n: 1 }],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 10,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/ldap_injection/php/vuln.php"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::QueryResultCountGreaterThan { n: 1 }],
benign_control: Some(PayloadRef {
label: "ldap-php-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"alice",
label: "ldap-php-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::QueryResultCountGreaterThan { n: 1 }],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 10,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/ldap_injection/php/benign.php"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,52 @@
//! Python `Cap::LDAP_INJECTION` payloads — `ldap.search_s` filter
//! injection.
//!
//! Vuln payload: a filter fragment whose `*)(uid=*` tail breaks out of
//! the host template's `(uid=…)` clause; the synthesized filter
//! becomes `(|(uid=…)(uid=*))` and matches every directory entry.
//! The harness's instrumented `ldap.search_s` records
//! `ProbeKind::Ldap { entries_returned: 3 }`.
//!
//! Benign control: the same intended username quoted via
//! `ldap.dn.escape_filter_chars`, leaving the filter pinned to a
//! single entry — `entries_returned: 1`, oracle clear.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"alice*)(uid=*",
label: "ldap-python-filter-wildcard",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::QueryResultCountGreaterThan { n: 1 }],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 10,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/ldap_injection/python/vuln.py"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::QueryResultCountGreaterThan { n: 1 }],
benign_control: Some(PayloadRef {
label: "ldap-python-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"alice",
label: "ldap-python-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::QueryResultCountGreaterThan { n: 1 }],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 10,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/ldap_injection/python/benign.py"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,89 @@
//! Go `Cap::OPEN_REDIRECT` payloads — `gin.Context.Redirect` /
//! `http.Redirect` off-origin redirect.
//!
//! Vuln payload: an absolute attacker URL spliced into
//! `c.Redirect(http.StatusFound, value)` (or
//! `http.Redirect(w, r, value, ...)`) without host validation; the
//! harness records a `ProbeKind::Redirect` probe whose `location`
//! points off-origin.
//!
//! Benign control: same shape but redirects to the same-origin path
//! `/dashboard`, so the captured `location` has no authority
//! component and the predicate stays clear.
//!
//! OOB-nonce variant (added 2026-05-22): when the runner attaches an
//! [`crate::dynamic::oob::OobListener`] the harness follows the
//! captured `Location:` URL via a real `net/http.Get` against the
//! loopback nonce URL so the listener records the per-finding
//! callback. Ordered first so the runner exercises the OOB observation
//! path before the absolute-URL vuln below triggers and short-circuits
//! iteration; runs without a listener skip cleanly (runner
//! `oob_nonce_slot` branch).
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
const ALLOWLIST: &[&str] = &["example.com"];
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
// `bytes` is unused when `oob_nonce_slot = true`; the runner
// substitutes a per-finding loopback URL (see runner.rs:405-413).
bytes: b"",
label: "open-redirect-go-oob-nonce",
oracle: Oracle::OobCallback { host: "127.0.0.1" },
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/open_redirect/go/vuln.go"],
oob_nonce_slot: true,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: Some(
"OOB-nonce open-redirect payload self-confirms via the per-finding listener \
callback when the harness follows the captured Location URL with net/http.Get; \
no benign URL can hit the nonce path.",
),
},
CuratedPayload {
bytes: b"https://attacker.test/",
label: "open-redirect-go-absolute",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::RedirectHostNotIn {
allowlist: ALLOWLIST,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 13,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/open_redirect/go/vuln.go"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::RedirectHostNotIn {
allowlist: ALLOWLIST,
}],
benign_control: Some(PayloadRef {
label: "open-redirect-go-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"/dashboard",
label: "open-redirect-go-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::RedirectHostNotIn {
allowlist: ALLOWLIST,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 13,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/open_redirect/go/benign.go"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,94 @@
//! Java `Cap::OPEN_REDIRECT` payloads —
//! `HttpServletResponse.sendRedirect` off-origin redirect.
//!
//! Vuln payload: a fully-qualified attacker URL
//! (`https://attacker.test/`). Spliced into the host's
//! `response.sendRedirect(value)` call without host validation, the
//! servlet response's `Location:` header points off-origin. The
//! harness's instrumented `sendRedirect` shim records a
//! `ProbeKind::Redirect { location: <raw>, request_host:
//! "example.com" }` probe; the predicate
//! [`crate::dynamic::oracle::ProbePredicate::RedirectHostNotIn`] sees
//! the off-allowlist host and fires.
//!
//! Benign control: same logical entry point, but the harness's benign
//! code path redirects to the relative path `/dashboard` (no host
//! component). The captured `location` has no off-origin authority
//! and the predicate stays clear.
//!
//! OOB-nonce variant (added 2026-05-22): when the runner attaches an
//! [`crate::dynamic::oob::OobListener`] the harness follows the
//! captured `Location:` URL via a real `HttpURLConnection.getInputStream()`
//! against the loopback nonce URL so the listener records the per-finding
//! callback. Ordered first so the runner exercises the OOB observation
//! path before the absolute-URL vuln below triggers and short-circuits
//! iteration; runs without a listener skip cleanly (runner
//! `oob_nonce_slot` branch).
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
const ALLOWLIST: &[&str] = &["example.com"];
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
// `bytes` is unused when `oob_nonce_slot = true`; the runner
// substitutes a per-finding loopback URL (see runner.rs:405-413).
bytes: b"",
label: "open-redirect-java-oob-nonce",
oracle: Oracle::OobCallback { host: "127.0.0.1" },
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/open_redirect/java/Vuln.java"],
oob_nonce_slot: true,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: Some(
"OOB-nonce open-redirect payload self-confirms via the per-finding listener \
callback when the harness follows the captured Location URL with \
HttpURLConnection.getInputStream; no benign URL can hit the nonce path.",
),
},
CuratedPayload {
bytes: b"https://attacker.test/",
label: "open-redirect-java-absolute",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::RedirectHostNotIn {
allowlist: ALLOWLIST,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 13,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/open_redirect/java/Vuln.java"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::RedirectHostNotIn {
allowlist: ALLOWLIST,
}],
benign_control: Some(PayloadRef {
label: "open-redirect-java-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"/dashboard",
label: "open-redirect-java-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::RedirectHostNotIn {
allowlist: ALLOWLIST,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 13,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/open_redirect/java/Benign.java"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,87 @@
//! JavaScript `Cap::OPEN_REDIRECT` payloads —
//! Express `res.redirect` off-origin redirect.
//!
//! Vuln payload: an absolute attacker URL spliced into
//! `res.redirect(value)` without host validation; the harness
//! records a `ProbeKind::Redirect` probe whose `location` points
//! off-origin.
//!
//! Benign control: same shape but redirects to the same-origin path
//! `/dashboard`, so the captured `location` has no authority
//! component and the predicate stays clear.
//!
//! OOB-nonce variant (added 2026-05-22): when the runner attaches an
//! [`crate::dynamic::oob::OobListener`] the harness follows the
//! captured `Location:` URL via a real `http.get` against the loopback
//! nonce URL so the listener records the per-finding callback. Ordered
//! first so the runner exercises the OOB observation path before the
//! absolute-URL vuln below triggers and short-circuits iteration; runs
//! without a listener skip cleanly (runner `oob_nonce_slot` branch).
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
const ALLOWLIST: &[&str] = &["example.com"];
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
// `bytes` is unused when `oob_nonce_slot = true`; the runner
// substitutes a per-finding loopback URL (see runner.rs:405-413).
bytes: b"",
label: "open-redirect-js-oob-nonce",
oracle: Oracle::OobCallback { host: "127.0.0.1" },
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/open_redirect/js/vuln.js"],
oob_nonce_slot: true,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: Some(
"OOB-nonce open-redirect payload self-confirms via the per-finding listener \
callback when the harness follows the captured Location URL with http.get; \
no benign URL can hit the nonce path.",
),
},
CuratedPayload {
bytes: b"https://attacker.test/",
label: "open-redirect-js-absolute",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::RedirectHostNotIn {
allowlist: ALLOWLIST,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 13,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/open_redirect/js/vuln.js"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::RedirectHostNotIn {
allowlist: ALLOWLIST,
}],
benign_control: Some(PayloadRef {
label: "open-redirect-js-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"/dashboard",
label: "open-redirect-js-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::RedirectHostNotIn {
allowlist: ALLOWLIST,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 13,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/open_redirect/js/benign.js"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,26 @@
//! Open-redirect (`Cap::OPEN_REDIRECT`) per-language payload slices.
//!
//! Phase 09 (Track J.7) carves open redirects across the seven HTTP
//! framework ecosystems Nyx supports: Java
//! (`HttpServletResponse.sendRedirect`), Python (`flask.redirect`),
//! PHP (Symfony `Response::redirect` / Slim `Response::withHeader`),
//! Ruby (`Rack::Response#redirect`), JavaScript (Express
//! `res.redirect`), Go (`gin.Context.Redirect`), Rust (`axum::response::
//! Redirect::to`). Every vuln payload binds an absolute attacker URL
//! (`https://attacker.test/`) into the response writer's redirect
//! entry point; the paired benign control redirects to a same-origin
//! path (`/dashboard`). The harness's instrumented redirect shim
//! records a [`crate::dynamic::probe::ProbeKind::Redirect { location,
//! request_host }`] probe with the unmodified location and the
//! request's origin host, and the
//! [`crate::dynamic::oracle::ProbePredicate::RedirectHostNotIn`]
//! predicate fires when the captured `location` resolves off-origin
//! relative to `allowlist {request_host}`.
pub mod go;
pub mod java;
pub mod js;
pub mod php;
pub mod python;
pub mod ruby;
pub mod rust;

View file

@ -0,0 +1,92 @@
//! PHP `Cap::OPEN_REDIRECT` payloads — `Response::redirect` /
//! Symfony `RedirectResponse(...)` off-origin redirect.
//!
//! Vuln payload: an absolute attacker URL passed to
//! `header("Location: $value")` or
//! `new \Symfony\Component\HttpFoundation\RedirectResponse($value)`
//! without host validation. The harness records a
//! `ProbeKind::Redirect { location, request_host }` probe and the
//! predicate fires on the off-allowlist host.
//!
//! Benign control: same shape but redirects to the same-origin path
//! `/dashboard`, so the captured `location` has no authority
//! component and the predicate stays clear.
//!
//! OOB-nonce variant (added 2026-05-22): when the runner attaches an
//! [`crate::dynamic::oob::OobListener`] the harness follows the
//! captured `Location:` URL via a real
//! `file_get_contents($location, stream_context_create(...))` against
//! the loopback nonce URL so the listener records the per-finding
//! callback. Ordered first so the runner exercises the OOB observation
//! path before the absolute-URL vuln below triggers and short-circuits
//! iteration; runs without a listener skip cleanly (runner
//! `oob_nonce_slot` branch).
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
const ALLOWLIST: &[&str] = &["example.com"];
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
// `bytes` is unused when `oob_nonce_slot = true`; the runner
// substitutes a per-finding loopback URL (see runner.rs:405-413).
bytes: b"",
label: "open-redirect-php-oob-nonce",
oracle: Oracle::OobCallback { host: "127.0.0.1" },
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/open_redirect/php/vuln.php"],
oob_nonce_slot: true,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: Some(
"OOB-nonce open-redirect payload self-confirms via the per-finding listener \
callback when the harness follows the captured Location URL with \
file_get_contents under a stream context timeout; no benign URL can hit \
the nonce path.",
),
},
CuratedPayload {
bytes: b"https://attacker.test/",
label: "open-redirect-php-absolute",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::RedirectHostNotIn {
allowlist: ALLOWLIST,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 13,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/open_redirect/php/vuln.php"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::RedirectHostNotIn {
allowlist: ALLOWLIST,
}],
benign_control: Some(PayloadRef {
label: "open-redirect-php-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"/dashboard",
label: "open-redirect-php-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::RedirectHostNotIn {
allowlist: ALLOWLIST,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 13,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/open_redirect/php/benign.php"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,89 @@
//! Python `Cap::OPEN_REDIRECT` payloads — `flask.redirect`
//! off-origin redirect.
//!
//! Vuln payload: an attacker-controlled absolute URL spliced into
//! `flask.redirect(value)` without host validation; the captured
//! `Location:` header points off-origin and the
//! [`crate::dynamic::oracle::ProbePredicate::RedirectHostNotIn`]
//! predicate fires.
//!
//! Benign control: same shape but redirects to the relative path
//! `/dashboard`, so the captured location has no authority component
//! and the predicate stays clear.
//!
//! OOB-nonce variant (added 2026-05-22): when the runner attaches an
//! [`crate::dynamic::oob::OobListener`] the harness follows the
//! captured `Location:` URL via a real `urllib.request.urlopen`
//! against the loopback nonce URL so the listener records the per-finding
//! callback. Ordered first so the runner exercises the OOB observation
//! path before the absolute-URL vuln below triggers and short-circuits
//! iteration; runs without a listener skip cleanly (runner
//! `oob_nonce_slot` branch).
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
const ALLOWLIST: &[&str] = &["example.com"];
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
// `bytes` is unused when `oob_nonce_slot = true`; the runner
// substitutes a per-finding loopback URL (see runner.rs:405-413).
bytes: b"",
label: "open-redirect-python-oob-nonce",
oracle: Oracle::OobCallback { host: "127.0.0.1" },
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/open_redirect/python/vuln.py"],
oob_nonce_slot: true,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: Some(
"OOB-nonce open-redirect payload self-confirms via the per-finding listener \
callback when the harness follows the captured Location URL with \
urllib.request.urlopen; no benign URL can hit the nonce path.",
),
},
CuratedPayload {
bytes: b"https://attacker.test/",
label: "open-redirect-python-absolute",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::RedirectHostNotIn {
allowlist: ALLOWLIST,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 13,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/open_redirect/python/vuln.py"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::RedirectHostNotIn {
allowlist: ALLOWLIST,
}],
benign_control: Some(PayloadRef {
label: "open-redirect-python-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"/dashboard",
label: "open-redirect-python-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::RedirectHostNotIn {
allowlist: ALLOWLIST,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 13,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/open_redirect/python/benign.py"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,88 @@
//! Ruby `Cap::OPEN_REDIRECT` payloads —
//! `Rack::Response#redirect` off-origin redirect.
//!
//! Vuln payload: an absolute attacker URL spliced into
//! `response.redirect(value)` without host validation; the harness
//! records a `ProbeKind::Redirect` probe whose `location` points
//! off-origin.
//!
//! Benign control: same shape but redirects to the same-origin path
//! `/dashboard`, so the captured `location` has no authority
//! component and the predicate stays clear.
//!
//! OOB-nonce variant (added 2026-05-22): when the runner attaches an
//! [`crate::dynamic::oob::OobListener`] the harness follows the
//! captured `Location:` URL via a real `Net::HTTP.get_response` against
//! the loopback nonce URL so the listener records the per-finding
//! callback. Ordered first so the runner exercises the OOB observation
//! path before the absolute-URL vuln below triggers and short-circuits
//! iteration; runs without a listener skip cleanly (runner
//! `oob_nonce_slot` branch).
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
const ALLOWLIST: &[&str] = &["example.com"];
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
// `bytes` is unused when `oob_nonce_slot = true`; the runner
// substitutes a per-finding loopback URL (see runner.rs:405-413).
bytes: b"",
label: "open-redirect-ruby-oob-nonce",
oracle: Oracle::OobCallback { host: "127.0.0.1" },
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/open_redirect/ruby/vuln.rb"],
oob_nonce_slot: true,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: Some(
"OOB-nonce open-redirect payload self-confirms via the per-finding listener \
callback when the harness follows the captured Location URL with \
Net::HTTP.get_response; no benign URL can hit the nonce path.",
),
},
CuratedPayload {
bytes: b"https://attacker.test/",
label: "open-redirect-ruby-absolute",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::RedirectHostNotIn {
allowlist: ALLOWLIST,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 13,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/open_redirect/ruby/vuln.rb"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::RedirectHostNotIn {
allowlist: ALLOWLIST,
}],
benign_control: Some(PayloadRef {
label: "open-redirect-ruby-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"/dashboard",
label: "open-redirect-ruby-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::RedirectHostNotIn {
allowlist: ALLOWLIST,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 13,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/open_redirect/ruby/benign.rb"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,88 @@
//! Rust `Cap::OPEN_REDIRECT` payloads — `axum::response::Redirect::to`
//! off-origin redirect.
//!
//! Vuln payload: an absolute attacker URL spliced into
//! `Redirect::to(value)` without host validation; the harness
//! records a `ProbeKind::Redirect` probe whose `location` points
//! off-origin.
//!
//! Benign control: same shape but redirects to the same-origin path
//! `/dashboard`, so the captured `location` has no authority
//! component and the predicate stays clear.
//!
//! OOB-nonce variant (added 2026-05-22): when the runner attaches an
//! [`crate::dynamic::oob::OobListener`] the harness follows the
//! captured `Location:` URL via a zero-dep `std::net::TcpStream`
//! `GET / HTTP/1.0` against the loopback nonce URL so the listener
//! records the per-finding callback. Ordered first so the runner
//! exercises the OOB observation path before the absolute-URL vuln
//! below triggers and short-circuits iteration; runs without a
//! listener skip cleanly (runner `oob_nonce_slot` branch).
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
const ALLOWLIST: &[&str] = &["example.com"];
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
// `bytes` is unused when `oob_nonce_slot = true`; the runner
// substitutes a per-finding loopback URL (see runner.rs:405-413).
bytes: b"",
label: "open-redirect-rust-oob-nonce",
oracle: Oracle::OobCallback { host: "127.0.0.1" },
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/open_redirect/rust/vuln.rs"],
oob_nonce_slot: true,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: Some(
"OOB-nonce open-redirect payload self-confirms via the per-finding listener \
callback when the harness follows the captured Location URL with a zero-dep \
TcpStream-based GET; no benign URL can hit the nonce path.",
),
},
CuratedPayload {
bytes: b"https://attacker.test/",
label: "open-redirect-rust-absolute",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::RedirectHostNotIn {
allowlist: ALLOWLIST,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 13,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/open_redirect/rust/vuln.rs"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::RedirectHostNotIn {
allowlist: ALLOWLIST,
}],
benign_control: Some(PayloadRef {
label: "open-redirect-rust-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"/dashboard",
label: "open-redirect-rust-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::RedirectHostNotIn {
allowlist: ALLOWLIST,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 13,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/open_redirect/rust/benign.rs"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,71 @@
//! Java `Cap::FILE_IO` path-traversal payloads (entry-driven servlet harness).
//!
//! The vulnerable payload escapes the fixture's `testfileDir`
//! (`<workdir>/testfiles/`) one level up to a canary file the harness plants at
//! the workdir root. The oracle marker is the canary file's CONTENT
//! ([`CANARY_MARKER`]), which is deliberately NOT a substring of the path
//! payload: an OWASP fixture that merely echoes the requested filename back to
//! the response (e.g. `getWriter().write("...'" + fileName + "'...")`) or logs
//! it (`System.out.println(... fileName ...)`) cannot reproduce the marker —
//! only an unsanitised `new FileInputStream(testfileDir + param)` that actually
//! opens and reads the canary does. This is the FILE_IO analogue of the
//! collision-resistant CODE_EXEC computed marker (`NYX_PWN_791`).
//!
//! The host sandbox (`path_traversal.sb`) denies `/etc/passwd` &c. but allows
//! reads inside the workdir, so the legacy `/etc/passwd` → `root:` rust payload
//! cannot confirm under isolation; the planted canary lives in the readable
//! workdir instead.
//!
//! The benign control names a file that does not exist under `testfileDir`, so
//! the same content-marker oracle cannot fire on it.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
/// Canary filename planted at the harness workdir root (the parent of
/// `testfiles/`). The Java emitter stages `<workdir>/nyx_pt_canary` with
/// [`CANARY_MARKER`] as its content plus an empty `testfiles/` directory so the
/// `../nyx_pt_canary` traversal resolves.
pub const CANARY_FILENAME: &str = "nyx_pt_canary";
/// Canary file content for the collision-resistant FILE_IO marker. It uses
/// alphanumeric characters plus underscore, so a faithful HTML/URL escaper
/// leaves it intact when the fixture writes the read bytes to the response.
/// NOT a substring of any payload path.
pub const CANARY_MARKER: &str = "NYX_PATHTRAVERSAL_R34D_a7f3c1d8";
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
// `testfileDir + "../nyx_pt_canary"` == `<workdir>/testfiles/../nyx_pt_canary`
// == `<workdir>/nyx_pt_canary` (the planted canary).
bytes: b"../nyx_pt_canary",
label: "path-traversal-canary-java",
oracle: Oracle::OutputContains(CANARY_MARKER),
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 17,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/benchmark/corpus/java/path_traversal/PathTraversalServlet.java"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: Some(PayloadRef {
label: "path-traversal-benign-java",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
// No traversal and no such file under `testfileDir`, so the canary is
// never read and the content marker cannot appear.
bytes: b"nyx_pt_benign_absent_NYX_BENIGN",
label: "path-traversal-benign-java",
oracle: Oracle::OutputContains(CANARY_MARKER),
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 17,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/benchmark/corpus/java/path_traversal/PathTraversalServlet.java"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,4 @@
//! Path-traversal (`Cap::FILE_IO`) per-language payload slices.
pub mod java;
pub mod rust;

View file

@ -0,0 +1,43 @@
//! Path-traversal payloads exercised by Rust fixtures
//! (`tests/benchmark/corpus/rust/path_traversal/`).
//!
//! Vuln payload reads `/etc/passwd`; benign payload names a file that does
//! not exist so the same oracle marker cannot fire.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"../../../../etc/passwd",
label: "path-traversal-passwd",
oracle: Oracle::OutputContains("root:"),
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 1,
deprecated_at_corpus_version: None,
fixture_paths: &[
"tests/benchmark/corpus/rust/path_traversal/path_file_open.rs",
"tests/benchmark/corpus/rust/path_traversal/path_read.rs",
],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: Some(PayloadRef {
label: "path-traversal-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"benign_safe_file_that_does_not_exist_NYX_BENIGN",
label: "path-traversal-benign",
oracle: Oracle::OutputContains("root:"),
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 1,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/benchmark/corpus/rust/path_traversal/path_file_open.rs"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,64 @@
//! JavaScript `Cap::PROTOTYPE_POLLUTION` payloads.
//!
//! Vuln payload: a JSON literal whose top-level key is `__proto__`.
//! When the host's deep-merge / `Object.assign` / JSON-parse-then-
//! deep-assign sink walks the key into the merge target, the
//! `__proto__` reference reaches `Object.prototype` and writes
//! `__nyx_canary`. The harness's instrumented setter trap records a
//! `ProbeKind::PrototypePollution { property: "__nyx_canary", … }`
//! probe; the predicate
//! [`crate::dynamic::oracle::ProbePredicate::PrototypeCanaryTouched`]
//! fires on the captured canary write.
//!
//! Benign control: a JSON literal whose top-level key is the regular
//! property `data`. Naive deep-merge walks `target.data` rather than
//! `target.__proto__`, so the prototype chain stays untouched and the
//! predicate stays clear. The matching fixture
//! (`tests/dynamic_fixtures/prototype_pollution/javascript/benign.js`)
//! additionally demonstrates the canonical mitigation pattern of
//! using `Object.create(null)` as the merge target — static analysis
//! of the fixture surfaces the prototype-less target while the
//! runtime differential is driven by the absence of a `__proto__` key
//! in the payload bytes.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::{Canary, ProbePredicate};
const CANARY: &str = Canary::PLACEHOLDER;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: br#"{"__proto__":{"__nyx_canary":"pwned"}}"#,
label: "prototype-pollution-js-proto-key",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::PrototypeCanaryTouched { canary: CANARY }],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 14,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/prototype_pollution/javascript/vuln.js"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::PrototypeCanaryTouched { canary: CANARY }],
benign_control: Some(PayloadRef {
label: "prototype-pollution-js-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: br#"{"data":{"__nyx_canary":"pwned"}}"#,
label: "prototype-pollution-js-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::PrototypeCanaryTouched { canary: CANARY }],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 14,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/prototype_pollution/javascript/benign.js"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,20 @@
//! Prototype-pollution (`Cap::PROTOTYPE_POLLUTION`) per-language
//! payload slices.
//!
//! Phase 10 (Track J.8) carves the JavaScript / TypeScript prototype-
//! pollution gadget against three sink families: `lodash.merge`,
//! `Object.assign` with tainted RHS, and `JSON.parse`-then-deep-assign.
//! Every vuln payload binds a JSON literal whose top-level key is
//! `__proto__`; the harness's instrumented deep-merge walks the key
//! into `Object.prototype` and a `Proxy`-style setter trap on
//! `Object.prototype.__nyx_canary` records a
//! [`crate::dynamic::probe::ProbeKind::PrototypePollution`] probe. The
//! paired benign control sends a JSON literal whose top-level key is
//! the regular property `data`, leaving the prototype chain
//! untouched. The
//! [`crate::dynamic::oracle::ProbePredicate::PrototypeCanaryTouched`]
//! predicate fires only on probes whose `property` equals the canary
//! name (`__nyx_canary`).
pub mod javascript;
pub mod typescript;

View file

@ -0,0 +1,50 @@
//! TypeScript `Cap::PROTOTYPE_POLLUTION` payloads.
//!
//! Mirrors [`super::javascript`] — the runtime is Node.js in both
//! cases, so the payload shape and oracle predicate are identical.
//! The per-language slice exists so the lang-aware corpus resolver
//! pairs TS vuln payloads against TS benign controls without crossing
//! the JS slice (and so the fixture paths point at the TS-specific
//! fixtures the static-analysis side consumes).
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::{Canary, ProbePredicate};
const CANARY: &str = Canary::PLACEHOLDER;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: br#"{"__proto__":{"__nyx_canary":"pwned"}}"#,
label: "prototype-pollution-ts-proto-key",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::PrototypeCanaryTouched { canary: CANARY }],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 14,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/prototype_pollution/typescript/vuln.ts"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::PrototypeCanaryTouched { canary: CANARY }],
benign_control: Some(PayloadRef {
label: "prototype-pollution-ts-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: br#"{"data":{"__nyx_canary":"pwned"}}"#,
label: "prototype-pollution-ts-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::PrototypeCanaryTouched { canary: CANARY }],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 14,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/prototype_pollution/typescript/benign.ts"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,7 @@
//! SQLi (`Cap::SQL_QUERY`) per-language payload slices.
//!
//! Each submodule exposes a `pub const PAYLOADS: &[CuratedPayload]` slice
//! registered against `(Cap::SQL_QUERY, Lang::<lang>)` in
//! [`super::registry::CORPUS`].
pub mod rust;

View file

@ -0,0 +1,57 @@
//! SQLi payloads exercised by Rust fixtures (`tests/benchmark/corpus/rust/sqli/`).
//!
//! Payload bytes are SQL-syntax, not Rust-specific; the `Lang::Rust` slot
//! reflects the fixture that currently drives them. Track J phases 0311
//! add per-language slices as new fixtures land.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"' OR '1'='1",
label: "sqli-tautology",
oracle: Oracle::OutputContains("NYX_SQL_CONFIRMED"),
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 1,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/benchmark/corpus/rust/sqli/sqli_rusqlite_format.rs"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: Some(PayloadRef {
label: "sqli-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"' UNION SELECT 'NYX_SQL_CONFIRMED'--",
label: "sqli-union-nyx",
oracle: Oracle::OutputContains("NYX_SQL_CONFIRMED"),
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 1,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/benchmark/corpus/rust/sqli/sqli_rusqlite_format.rs"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: Some(PayloadRef {
label: "sqli-benign",
}),
no_benign_control_rationale: None,
},
// Benign control: ordinary value that should never produce the SQL marker.
CuratedPayload {
bytes: b"benign_safe_sqli_NYX_BENIGN",
label: "sqli-benign",
oracle: Oracle::OutputContains("NYX_SQL_CONFIRMED"),
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 4,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/benchmark/corpus/rust/sqli/sqli_rusqlite_format.rs"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,3 @@
//! SSRF (`Cap::SSRF`) per-language payload slices.
pub mod rust;

View file

@ -0,0 +1,73 @@
//! SSRF payloads exercised by Rust fixtures
//! (`tests/benchmark/corpus/rust/ssrf/`).
//!
//! Two variants:
//! 1. `file://` scheme — static payload, `OutputContains` oracle. Works in
//! the process backend without OOB infrastructure.
//! 2. OOB nonce slot — URL generated at runtime from the OOB listener.
//! Confirms SSRF by recording the callback nonce.
//!
//! Oracle notes:
//! `OutputContains("daemon:")` matches both Linux (`daemon:x:1:1:`) and
//! macOS (`daemon:*:1:1:`) `/etc/passwd` formats and must NOT collide with
//! FILE_IO's `"root:"` marker (see marker_uniqueness test).
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"file:///etc/passwd",
label: "ssrf-file-scheme",
oracle: Oracle::OutputContains("daemon:"),
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 1,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/benchmark/corpus/rust/ssrf/ssrf_reqwest.rs"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: Some(PayloadRef {
label: "ssrf-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
// `bytes` is unused when `oob_nonce_slot = true`; the runner
// materialises the URL from the OOB listener at call time.
bytes: b"",
label: "ssrf-oob-nonce",
oracle: Oracle::OobCallback { host: "127.0.0.1" },
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 2,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/benchmark/corpus/rust/ssrf/ssrf_reqwest.rs"],
oob_nonce_slot: true,
probe_predicates: &[],
// OOB-nonce payloads are self-confirming via the listener; no benign
// counterpart is meaningful (a benign URL can never hit the nonce
// listener), so this entry sits at `NoControl`.
benign_control: None,
no_benign_control_rationale: Some(
"OOB-nonce payload self-confirms via the per-finding listener callback; \
no benign URL can hit the nonce path, so no paired control is meaningful.",
),
},
// Benign control for the file-scheme SSRF variant. Fetched the same
// way as the vuln payload but cannot resolve to a body containing the
// `daemon:` marker.
CuratedPayload {
bytes: b"benign_safe_ssrf_NYX_BENIGN",
label: "ssrf-benign",
oracle: Oracle::OutputContains("daemon:"),
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 4,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/benchmark/corpus/rust/ssrf/ssrf_reqwest.rs"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,46 @@
//! Java Thymeleaf `Cap::SSTI` payloads.
//!
//! Vuln payload: `[[${7*7}]]` — Thymeleaf evaluates the SpEL-style
//! expression inside the inlined-output marker and renders `49`.
//! Benign control sends the literal `7*7` text; without the `[[${...}]]`
//! markers Thymeleaf passes the payload through unchanged.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"[[${7*7}]]",
label: "ssti-thymeleaf-eval",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::TemplateEvalEqual { expected: 49 }],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 8,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/ssti/java_thymeleaf/vuln.java"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::TemplateEvalEqual { expected: 49 }],
benign_control: Some(PayloadRef {
label: "ssti-thymeleaf-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"7*7",
label: "ssti-thymeleaf-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::TemplateEvalEqual { expected: 49 }],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 8,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/ssti/java_thymeleaf/benign.java"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,52 @@
//! JavaScript Handlebars `Cap::SSTI` payloads.
//!
//! Handlebars does not evaluate arbitrary arithmetic in `{{ ... }}`
//! expressions out of the box, so the vuln payload reaches the engine
//! through the built-in `lookup` helper combined with a constructor
//! gadget chain: `{{#with (lookup this 'constructor')}}{{lookup
//! this 'constructor'}}{{/with}}` is the canonical pattern, but the
//! evaluation marker we need ("rendered constant only via eval")
//! reduces to a much simpler `{{multiply 7 7}}` against the in-harness
//! `multiply` helper. The harness registers that helper before
//! compiling so the rendered body is `49`; benign control sends `7*7`
//! plain text which Handlebars echoes verbatim.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"{{multiply 7 7}}",
label: "ssti-handlebars-eval",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::TemplateEvalEqual { expected: 49 }],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 8,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/ssti/js_handlebars/vuln.js"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::TemplateEvalEqual { expected: 49 }],
benign_control: Some(PayloadRef {
label: "ssti-handlebars-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"7*7",
label: "ssti-handlebars-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::TemplateEvalEqual { expected: 49 }],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 8,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/ssti/js_handlebars/benign.js"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,19 @@
//! Server-Side Template Injection (`Cap::SSTI`) per-engine payload slices.
//!
//! Phase 04 (Track J.2) carves SSTI across the five most-common template
//! engines: Jinja2 (Python), ERB (Ruby), Twig (PHP), Thymeleaf (Java), and
//! Handlebars (JavaScript). Every vuln payload sends a template
//! expression that resolves to a known constant *only* when the engine
//! actually evaluates the expression (e.g. `{{7*7}}` → `49` in Jinja2,
//! `<%= 7*7 %>` → `49` in ERB). The paired benign control sends the
//! literal arithmetic text without engine markers so the per-engine
//! harness echoes the payload verbatim rather than evaluating it; the
//! oracle's [`crate::dynamic::oracle::ProbePredicate::TemplateEvalEqual`]
//! check fires on the vuln render (`49`) and does not fire on the
//! benign render (`7*7`), satisfying the §4.1 differential rule.
pub mod java_thymeleaf;
pub mod js_handlebars;
pub mod php_twig;
pub mod python_jinja2;
pub mod ruby_erb;

View file

@ -0,0 +1,46 @@
//! PHP Twig `Cap::SSTI` payloads.
//!
//! Vuln payload: `{{7*7}}` — Twig evaluates the expression and the
//! rendered template body is `49`. Benign control sends the literal
//! `7*7` text; Twig has no `{{ ... }}` markers around it and echoes
//! the payload verbatim.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"{{7*7}}",
label: "ssti-twig-eval",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::TemplateEvalEqual { expected: 49 }],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 8,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/ssti/php_twig/vuln.php"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::TemplateEvalEqual { expected: 49 }],
benign_control: Some(PayloadRef {
label: "ssti-twig-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"7*7",
label: "ssti-twig-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::TemplateEvalEqual { expected: 49 }],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 8,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/ssti/php_twig/benign.php"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,53 @@
//! Python Jinja2 `Cap::SSTI` payloads.
//!
//! Vuln payload: `{{7*7}}` — Jinja2 evaluates the expression and the
//! rendered template body is `49`. The harness's
//! [`crate::dynamic::oracle::ProbePredicate::TemplateEvalEqual`] check
//! compares the captured `{"render": "49"}` JSON body against
//! `expected = 49` and the oracle fires.
//!
//! Benign control: literal `7*7` — Jinja2 has no `{{ ... }}` markers to
//! evaluate so the engine echoes the payload verbatim. The rendered
//! body is `7*7`, the oracle's integer parse fails, and the oracle
//! does not fire. Together with the vuln payload this satisfies the
//! §4.1 differential confirmation rule.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"{{7*7}}",
label: "ssti-jinja2-eval",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::TemplateEvalEqual { expected: 49 }],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 8,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/ssti/python_jinja2/vuln.py"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::TemplateEvalEqual { expected: 49 }],
benign_control: Some(PayloadRef {
label: "ssti-jinja2-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"7*7",
label: "ssti-jinja2-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::TemplateEvalEqual { expected: 49 }],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 8,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/ssti/python_jinja2/benign.py"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,46 @@
//! Ruby ERB `Cap::SSTI` payloads.
//!
//! Vuln payload: `<%= 7*7 %>` — ERB evaluates the embedded Ruby
//! expression and the rendered template body is `49`. Benign control
//! ships the literal `7*7` text which ERB has no `<%= ... %>` marker
//! around and so passes through verbatim.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"<%= 7*7 %>",
label: "ssti-erb-eval",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::TemplateEvalEqual { expected: 49 }],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 8,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/ssti/ruby_erb/vuln.rb"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::TemplateEvalEqual { expected: 49 }],
benign_control: Some(PayloadRef {
label: "ssti-erb-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"7*7",
label: "ssti-erb-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::TemplateEvalEqual { expected: 49 }],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 8,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/ssti/ruby_erb/benign.rb"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,41 @@
//! go `Cap::UNAUTHORIZED_ID` payloads.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"bob",
label: "idor-go-cross-tenant",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::IdorBoundaryCrossed],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/unauthorized_id/go/vuln.go"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::IdorBoundaryCrossed],
benign_control: Some(PayloadRef {
label: "idor-go-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"alice",
label: "idor-go-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::IdorBoundaryCrossed],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/unauthorized_id/go/benign.go"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,41 @@
//! java `Cap::UNAUTHORIZED_ID` payloads.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"bob",
label: "idor-java-cross-tenant",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::IdorBoundaryCrossed],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/unauthorized_id/java/Vuln.java"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::IdorBoundaryCrossed],
benign_control: Some(PayloadRef {
label: "idor-java-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"alice",
label: "idor-java-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::IdorBoundaryCrossed],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/unauthorized_id/java/Benign.java"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,41 @@
//! js `Cap::UNAUTHORIZED_ID` payloads.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"bob",
label: "idor-js-cross-tenant",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::IdorBoundaryCrossed],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/unauthorized_id/js/vuln.js"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::IdorBoundaryCrossed],
benign_control: Some(PayloadRef {
label: "idor-js-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"alice",
label: "idor-js-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::IdorBoundaryCrossed],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/unauthorized_id/js/benign.js"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,23 @@
//! IDOR / unauthorized-id-access (`Cap::UNAUTHORIZED_ID`)
//! per-language payload slices.
//!
//! Phase 11 (Track J.9) carves an IDOR oracle across all seven
//! backend-capable languages. Each harness stands up a mock data
//! store keyed by `owner_id` and a hard-coded `caller_id`
//! (`"alice"`). The vuln payload supplies an `owner_id` that
//! belongs to another user (`"bob"`); the harness's instrumented
//! lookup returns the record without an authorization check and
//! writes a [`crate::dynamic::probe::ProbeKind::IdorAccess { caller_id,
//! owner_id }`] probe. The
//! [`crate::dynamic::oracle::ProbePredicate::IdorBoundaryCrossed`]
//! predicate fires whenever `caller_id != owner_id`. The paired
//! benign control asks for the caller's own record (`"alice"`), so
//! the probe records matching ids and the predicate stays clear.
pub mod go;
pub mod java;
pub mod js;
pub mod php;
pub mod python;
pub mod ruby;
pub mod rust;

View file

@ -0,0 +1,41 @@
//! php `Cap::UNAUTHORIZED_ID` payloads.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"bob",
label: "idor-php-cross-tenant",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::IdorBoundaryCrossed],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/unauthorized_id/php/vuln.php"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::IdorBoundaryCrossed],
benign_control: Some(PayloadRef {
label: "idor-php-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"alice",
label: "idor-php-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::IdorBoundaryCrossed],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/unauthorized_id/php/benign.php"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,41 @@
//! Python `Cap::UNAUTHORIZED_ID` payloads.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"bob",
label: "idor-python-cross-tenant",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::IdorBoundaryCrossed],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/unauthorized_id/python/vuln.py"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::IdorBoundaryCrossed],
benign_control: Some(PayloadRef {
label: "idor-python-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"alice",
label: "idor-python-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::IdorBoundaryCrossed],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/unauthorized_id/python/benign.py"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,41 @@
//! ruby `Cap::UNAUTHORIZED_ID` payloads.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"bob",
label: "idor-ruby-cross-tenant",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::IdorBoundaryCrossed],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/unauthorized_id/ruby/vuln.rb"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::IdorBoundaryCrossed],
benign_control: Some(PayloadRef {
label: "idor-ruby-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"alice",
label: "idor-ruby-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::IdorBoundaryCrossed],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/unauthorized_id/ruby/benign.rb"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,41 @@
//! rust `Cap::UNAUTHORIZED_ID` payloads.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"bob",
label: "idor-rust-cross-tenant",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::IdorBoundaryCrossed],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/unauthorized_id/rust/vuln.rs"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::IdorBoundaryCrossed],
benign_control: Some(PayloadRef {
label: "idor-rust-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"alice",
label: "idor-rust-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::IdorBoundaryCrossed],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/unauthorized_id/rust/benign.rs"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,53 @@
//! Java `Cap::XPATH_INJECTION` payloads — `javax.xml.xpath.XPath.evaluate`
//! expression injection.
//!
//! Vuln payload: an XPath fragment whose `' or '1'='1` tail breaks
//! out of the host template's `[@name='…']` predicate and rewraps
//! the selector as `//user[@name='' or '1'='1']`, matching every
//! node the staged document carries. The harness's instrumented
//! `XPath.evaluate` records
//! `ProbeKind::Xpath { nodes_returned: 3 }`.
//!
//! Benign control: the same intended username quoted via the
//! harness's XPath-escape helper, leaving the expression pinned to a
//! single node — `nodes_returned: 1`, oracle clear.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"alice' or '1'='1",
label: "xpath-java-expression-wildcard",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::QueryResultCountGreaterThan { n: 1 }],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 11,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/xpath_injection/java/Vuln.java"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::QueryResultCountGreaterThan { n: 1 }],
benign_control: Some(PayloadRef {
label: "xpath-java-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"alice",
label: "xpath-java-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::QueryResultCountGreaterThan { n: 1 }],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 11,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/xpath_injection/java/Benign.java"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,53 @@
//! JavaScript `Cap::XPATH_INJECTION` payloads — `xpath` npm package's
//! `select` expression injection.
//!
//! Vuln payload: an XPath fragment whose `' or '1'='1` tail breaks
//! out of the host template's `[@name='…']` predicate; the
//! synthesized expression becomes `//user[@name='' or '1'='1']` and
//! matches every node in the staged document. The harness's
//! instrumented `xpath.select` records
//! `ProbeKind::Xpath { nodes_returned: 3 }`.
//!
//! Benign control: the same intended username quoted via the
//! harness's XPath-escape helper, leaving the expression pinned to a
//! single node — `nodes_returned: 1`, oracle clear.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"alice' or '1'='1",
label: "xpath-js-expression-wildcard",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::QueryResultCountGreaterThan { n: 1 }],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 11,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/xpath_injection/js/vuln.js"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::QueryResultCountGreaterThan { n: 1 }],
benign_control: Some(PayloadRef {
label: "xpath-js-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"alice",
label: "xpath-js-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::QueryResultCountGreaterThan { n: 1 }],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 11,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/xpath_injection/js/benign.js"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,29 @@
//! XPath expression injection (`Cap::XPATH_INJECTION`) per-language
//! payload slices.
//!
//! Phase 07 (Track J.5) carves XPath injection across the four
//! most-common XPath evaluator stacks: Java
//! (`javax.xml.xpath.XPath.evaluate`), Python (`lxml.etree.xpath`),
//! PHP (`DOMXPath::query`), and Node.js (`xpath` npm package's
//! `select`). Every vuln payload appends the canonical
//! `' or '1'='1` quote-escape break — once the host code substitutes
//! the attacker bytes into its XPath template the synthesized
//! expression selects every node the in-workdir
//! [`crate::dynamic::stubs::xpath_document`] XML carries (three
//! users). The paired benign control quotes the same bytes through
//! the per-language escape helper, leaving the expression pinned to
//! the originally-intended single node.
//!
//! The oracle's
//! [`crate::dynamic::oracle::ProbePredicate::QueryResultCountGreaterThan`]
//! checks the per-payload `ProbeKind::Xpath.nodes_returned` against
//! `n = 1` — vuln passes (3 nodes), benign clears (1 node),
//! fulfilling the §4.1 differential rule. The same predicate also
//! satisfies LDAP probes (`ProbeKind::Ldap.entries_returned`); the
//! Phase 06 → Phase 07 rename from `LdapResultCountGreaterThan` to
//! `QueryResultCountGreaterThan` captures the shared shape.
pub mod java;
pub mod js;
pub mod php;
pub mod python;

View file

@ -0,0 +1,53 @@
//! PHP `Cap::XPATH_INJECTION` payloads — `DOMXPath::query` expression
//! injection.
//!
//! Vuln payload: an XPath fragment whose `' or '1'='1` tail breaks
//! out of the host template's `[@name='…']` predicate; the
//! synthesized expression becomes `//user[@name='' or '1'='1']` and
//! matches every node in the staged document. The harness's
//! instrumented `DOMXPath::query` records
//! `ProbeKind::Xpath { nodes_returned: 3 }`.
//!
//! Benign control: the same intended username quoted via the
//! harness's XPath-escape helper, leaving the expression pinned to a
//! single node — `nodes_returned: 1`, oracle clear.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"alice' or '1'='1",
label: "xpath-php-expression-wildcard",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::QueryResultCountGreaterThan { n: 1 }],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 11,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/xpath_injection/php/vuln.php"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::QueryResultCountGreaterThan { n: 1 }],
benign_control: Some(PayloadRef {
label: "xpath-php-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"alice",
label: "xpath-php-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::QueryResultCountGreaterThan { n: 1 }],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 11,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/xpath_injection/php/benign.php"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,53 @@
//! Python `Cap::XPATH_INJECTION` payloads — `lxml.etree.xpath`
//! expression injection.
//!
//! Vuln payload: an XPath fragment whose `' or '1'='1` tail breaks
//! out of the host template's `[@name='…']` predicate; the
//! synthesized expression becomes `//user[@name='' or '1'='1']` and
//! matches every node in the staged document. The harness's
//! instrumented `xpath` evaluator records
//! `ProbeKind::Xpath { nodes_returned: 3 }`.
//!
//! Benign control: the same intended username quoted via the
//! harness's XPath-escape helper, leaving the expression pinned to a
//! single node — `nodes_returned: 1`, oracle clear.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"alice' or '1'='1",
label: "xpath-python-expression-wildcard",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::QueryResultCountGreaterThan { n: 1 }],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 11,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/xpath_injection/python/vuln.py"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::QueryResultCountGreaterThan { n: 1 }],
benign_control: Some(PayloadRef {
label: "xpath-python-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"alice",
label: "xpath-python-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::QueryResultCountGreaterThan { n: 1 }],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 11,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/xpath_injection/python/benign.py"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,3 @@
//! XSS (`Cap::HTML_ESCAPE`) per-language payload slices.
pub mod rust;

View file

@ -0,0 +1,40 @@
//! XSS payloads exercised by Rust fixtures
//! (`tests/benchmark/corpus/rust/xss/axum_html/`).
//!
//! Vuln: raw script tag echoed to output.
//! Benign: harmless text that should NOT produce the XSS marker.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"<script>NYX_XSS_CONFIRMED</script>",
label: "xss-script-marker",
oracle: Oracle::OutputContains("<script>NYX_XSS_CONFIRMED</script>"),
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 1,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/benchmark/corpus/rust/xss/axum_html/main.rs"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: Some(PayloadRef {
label: "xss-benign-text",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: b"Hello World",
label: "xss-benign-text",
oracle: Oracle::OutputContains("<script>NYX_XSS_CONFIRMED</script>"),
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 1,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/benchmark/corpus/rust/xss/axum_html/main.rs"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,87 @@
//! Go `Cap::XXE` payloads — `encoding/xml.Decoder` with `Strict: false`.
//!
//! Vuln payload: an XML document declaring an external entity that
//! the harness's instrumented `xml.Decoder` (running non-strict so
//! the doctype is parsed at all) expands inside `<data>`; the shim
//! writes `ProbeKind::Xxe { entity_expanded: true }` once it sees the
//! entity body substitute into the decoded element value.
//!
//! Benign control: a well-formed XML document with no doctype, so the
//! decoder has no entity to resolve and the shim writes
//! `entity_expanded: false`.
//!
//! OOB-nonce variant (added 2026-05-21): when the runner attaches an
//! [`crate::dynamic::oob::OobListener`] the harness's
//! `nyxBuildXxeDocument` helper performs a real `http.Client.Get`
//! against the loopback URL so the listener records the per-finding
//! nonce. Ordered first so iteration exercises OOB before the
//! doctype-entity vuln triggers and short-circuits.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"",
label: "xxe-go-oob-nonce",
oracle: Oracle::OobCallback { host: "127.0.0.1" },
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/xxe/go/vuln.go"],
oob_nonce_slot: true,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: Some(
"OOB-nonce XXE payload self-confirms via the per-finding listener \
callback when the Go harness performs the loopback GET before \
building the DTD; no benign URL can hit the nonce path.",
),
},
CuratedPayload {
bytes: br#"<?xml version="1.0"?>
<!DOCTYPE data [
<!ENTITY xxe SYSTEM "file:///etc/hostname">
]>
<data>&xxe;</data>"#,
label: "xxe-go-doctype-entity",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::XxeEntityExpanded {
require_expanded: true,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 9,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/xxe/go/vuln.go"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::XxeEntityExpanded {
require_expanded: true,
}],
benign_control: Some(PayloadRef {
label: "xxe-go-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: br#"<?xml version="1.0"?>
<data>hello</data>"#,
label: "xxe-go-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::XxeEntityExpanded {
require_expanded: true,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 9,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/xxe/go/benign.go"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,89 @@
//! Java `Cap::XXE` payloads — `DocumentBuilderFactory` / `SAXParser`.
//!
//! Vuln payload: an XML document declaring an external entity that
//! the harness's instrumented `DocumentBuilder.parse` resolves and
//! substitutes inside `<data>` — the parser writes a
//! `ProbeKind::Xxe { entity_expanded: true }` record once it sees the
//! entity body materialise.
//!
//! Benign control: a well-formed XML document with no doctype
//! declaration so the parser has no entity to resolve. The harness's
//! instrumented parser writes `entity_expanded: false`, the oracle
//! does not fire, and the differential rule (§4.1) stays clean.
//!
//! OOB-nonce variant (added 2026-05-21): when the runner attaches an
//! [`crate::dynamic::oob::OobListener`] the harness's `EntityResolver`
//! hook performs a real `HttpURLConnection.openConnection().getInputStream()`
//! against the loopback URL so the listener records the per-finding nonce.
//! Ordered first so the runner exercises the OOB observation path before
//! the doctype-entity vuln below triggers and short-circuits iteration;
//! runs without a listener skip cleanly (runner `oob_nonce_slot` branch).
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"",
label: "xxe-java-oob-nonce",
oracle: Oracle::OobCallback { host: "127.0.0.1" },
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/xxe/java/Vuln.java"],
oob_nonce_slot: true,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: Some(
"OOB-nonce XXE payload self-confirms via the per-finding listener \
callback when DocumentBuilder's EntityResolver fetches the \
loopback URL; no benign URL can hit the nonce path.",
),
},
CuratedPayload {
bytes: br#"<?xml version="1.0"?>
<!DOCTYPE data [
<!ENTITY xxe SYSTEM "file:///etc/hostname">
]>
<data>&xxe;</data>"#,
label: "xxe-java-doctype-entity",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::XxeEntityExpanded {
require_expanded: true,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 9,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/xxe/java/Vuln.java"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::XxeEntityExpanded {
require_expanded: true,
}],
benign_control: Some(PayloadRef {
label: "xxe-java-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: br#"<?xml version="1.0"?>
<data>hello</data>"#,
label: "xxe-java-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::XxeEntityExpanded {
require_expanded: true,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 9,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/xxe/java/Benign.java"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,24 @@
//! XML External Entity expansion (`Cap::XXE`) per-language payload slices.
//!
//! Phase 05 (Track J.3) carves XXE across the five most-common XML
//! parser stacks: Java (`DocumentBuilderFactory`), Python
//! (`lxml.etree.XMLParser`), PHP (`simplexml_load_string` under
//! `libxml_disable_entity_loader(false)`), Ruby (REXML / Nokogiri), and
//! Go (`encoding/xml.Decoder`). Every vuln payload ships an XML
//! document declaring an external entity (`<!ENTITY xxe SYSTEM "…">`)
//! that the engine expands inside an element body. The paired benign
//! control omits the doctype + entity so the parser has nothing to
//! resolve; the oracle's
//! [`crate::dynamic::oracle::ProbePredicate::XxeEntityExpanded`] check
//! satisfies on the vuln run (`entity_expanded: true`) and stays clear
//! on the benign run, fulfilling the §4.1 differential rule.
//!
//! C# is intentionally omitted: the [`crate::symbol::Lang`] enum has
//! no `CSharp` variant, so the corpus has nowhere to register it.
//! Tracked in `.pitboss/play/deferred.md`.
pub mod go;
pub mod java;
pub mod php;
pub mod python;
pub mod ruby;

View file

@ -0,0 +1,87 @@
//! PHP `Cap::XXE` payloads — `simplexml_load_string` under
//! `libxml_disable_entity_loader(false)`.
//!
//! Vuln payload: an XML document declaring an external entity that
//! the harness's instrumented parser expands inside `<data>`; the
//! shim writes `ProbeKind::Xxe { entity_expanded: true }` once it
//! sees the entity body substitute into the parsed output.
//!
//! Benign control: a well-formed XML document with no doctype, so
//! the parser has no entity to resolve and the shim writes
//! `entity_expanded: false`.
//!
//! OOB-nonce variant (added 2026-05-21): when the runner attaches an
//! [`crate::dynamic::oob::OobListener`] the harness's
//! `libxml_set_external_entity_loader` callback performs a real
//! `file_get_contents` against the loopback URL so the listener records
//! the per-finding nonce. Ordered first so iteration exercises OOB
//! before the doctype-entity vuln triggers and short-circuits.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"",
label: "xxe-php-oob-nonce",
oracle: Oracle::OobCallback { host: "127.0.0.1" },
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/xxe/php/vuln.php"],
oob_nonce_slot: true,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: Some(
"OOB-nonce XXE payload self-confirms via the per-finding listener \
callback when libxml's external-entity loader fetches the \
loopback URL; no benign URL can hit the nonce path.",
),
},
CuratedPayload {
bytes: br#"<?xml version="1.0"?>
<!DOCTYPE data [
<!ENTITY xxe SYSTEM "file:///etc/hostname">
]>
<data>&xxe;</data>"#,
label: "xxe-php-doctype-entity",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::XxeEntityExpanded {
require_expanded: true,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 9,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/xxe/php/vuln.php"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::XxeEntityExpanded {
require_expanded: true,
}],
benign_control: Some(PayloadRef {
label: "xxe-php-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: br#"<?xml version="1.0"?>
<data>hello</data>"#,
label: "xxe-php-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::XxeEntityExpanded {
require_expanded: true,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 9,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/xxe/php/benign.php"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,98 @@
//! Python `Cap::XXE` payloads — `lxml.etree.XMLParser(resolve_entities=True)`.
//!
//! Vuln payload: an XML document declaring an external entity that
//! the harness's instrumented parser (`resolve_entities=True`)
//! expands inside `<data>`; the shim writes
//! `ProbeKind::Xxe { entity_expanded: true }` once it sees the entity
//! body substitute into the parsed tree.
//!
//! Benign control: a well-formed XML document with no doctype, so the
//! parser has nothing to resolve and the shim writes
//! `entity_expanded: false`.
//!
//! OOB-nonce variant (added 2026-05-21): when the runner attaches an
//! [`crate::dynamic::oob::OobListener`], the runner materialises this
//! payload's bytes as a loopback URL and the Python harness wraps the
//! URL into `<!ENTITY xxe SYSTEM "URL">`. Expat's external-entity hook
//! performs a real `urllib.request.urlopen` against the URL so the
//! listener records the per-finding nonce. Ordered first so the runner
//! exercises the OOB observation path before the doctype-entity vuln
//! triggers and short-circuits the iteration; runs without a listener
//! skip cleanly (the runner's `oob_nonce_slot` branch `continue`s when
//! [`crate::dynamic::sandbox::SandboxOptions::oob_listener`] is None).
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
// OOB-nonce XXE variant. Ordered first so the harness exercises the
// OOB observation path before the doctype-entity vuln below triggers
// and breaks iteration. Self-confirming via [`Oracle::OobCallback`];
// no paired benign control because a benign URL can never hit the
// per-finding nonce path. Runs only when an [`OobListener`] is
// attached; the runner's `oob_nonce_slot` branch skips otherwise.
CuratedPayload {
bytes: b"",
label: "xxe-python-oob-nonce",
oracle: Oracle::OobCallback { host: "127.0.0.1" },
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/xxe/python/vuln.py"],
oob_nonce_slot: true,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: Some(
"OOB-nonce XXE payload self-confirms via the per-finding listener \
callback when expat's external-entity hook fetches the loopback \
URL; no benign URL can hit the nonce path so no paired control \
is meaningful.",
),
},
CuratedPayload {
bytes: br#"<?xml version="1.0"?>
<!DOCTYPE data [
<!ENTITY xxe SYSTEM "file:///etc/hostname">
]>
<data>&xxe;</data>"#,
label: "xxe-python-doctype-entity",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::XxeEntityExpanded {
require_expanded: true,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 9,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/xxe/python/vuln.py"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::XxeEntityExpanded {
require_expanded: true,
}],
benign_control: Some(PayloadRef {
label: "xxe-python-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: br#"<?xml version="1.0"?>
<data>hello</data>"#,
label: "xxe-python-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::XxeEntityExpanded {
require_expanded: true,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 9,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/xxe/python/benign.py"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];

View file

@ -0,0 +1,86 @@
//! Ruby `Cap::XXE` payloads — REXML / Nokogiri document parsers.
//!
//! Vuln payload: an XML document declaring an external entity that
//! the harness's instrumented parser expands inside `<data>`; the
//! shim writes `ProbeKind::Xxe { entity_expanded: true }` once it
//! sees the entity body substitute into the parsed output.
//!
//! Benign control: a well-formed XML document with no doctype, so
//! the parser has no entity to resolve and the shim writes
//! `entity_expanded: false`.
//!
//! OOB-nonce variant (added 2026-05-21): when the runner attaches an
//! [`crate::dynamic::oob::OobListener`] the harness's
//! `_nyx_build_xxe_document` helper performs a real `Net::HTTP.start`
//! against the loopback URL so the listener records the per-finding
//! nonce. Ordered first so iteration exercises OOB before the
//! doctype-entity vuln triggers and short-circuits.
use super::super::{CuratedPayload, Oracle, PayloadProvenance, PayloadRef};
use crate::dynamic::oracle::ProbePredicate;
pub const PAYLOADS: &[CuratedPayload] = &[
CuratedPayload {
bytes: b"",
label: "xxe-ruby-oob-nonce",
oracle: Oracle::OobCallback { host: "127.0.0.1" },
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 15,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/xxe/ruby/vuln.rb"],
oob_nonce_slot: true,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: Some(
"OOB-nonce XXE payload self-confirms via the per-finding listener \
callback when the Ruby harness performs the loopback GET before \
building the DTD; no benign URL can hit the nonce path.",
),
},
CuratedPayload {
bytes: br#"<?xml version="1.0"?>
<!DOCTYPE data [
<!ENTITY xxe SYSTEM "file:///etc/hostname">
]>
<data>&xxe;</data>"#,
label: "xxe-ruby-doctype-entity",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::XxeEntityExpanded {
require_expanded: true,
}],
},
is_benign: false,
provenance: PayloadProvenance::Curated,
since_corpus_version: 9,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/xxe/ruby/vuln.rb"],
oob_nonce_slot: false,
probe_predicates: &[ProbePredicate::XxeEntityExpanded {
require_expanded: true,
}],
benign_control: Some(PayloadRef {
label: "xxe-ruby-benign",
}),
no_benign_control_rationale: None,
},
CuratedPayload {
bytes: br#"<?xml version="1.0"?>
<data>hello</data>"#,
label: "xxe-ruby-benign",
oracle: Oracle::SinkProbe {
predicates: &[ProbePredicate::XxeEntityExpanded {
require_expanded: true,
}],
},
is_benign: true,
provenance: PayloadProvenance::Curated,
since_corpus_version: 9,
deprecated_at_corpus_version: None,
fixture_paths: &["tests/dynamic_fixtures/xxe/ruby/benign.rb"],
oob_nonce_slot: false,
probe_predicates: &[],
benign_control: None,
no_benign_control_rationale: None,
},
];