mirror of
https://github.com/elicpeter/nyx.git
synced 2026-06-30 20:39:39 +02:00
Python fp and docs updtes (#58)
* refactor: Update comments for clarity and add expectations.json files for performance metrics * feat: Implement FP guard for JS/TS local-collection receivers to suppress missing ownership checks * feat: Enhance Rust parameter handling to classify local collections and prevent false ownership checks * refactor: Simplify code formatting for better readability in multiple files * refactor: Improve UTF-8 sequence length handling and enhance clarity in loop iteration * feat: Update Java and Python patterns to include new security rules * refactor: Improve comment clarity and consistency across multiple Rust files * refactor: Simplify code formatting for improved readability in integration tests and module files * refactor: Improve comment formatting and enhance clarity in assertions across multiple files
This commit is contained in:
parent
4db0805de6
commit
a438886217
291 changed files with 9485 additions and 3851 deletions
125
tests/fetch_data_exfil_integration_tests.rs
Normal file
125
tests/fetch_data_exfil_integration_tests.rs
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
//! Integration tests for the `Cap::DATA_EXFIL` detector class.
|
||||
//!
|
||||
//! Validates per-cap attribution at multi-gate call sites: a single `fetch`
|
||||
//! call carries both an SSRF gate (URL flow) and a DATA_EXFIL gate (body /
|
||||
//! headers / json flow), and a tainted body must not surface as SSRF and
|
||||
//! vice versa. Also sanity-checks the SARIF output so the new finding
|
||||
//! class produces a distinct rule id.
|
||||
|
||||
mod common;
|
||||
|
||||
use common::scan_fixture_dir;
|
||||
use nyx_scanner::commands::scan::Diag;
|
||||
use nyx_scanner::utils::config::AnalysisMode;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn js_fixture_dir() -> PathBuf {
|
||||
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||
.join("tests")
|
||||
.join("fixtures")
|
||||
.join("js")
|
||||
}
|
||||
|
||||
fn diags_for(file: &str) -> Vec<Diag> {
|
||||
let dir = js_fixture_dir();
|
||||
let all = scan_fixture_dir(&dir, AnalysisMode::Full);
|
||||
all.into_iter().filter(|d| d.path.ends_with(file)).collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fetch_body_data_exfil_emits_data_exfil_not_ssrf() {
|
||||
let diags = diags_for("fetch_body_data_exfil.js");
|
||||
let exfil = diags
|
||||
.iter()
|
||||
.filter(|d| d.id.starts_with("taint-data-exfiltration"))
|
||||
.count();
|
||||
let plain_taint = diags
|
||||
.iter()
|
||||
.filter(|d| d.id.starts_with("taint-unsanitised-flow"))
|
||||
.count();
|
||||
assert!(
|
||||
exfil >= 1,
|
||||
"expected at least one taint-data-exfiltration finding, got 0.\n\
|
||||
Diags: {:#?}",
|
||||
diags.iter().map(|d| &d.id).collect::<Vec<_>>(),
|
||||
);
|
||||
assert_eq!(
|
||||
plain_taint,
|
||||
0,
|
||||
"fixed-URL fetch with tainted body must NOT emit SSRF \
|
||||
(taint-unsanitised-flow), got {plain_taint}.\n\
|
||||
Diags: {:#?}",
|
||||
diags.iter().map(|d| &d.id).collect::<Vec<_>>(),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fetch_ssrf_url_tainted_emits_ssrf_not_data_exfil() {
|
||||
let diags = diags_for("fetch_ssrf_url_tainted.js");
|
||||
let ssrf = diags
|
||||
.iter()
|
||||
.filter(|d| d.id.starts_with("taint-unsanitised-flow"))
|
||||
.count();
|
||||
let exfil = diags
|
||||
.iter()
|
||||
.filter(|d| d.id.starts_with("taint-data-exfiltration"))
|
||||
.count();
|
||||
assert!(
|
||||
ssrf >= 1,
|
||||
"expected at least one taint-unsanitised-flow (SSRF) finding, got 0.\n\
|
||||
Diags: {:#?}",
|
||||
diags.iter().map(|d| &d.id).collect::<Vec<_>>(),
|
||||
);
|
||||
assert_eq!(
|
||||
exfil,
|
||||
0,
|
||||
"tainted-URL fetch must NOT emit DATA_EXFIL, got {exfil}.\n\
|
||||
Diags: {:#?}",
|
||||
diags.iter().map(|d| &d.id).collect::<Vec<_>>(),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sarif_distinguishes_data_exfil_rule_id_from_ssrf() {
|
||||
use nyx_scanner::output::build_sarif;
|
||||
|
||||
let dir = js_fixture_dir();
|
||||
let diags = scan_fixture_dir(&dir, AnalysisMode::Full);
|
||||
let sarif = build_sarif(&diags, &dir);
|
||||
|
||||
let rules = sarif["runs"][0]["tool"]["driver"]["rules"]
|
||||
.as_array()
|
||||
.expect("SARIF rules array");
|
||||
let rule_ids: Vec<&str> = rules.iter().filter_map(|r| r["id"].as_str()).collect();
|
||||
|
||||
assert!(
|
||||
rule_ids.contains(&"taint-data-exfiltration"),
|
||||
"SARIF rules must contain taint-data-exfiltration, got: {rule_ids:?}"
|
||||
);
|
||||
assert!(
|
||||
rule_ids.contains(&"taint-unsanitised-flow"),
|
||||
"SARIF rules must contain taint-unsanitised-flow, got: {rule_ids:?}"
|
||||
);
|
||||
|
||||
// Each finding should reference exactly one rule, and the cap-specific
|
||||
// class must not be folded back into the generic taint bucket.
|
||||
let results = sarif["runs"][0]["results"]
|
||||
.as_array()
|
||||
.expect("SARIF results array");
|
||||
let exfil_results = results
|
||||
.iter()
|
||||
.filter(|r| r["ruleId"].as_str() == Some("taint-data-exfiltration"))
|
||||
.count();
|
||||
let ssrf_results = results
|
||||
.iter()
|
||||
.filter(|r| r["ruleId"].as_str() == Some("taint-unsanitised-flow"))
|
||||
.count();
|
||||
assert!(
|
||||
exfil_results >= 1,
|
||||
"expected >= 1 SARIF result with ruleId taint-data-exfiltration, got {exfil_results}",
|
||||
);
|
||||
assert!(
|
||||
ssrf_results >= 1,
|
||||
"expected >= 1 SARIF result with ruleId taint-unsanitised-flow, got {ssrf_results}",
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue