mirror of
https://github.com/elicpeter/nyx.git
synced 2026-06-12 19:55:14 +02:00
fixed some dynamic and static bugs and failing test cases
This commit is contained in:
parent
20093972a9
commit
ddf9ff13e2
10 changed files with 215 additions and 35 deletions
|
|
@ -221,11 +221,8 @@ pub static RULES: &[LabelRule] = &[
|
|||
label: DataLabel::Sink(Cap::HTML_ESCAPE),
|
||||
case_sensitive: false,
|
||||
},
|
||||
LabelRule {
|
||||
matchers: &["res.redirect"],
|
||||
label: DataLabel::Sink(Cap::SSRF),
|
||||
case_sensitive: false,
|
||||
},
|
||||
// `res.redirect` is OPEN_REDIRECT only (see the dedicated rule below): a
|
||||
// 302 to the browser is client-side navigation, not SSRF.
|
||||
LabelRule {
|
||||
matchers: &["res.sendFile", "res.download"],
|
||||
label: DataLabel::Sink(Cap::FILE_IO),
|
||||
|
|
@ -911,6 +908,37 @@ pub static GATED_SINKS: &[SinkGate] = &[
|
|||
object_destination_fields: &["url", "prefixUrl"],
|
||||
},
|
||||
},
|
||||
// `request` npm library: `request.get(url)` / `request.post(url, …)`. The
|
||||
// Destination gate fires only on a tainted URL arg, so the `req.get(header)`
|
||||
// header-read collision (constant arg 0) never activates.
|
||||
SinkGate {
|
||||
callee_matcher: "request.get",
|
||||
arg_index: 0,
|
||||
dangerous_values: &[],
|
||||
dangerous_prefixes: &[],
|
||||
label: DataLabel::Sink(Cap::SSRF),
|
||||
case_sensitive: false,
|
||||
payload_args: &[0],
|
||||
keyword_name: None,
|
||||
dangerous_kwargs: &[],
|
||||
activation: GateActivation::Destination {
|
||||
object_destination_fields: &["url", "uri"],
|
||||
},
|
||||
},
|
||||
SinkGate {
|
||||
callee_matcher: "request.post",
|
||||
arg_index: 0,
|
||||
dangerous_values: &[],
|
||||
dangerous_prefixes: &[],
|
||||
label: DataLabel::Sink(Cap::SSRF),
|
||||
case_sensitive: false,
|
||||
payload_args: &[0],
|
||||
keyword_name: None,
|
||||
dangerous_kwargs: &[],
|
||||
activation: GateActivation::Destination {
|
||||
object_destination_fields: &["url", "uri"],
|
||||
},
|
||||
},
|
||||
// `undici.request(url | opts[, opts])`, opts exposes `origin` and
|
||||
// `path`. Body-ish fields (`body`, `headers`) are excluded.
|
||||
SinkGate {
|
||||
|
|
|
|||
|
|
@ -670,6 +670,31 @@ pub fn is_js_ts_handler_param_name(name: &str) -> bool {
|
|||
false
|
||||
}
|
||||
|
||||
/// Bare bindings denoting an Express/Koa request sub-object when the handler
|
||||
/// param is destructured (`({ query }, res) => …`). Kept out of
|
||||
/// [`is_js_ts_handler_param_name`] so a plain param named `query`/`body` is
|
||||
/// never seeded; the SSA seeder additionally requires a sibling response param.
|
||||
const JS_TS_REQUEST_FIELD_NAMES: &[&str] =
|
||||
&["query", "body", "params", "headers", "cookies", "cookie"];
|
||||
|
||||
/// True when `name` is a bare destructured request-field binding. Only
|
||||
/// meaningful behind the destructured-handler-param gate in the SSA seeder.
|
||||
pub fn is_express_request_field_name(name: &str) -> bool {
|
||||
JS_TS_REQUEST_FIELD_NAMES
|
||||
.iter()
|
||||
.any(|candidate| candidate.eq_ignore_ascii_case(name))
|
||||
}
|
||||
|
||||
/// True for the conventional Express/Koa/Fastify response-object parameter
|
||||
/// (`res`/`response`/`reply`) — the structural signal that a function is a
|
||||
/// route handler, so a sibling destructured `{ query }` is a real source.
|
||||
pub fn is_handler_response_param_name(name: &str) -> bool {
|
||||
matches!(
|
||||
name.to_ascii_lowercase().as_str(),
|
||||
"res" | "response" | "reply"
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn lookup(lang: &str, raw: &str) -> Kind {
|
||||
CLASSIFIERS
|
||||
|
|
|
|||
|
|
@ -528,13 +528,12 @@ pub static GATED_SINKS: &[SinkGate] = &[
|
|||
// is a `Location: ...` header, so the dashboard / OWASP bucket
|
||||
// correctly classifies redirect-class flows independently of CRLF.
|
||||
//
|
||||
// Activation: arg 0 prefix `Location:` (case-insensitive). When arg
|
||||
// 0 is a constant string starting with `Location:` the gate fires and
|
||||
// checks payload arg 0 for taint; constants like `Content-Type: ...`
|
||||
// are suppressed by the safe-literal branch. When arg 0 is a binary
|
||||
// expression (`"Location: " . $url`) or otherwise dynamic, the
|
||||
// value-extraction returns `None` and the gate fires conservatively
|
||||
// — matching the existing convention in `setAttribute`/`parseFromString`.
|
||||
// Fires only on a positive `Location:` literal at arg 0 (a constant, or a
|
||||
// concat whose leading literal is `Location:` — `extract_const_string_arg`
|
||||
// returns the left-most literal). `LiteralOnly` makes the dynamic/unknown
|
||||
// case suppress rather than fire conservatively, so `header($notALocation)`
|
||||
// and 404-status-line forms no longer mis-classify as OPEN_REDIRECT. The
|
||||
// flat HEADER_INJECTION sink above still fires on any tainted `header()`.
|
||||
SinkGate {
|
||||
callee_matcher: "=header",
|
||||
arg_index: 0,
|
||||
|
|
@ -545,7 +544,7 @@ pub static GATED_SINKS: &[SinkGate] = &[
|
|||
payload_args: &[0],
|
||||
keyword_name: None,
|
||||
dangerous_kwargs: &[],
|
||||
activation: GateActivation::ValueMatch,
|
||||
activation: GateActivation::LiteralOnly,
|
||||
},
|
||||
// Smarty `$smarty->fetch($name)` — only the `string:` resource prefix
|
||||
// accepts an inline template *source*; the bare form (`page.tpl`) is a
|
||||
|
|
|
|||
|
|
@ -186,11 +186,8 @@ pub static RULES: &[LabelRule] = &[
|
|||
label: DataLabel::Sink(Cap::HTML_ESCAPE),
|
||||
case_sensitive: false,
|
||||
},
|
||||
LabelRule {
|
||||
matchers: &["res.redirect"],
|
||||
label: DataLabel::Sink(Cap::SSRF),
|
||||
case_sensitive: false,
|
||||
},
|
||||
// `res.redirect` is OPEN_REDIRECT only (dedicated rule below): a 302 to the
|
||||
// browser is client-side navigation, not SSRF.
|
||||
LabelRule {
|
||||
matchers: &["res.sendFile", "res.download"],
|
||||
label: DataLabel::Sink(Cap::FILE_IO),
|
||||
|
|
@ -693,6 +690,36 @@ pub static GATED_SINKS: &[SinkGate] = &[
|
|||
object_destination_fields: &["url", "prefixUrl"],
|
||||
},
|
||||
},
|
||||
// `request` npm library: `request.get(url)` / `request.post(url, …)`.
|
||||
// Destination gate fires only on a tainted URL arg. Mirrors javascript.rs.
|
||||
SinkGate {
|
||||
callee_matcher: "request.get",
|
||||
arg_index: 0,
|
||||
dangerous_values: &[],
|
||||
dangerous_prefixes: &[],
|
||||
label: DataLabel::Sink(Cap::SSRF),
|
||||
case_sensitive: false,
|
||||
payload_args: &[0],
|
||||
keyword_name: None,
|
||||
dangerous_kwargs: &[],
|
||||
activation: GateActivation::Destination {
|
||||
object_destination_fields: &["url", "uri"],
|
||||
},
|
||||
},
|
||||
SinkGate {
|
||||
callee_matcher: "request.post",
|
||||
arg_index: 0,
|
||||
dangerous_values: &[],
|
||||
dangerous_prefixes: &[],
|
||||
label: DataLabel::Sink(Cap::SSRF),
|
||||
case_sensitive: false,
|
||||
payload_args: &[0],
|
||||
keyword_name: None,
|
||||
dangerous_kwargs: &[],
|
||||
activation: GateActivation::Destination {
|
||||
object_destination_fields: &["url", "uri"],
|
||||
},
|
||||
},
|
||||
SinkGate {
|
||||
callee_matcher: "undici.request",
|
||||
arg_index: 0,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue