use crate::http_client::HttpResponse;
use tracing::debug;
pub fn is_cdn_protected(response: &HttpResponse) -> Option<String> {
if response.header("cf-ray").is_some()
|| response.header("cf-cache-status").is_some()
|| response
.header("server")
.map(|s| s.contains("cloudflare"))
.unwrap_or(false)
{
return Some("Cloudflare".to_string());
}
if response.header("x-amz-cf-id").is_some()
|| response.header("x-amz-cf-pop").is_some()
|| response
.header("via")
.map(|s| s.contains("CloudFront"))
.unwrap_or(false)
{
return Some("AWS CloudFront".to_string());
}
if response.header("x-akamai-request-id").is_some()
|| response.header("akamai-grn").is_some()
|| response
.header("server")
.map(|s| s.contains("AkamaiGHost"))
.unwrap_or(false)
{
return Some("Akamai".to_string());
}
if response
.header("x-served-by")
.map(|s| s.contains("cache"))
.unwrap_or(false)
|| response.header("x-fastly-request-id").is_some()
|| response.header("fastly-io-info").is_some()
{
return Some("Fastly".to_string());
}
if response.header("x-azure-ref").is_some() || response.header("x-fd-healthprobe").is_some() {
return Some("Azure Front Door".to_string());
}
if response
.header("via")
.map(|s| s.contains("1.1 google"))
.unwrap_or(false)
|| response.header("x-goog-generation").is_some()
{
return Some("Google Cloud CDN".to_string());
}
if response
.header("x-cdn")
.map(|s| s.contains("Incapsula"))
.unwrap_or(false)
|| response.header("x-iinfo").is_some()
{
return Some("Incapsula".to_string());
}
if response.header("x-sucuri-id").is_some() || response.header("x-sucuri-cache").is_some() {
return Some("Sucuri".to_string());
}
if response.header("x-sp-cache-status").is_some() || response.header("x-sp-server").is_some() {
return Some("StackPath".to_string());
}
if response
.header("server")
.map(|s| s.contains("keycdn"))
.unwrap_or(false)
|| response.header("x-keycdn-cache-status").is_some()
{
return Some("KeyCDN".to_string());
}
if response.header("x-bunny-cache").is_some()
|| response.header("bunny-cache-status").is_some()
|| response.header("cdn-pullzone").is_some()
|| response
.header("server")
.map(|s| s.contains("bunny"))
.unwrap_or(false)
{
return Some("Bunny CDN".to_string());
}
if response.header("x-cache").is_some()
|| response.header("x-cache-status").is_some()
|| response.header("cdn-cache-control").is_some()
{
return Some("Generic CDN".to_string());
}
None
}
pub fn is_waf_protected_against_cve(response: &HttpResponse, cve_id: &str) -> Option<String> {
let cdn = is_cdn_protected(response)?;
if cve_id == "CVE-2025-55182" {
match cdn.as_str() {
"Cloudflare" => {
debug!("Target is behind Cloudflare WAF - CVE-2025-55182 is blocked by default");
return Some("Cloudflare WAF (rule deployed Dec 2, 2025)".to_string());
}
"AWS CloudFront" => {
debug!("Target may be protected by AWS WAF - verify WAF rules are enabled");
return Some("AWS WAF (verify rules are enabled)".to_string());
}
"Akamai" => {
debug!("Target may be protected by Akamai - verify App & API Protector is enabled");
return Some("Akamai (verify App & API Protector)".to_string());
}
_ => {}
}
}
if cve_id == "CVE-2025-55183" {
match cdn.as_str() {
"Cloudflare" => {
debug!("Target is behind Cloudflare WAF - CVE-2025-55183 is blocked by default");
return Some("Cloudflare WAF (rule 17c5123f/3114709a)".to_string());
}
"AWS CloudFront" => {
debug!("Target may be protected by AWS WAF - verify WAF rules are enabled");
return Some("AWS WAF (verify rules are enabled)".to_string());
}
"Akamai" => {
debug!("Target may be protected by Akamai - verify App & API Protector is enabled");
return Some("Akamai (verify App & API Protector)".to_string());
}
_ => {}
}
}
if cve_id == "CVE-2025-55184" {
match cdn.as_str() {
"Cloudflare" => {
debug!("Target is behind Cloudflare WAF - CVE-2025-55184 is blocked by default");
return Some("Cloudflare WAF (rule 2694f161)".to_string());
}
"AWS CloudFront" => {
debug!("Target may be protected by AWS WAF - verify WAF rules are enabled");
return Some("AWS WAF (verify rules are enabled)".to_string());
}
"Akamai" => {
debug!("Target may be protected by Akamai - verify App & API Protector is enabled");
return Some("Akamai (verify App & API Protector)".to_string());
}
_ => {}
}
}
None
}
pub fn get_scanners_to_skip_for_cdn(cdn_name: &str) -> Vec<String> {
debug!(
"Target is CDN-protected ({}), skipping server-side tests",
cdn_name
);
vec![
"sqli".to_string(), "command_injection".to_string(), "path_traversal".to_string(), "nosql".to_string(), "ldap_injection".to_string(), "xxe".to_string(), "template_injection".to_string(), "code_injection".to_string(), "ssi_injection".to_string(), "xml_injection".to_string(), "xpath_injection".to_string(), ]
}
pub fn get_scanners_for_cdn() -> Vec<String> {
vec![
"xss".to_string(), "cors".to_string(), "security_headers".to_string(), "clickjacking".to_string(), "open_redirect".to_string(), "crlf_injection".to_string(), "cache_poisoning".to_string(), "host_header_injection".to_string(), ]
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
#[test]
fn test_cloudflare_detection() {
let mut headers = HashMap::new();
headers.insert("cf-ray".to_string(), "123456".to_string());
let response = HttpResponse {
status_code: 200,
body: String::new(),
headers,
duration_ms: 0,
};
assert_eq!(is_cdn_protected(&response), Some("Cloudflare".to_string()));
}
#[test]
fn test_aws_cloudfront_detection() {
let mut headers = HashMap::new();
headers.insert("x-amz-cf-id".to_string(), "abc123".to_string());
let response = HttpResponse {
status_code: 200,
body: String::new(),
headers,
duration_ms: 0,
};
assert_eq!(
is_cdn_protected(&response),
Some("AWS CloudFront".to_string())
);
}
#[test]
fn test_no_cdn() {
let response = HttpResponse {
status_code: 200,
body: String::new(),
headers: HashMap::new(),
duration_ms: 0,
};
assert_eq!(is_cdn_protected(&response), None);
}
}