Fix SSRF (Server Side Request Forgery) in Rocket
SSRF in Rocket apps usually hits when you're blindly piping user-supplied URLs into a client like 'reqwest'. If you don't validate the destination, an attacker can pivot into your internal network, hit the AWS metadata service (169.254.169.254), or scan your local k8s services. In Rust, the 'reqwest' default settings won't save you from a determined probe.
The Vulnerable Pattern
#[get("/fetch?")]
async fn fetch_api(target: &str) -> String {
// POISON: Blindly trusting the 'target' parameter
let res = reqwest::get(target).await.unwrap();
res.text().await.unwrap()
}
The Secure Implementation
The fix involves a multi-layered defense: First, we enforce HTTPS to prevent protocol smuggling (gopher://, file://). Second, we perform manual DNS resolution before the request is made. This allows us to inspect the actual IP address and block private ranges (RFC 1918) and link-local addresses (AWS/GCP metadata endpoints). Note that to fully prevent DNS Rebinding, you should ideally use the resolved IP directly in the request and verify the SNI/Host header separately, or use a client with a custom DNS resolver that filters at the socket level.
use std::net::IpAddr; use url::Url; use rocket::http::Status;#[get(“/fetch?
”)] async fn secure_fetch(target: &str) -> Result<String, Status> { let parsed = Url::parse(target).map_err(|_| Status::BadRequest)?; // 1. Protocol Whitelisting if parsed.scheme() != "https" { return Err(Status::BadRequest); } // 2. DNS Resolution & IP Blacklisting let host = parsed.host_str().ok_or(Status::BadRequest)?; let addrs = tokio::net::lookup_host(format!("{}:443", host)) .await .map_err(|_| Status::InternalServerError)?; for addr in addrs { let ip = addr.ip(); if ip.is_loopback() || ip.is_multicast() || is_private_ip(ip) { return Err(Status::Forbidden); } } let client = reqwest::Client::builder() .timeout(std::time::Duration::from_secs(5)) .build().unwrap(); let body = client.get(target).send().await.map_err(|_| Status::BadGateway)? .text().await.map_err(|_| Status::InternalServerError)?; Ok(body)}
fn is_private_ip(ip: IpAddr) -> bool { match ip { IpAddr::V4(v4) => v4.is_private() || v4.is_link_local(), IpAddr::V6(_) => true, // Simplified: block all IPv6 if not explicitly needed } }
Your Rocket API
might be exposed to SSRF (Server Side Request Forgery)
74% of Rocket apps fail this check. Hackers use automated scanners to find this specific flaw. Check your codebase before they do.
Free Tier • No Credit Card • Instant Report
Verified by Ghost Labs Security Team
This content is continuously validated by our automated security engine and reviewed by our research team. Ghost Labs analyzes over 500+ vulnerability patterns across 40+ frameworks to provide up-to-date remediation strategies.