mirror of
https://github.com/elicpeter/nyx.git
synced 2026-06-15 20:05:13 +02:00
feat(surface): make attack surface first-class in the finding pipeline
This commit is contained in:
parent
c9776a5caf
commit
1abcdedbfe
48 changed files with 1591 additions and 214 deletions
27
src/rank.rs
27
src/rank.rs
|
|
@ -55,6 +55,32 @@ pub fn compute_attack_rank(diag: &Diag) -> AttackRank {
|
|||
components.push(("evidence".into(), format!("{evidence_bonus}")));
|
||||
}
|
||||
|
||||
// ── 3b. Surface exposure ────────────────────────────────────────────
|
||||
//
|
||||
// A finding reachable from a surface entry-point is more exploitable
|
||||
// than an internal one; reachable *without auth* more so. Transitive
|
||||
// reach (through the call graph rather than in the handler's own
|
||||
// file) is slightly discounted because the file-level reach map can
|
||||
// over-approximate. Magnitudes keep the severity tier ordering: the
|
||||
// maximum exposure bonus (+10) plus all other Medium-tier bonuses
|
||||
// stays below the High severity base (see tier tests).
|
||||
if let Some(exp) = &diag.exposure {
|
||||
let mut exposure_bonus = if exp.auth_required { 4.0 } else { 10.0 };
|
||||
if exp.transitive {
|
||||
exposure_bonus -= 2.0;
|
||||
}
|
||||
score += exposure_bonus;
|
||||
let auth_tag = if exp.auth_required {
|
||||
"auth-gated"
|
||||
} else {
|
||||
"unauthenticated"
|
||||
};
|
||||
components.push((
|
||||
"exposure".into(),
|
||||
format!("{exposure_bonus:+} ({auth_tag})"),
|
||||
));
|
||||
}
|
||||
|
||||
// ── 4. State finding sub-ranking ────────────────────────────────────
|
||||
let state_bonus = state_finding_bonus(&diag.id);
|
||||
score += state_bonus;
|
||||
|
|
@ -421,6 +447,7 @@ mod tests {
|
|||
evidence: None,
|
||||
rank_score: None,
|
||||
rank_reason: None,
|
||||
exposure: None,
|
||||
suppressed: false,
|
||||
suppression: None,
|
||||
triage_state: "open".to_string(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue