mirror of
https://github.com/elicpeter/nyx.git
synced 2026-06-09 19:45:13 +02:00
Added Cap::DATA_EXFIL and taint fp and fn fixes on real repos (#59)
* feat: Enhance data exfiltration detection with source sensitivity gating for cookies and headers * feat: Implement cross-file data exfiltration detection with parameter-specific gate filters * feat: Add calibration tests and refine DATA_EXFIL severity scoring logic * feat: Introduce per-detector configuration for data exfiltration suppression * feat: Enhance DATA_EXFIL findings with destination field tracking in diagnostics and SARIF output * feat: Add tainted body and URL handling for data exfiltration detection * feat: Add integration tests and fixtures for DATA_EXFIL and SSRF detection in Go * feat: Add Java integration tests and fixtures for DATA_EXFIL detection across multiple HTTP clients * feat: Add synthetic externals handling for closure-captured variables in SSA * feat: Implement closure-based suppression for resource leak findings * feat: Add regression guards for shell-injection and taint propagation in for-of destructure patterns * feat: Implement constructor cap narrowing for data exfiltration detection in HTTP request builders * feat: Add gated sinks for data exfiltration detection in C and C++ using curl_easy_setopt * feat: Implement DATA_EXFIL cap parity for backwards analysis and add integration tests * feat: Add data exfiltration sinks for various languages and enhance documentation * refactor: Simplify formatting and improve readability in various files * refactor: Improve readability by simplifying conditional statements and adding clippy linting * docs: Update CHANGELOG and comments for data exfiltration features and configuration * docs: Clarify configuration instructions for data exfiltration trusted destinations * docs: Enhance comments for evidence routing logic in data exfiltration
This commit is contained in:
parent
a438886217
commit
58f1794a4e
189 changed files with 8421 additions and 383 deletions
|
|
@ -158,6 +158,39 @@ pub struct SsaFuncSummary {
|
|||
/// (caller_param_index, sink_arg_position, sink_caps).
|
||||
#[serde(default)]
|
||||
pub param_to_sink_param: Vec<(usize, usize, Cap)>,
|
||||
/// Per-parameter gate-filter cap masks lifted from inner multi-gate
|
||||
/// sink call sites.
|
||||
///
|
||||
/// When a function body contains a callee whose
|
||||
/// [`crate::cfg::CallMeta::gate_filters`] carries more than one entry
|
||||
/// (e.g. `fetch` is both an `SSRF` gate on the URL arg and a
|
||||
/// `DATA_EXFIL` gate on the body arg), the multi-gate dispatch in
|
||||
/// [`super::super::collect_block_events`] cap-narrows the event's
|
||||
/// `sink_caps` to the specific gate's `label_caps`. Each
|
||||
/// `(param_idx, label_caps)` entry records that this function's
|
||||
/// parameter `param_idx` flowed into a gated sink whose narrowed
|
||||
/// caps were `label_caps`.
|
||||
///
|
||||
/// Cross-file callers consume this list to preserve per-position cap
|
||||
/// attribution through wrapper functions: a wrapper
|
||||
/// `fn forward(url, body) { fetch(url, {body}) }` records
|
||||
/// `[(0, SSRF), (1, DATA_EXFIL)]` so a caller of `forward` splits
|
||||
/// URL-tainted SSRF findings from body-tainted DATA_EXFIL findings
|
||||
/// instead of conflating both caps onto every parameter.
|
||||
///
|
||||
/// `Vec<(param_idx, label_caps)>` is sufficient at cross-file
|
||||
/// granularity, the corresponding `payload_args` and
|
||||
/// `destination_uses` are intra-file context that does not survive
|
||||
/// the function-summary boundary (field idents reference SSA
|
||||
/// values from the callee body).
|
||||
///
|
||||
/// Empty (the default) for callees whose internal sinks carry zero
|
||||
/// or one gate filter, the existing
|
||||
/// [`Self::param_to_sink`] /
|
||||
/// [`Self::param_to_sink_param`] machinery already records those
|
||||
/// cases without per-position cap conflict.
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub param_to_gate_filters: Vec<(usize, Cap)>,
|
||||
/// Parameter indices whose container identity flows to the return value
|
||||
/// (e.g., function returns the same container it received as input).
|
||||
///
|
||||
|
|
|
|||
|
|
@ -441,6 +441,7 @@ fn ssa_summary_serde_round_trip_identity() {
|
|||
field_points_to: Default::default(),
|
||||
return_path_facts: smallvec::SmallVec::new(),
|
||||
typed_call_receivers: vec![],
|
||||
param_to_gate_filters: vec![],
|
||||
};
|
||||
let json = serde_json::to_string(&summary).unwrap();
|
||||
let back: SsaFuncSummary = serde_json::from_str(&json).unwrap();
|
||||
|
|
@ -473,6 +474,7 @@ fn ssa_summary_serde_round_trip_strip_bits() {
|
|||
field_points_to: Default::default(),
|
||||
return_path_facts: smallvec::SmallVec::new(),
|
||||
typed_call_receivers: vec![],
|
||||
param_to_gate_filters: vec![],
|
||||
};
|
||||
let json = serde_json::to_string(&summary).unwrap();
|
||||
let back: SsaFuncSummary = serde_json::from_str(&json).unwrap();
|
||||
|
|
@ -502,6 +504,7 @@ fn ssa_summary_serde_round_trip_add_bits() {
|
|||
field_points_to: Default::default(),
|
||||
return_path_facts: smallvec::SmallVec::new(),
|
||||
typed_call_receivers: vec![],
|
||||
param_to_gate_filters: vec![],
|
||||
};
|
||||
let json = serde_json::to_string(&summary).unwrap();
|
||||
let back: SsaFuncSummary = serde_json::from_str(&json).unwrap();
|
||||
|
|
@ -538,6 +541,7 @@ fn ssa_summary_serde_round_trip_all_variants() {
|
|||
field_points_to: Default::default(),
|
||||
return_path_facts: smallvec::SmallVec::new(),
|
||||
typed_call_receivers: vec![],
|
||||
param_to_gate_filters: vec![],
|
||||
};
|
||||
let json = serde_json::to_string(&summary).unwrap();
|
||||
let back: SsaFuncSummary = serde_json::from_str(&json).unwrap();
|
||||
|
|
@ -576,6 +580,7 @@ fn global_summaries_insert_ssa_exact_key_replacement() {
|
|||
field_points_to: Default::default(),
|
||||
return_path_facts: smallvec::SmallVec::new(),
|
||||
typed_call_receivers: vec![],
|
||||
param_to_gate_filters: vec![],
|
||||
};
|
||||
gs.insert_ssa(key.clone(), v1.clone());
|
||||
assert_eq!(gs.get_ssa(&key), Some(&v1));
|
||||
|
|
@ -602,6 +607,7 @@ fn global_summaries_insert_ssa_exact_key_replacement() {
|
|||
field_points_to: Default::default(),
|
||||
return_path_facts: smallvec::SmallVec::new(),
|
||||
typed_call_receivers: vec![],
|
||||
param_to_gate_filters: vec![],
|
||||
};
|
||||
gs.insert_ssa(key.clone(), v2.clone());
|
||||
assert_eq!(gs.get_ssa(&key), Some(&v2));
|
||||
|
|
@ -648,6 +654,7 @@ fn global_summaries_merge_with_ssa_entries() {
|
|||
field_points_to: Default::default(),
|
||||
return_path_facts: smallvec::SmallVec::new(),
|
||||
typed_call_receivers: vec![],
|
||||
param_to_gate_filters: vec![],
|
||||
};
|
||||
let sum_b = SsaFuncSummary {
|
||||
param_to_return: vec![],
|
||||
|
|
@ -670,6 +677,7 @@ fn global_summaries_merge_with_ssa_entries() {
|
|||
field_points_to: Default::default(),
|
||||
return_path_facts: smallvec::SmallVec::new(),
|
||||
typed_call_receivers: vec![],
|
||||
param_to_gate_filters: vec![],
|
||||
};
|
||||
|
||||
gs1.insert_ssa(key_a.clone(), sum_a.clone());
|
||||
|
|
@ -716,6 +724,7 @@ fn global_summaries_is_empty_considers_ssa() {
|
|||
field_points_to: Default::default(),
|
||||
return_path_facts: smallvec::SmallVec::new(),
|
||||
typed_call_receivers: vec![],
|
||||
param_to_gate_filters: vec![],
|
||||
},
|
||||
);
|
||||
|
||||
|
|
@ -745,6 +754,7 @@ fn ssa_summary_serde_round_trip_param_to_sink_param() {
|
|||
field_points_to: Default::default(),
|
||||
return_path_facts: smallvec::SmallVec::new(),
|
||||
typed_call_receivers: vec![],
|
||||
param_to_gate_filters: vec![],
|
||||
};
|
||||
let json = serde_json::to_string(&summary).unwrap();
|
||||
let back: SsaFuncSummary = serde_json::from_str(&json).unwrap();
|
||||
|
|
@ -789,6 +799,7 @@ fn ssa_summary_serde_round_trip_container_fields() {
|
|||
field_points_to: Default::default(),
|
||||
return_path_facts: smallvec::SmallVec::new(),
|
||||
typed_call_receivers: vec![],
|
||||
param_to_gate_filters: vec![],
|
||||
};
|
||||
let json = serde_json::to_string(&summary).unwrap();
|
||||
let back: SsaFuncSummary = serde_json::from_str(&json).unwrap();
|
||||
|
|
@ -843,6 +854,7 @@ fn ssa_summary_serde_round_trip_return_abstract() {
|
|||
field_points_to: Default::default(),
|
||||
return_path_facts: smallvec::SmallVec::new(),
|
||||
typed_call_receivers: vec![],
|
||||
param_to_gate_filters: vec![],
|
||||
};
|
||||
let json = serde_json::to_string(&summary).unwrap();
|
||||
let back: SsaFuncSummary = serde_json::from_str(&json).unwrap();
|
||||
|
|
@ -916,6 +928,8 @@ fn make_callee_body(
|
|||
exception_edges: vec![],
|
||||
field_interner: crate::ssa::ir::FieldInterner::default(),
|
||||
field_writes: std::collections::HashMap::new(),
|
||||
|
||||
synthetic_externals: std::collections::HashSet::new(),
|
||||
},
|
||||
opt: crate::ssa::OptimizeResult {
|
||||
const_values: std::collections::HashMap::new(),
|
||||
|
|
@ -1361,6 +1375,7 @@ fn global_summaries_resolve_body_requires_body_present() {
|
|||
field_points_to: Default::default(),
|
||||
return_path_facts: smallvec::SmallVec::new(),
|
||||
typed_call_receivers: vec![],
|
||||
param_to_gate_filters: vec![],
|
||||
},
|
||||
);
|
||||
// Don't insert body
|
||||
|
|
@ -3504,6 +3519,7 @@ fn cf4_return_path_transform_serde_round_trip() {
|
|||
field_points_to: Default::default(),
|
||||
return_path_facts: smallvec::SmallVec::new(),
|
||||
typed_call_receivers: vec![],
|
||||
param_to_gate_filters: vec![],
|
||||
};
|
||||
let json = serde_json::to_string(&summary).unwrap();
|
||||
let back: SsaFuncSummary = serde_json::from_str(&json).unwrap();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue