GuardAPI Logo
GuardAPI

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 } }

System Alert • ID: 2173
Target: Rocket API
Potential Vulnerability

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.

RUN FREE SECURITY DIAGNOSTIC
GuardLabs Engine: ONLINE

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.