GuardAPI Logo
GuardAPI

Fix SSRF (Server Side Request Forgery) in Poem

SSRF in the Poem framework typically manifests when a handler accepts a user-provided URL and fetches it using an HTTP client like `reqwest`. Without validation, an attacker can probe internal services, hit metadata endpoints (169.254.169.254), or bypass firewalls by forcing the server to act as a proxy.

The Vulnerable Pattern

use poem::{handler, web::Query, Route, listener::TcpListener, Server};
use serde::Deserialize;

#[derive(Deserialize)] struct Params { url: String }

#[handler] async fn proxy(Query(res): Query) -> String { // VULNERABLE: Direct use of user input in outbound request reqwest::get(&res.url).await.unwrap().text().await.unwrap() }

#[tokio::main] async fn main() { let app = Route::new().at(”/”, proxy); Server::new(TcpListener::bind(“127.0.0.1:3000”)).run(app).await.unwrap(); }

The Secure Implementation

The secure implementation mitigates SSRF by applying a multi-layered defense. First, it parses the input into a structured URL to prevent obfuscation attacks. Second, it enforces the HTTPS scheme to stop protocol smuggling (e.g., file:// or gopher://). Third, it implements a strict domain allowlist. For production-grade hardening, use a custom DNS resolver with the HTTP client to verify that the resolved IP address is not in a private or loopback range (e.g., 10.0.0.0/8, 127.0.0.1) before the request is dispatched, preventing DNS rebinding attacks.

use poem::{handler, web::Query, error::BadRequestError, Result};
use url::Url;
use serde::Deserialize;

#[derive(Deserialize)] struct Params { url: String }

fn validate_url(input: &str) -> Option { let parsed = Url::parse(input).ok()?; let host = parsed.host_str()?;

// 1. Enforce HTTPS
if parsed.scheme() != "https" { return None; }

// 2. Strict Domain Allowlist
let allowed_domains = ["api.trusted.com", "cdn.assets.io"];
if !allowed_domains.contains(&host) { return None; }

Some(parsed)

}

#[handler] async fn secure_proxy(Query(res): Query) -> Result { let validated_url = validate_url(&res.url).ok_or(BadRequestError)?;

let client = reqwest::Client::builder()
    .timeout(std::time::Duration::from_secs(5))
    .build().map_err(|_| BadRequestError)?;

let body = client.get(validated_url.as_str())
    .send().await.map_err(|_| BadRequestError)?
    .text().await.map_err(|_| BadRequestError)?;

Ok(body)

}

System Alert • ID: 4017
Target: Poem API
Potential Vulnerability

Your Poem API might be exposed to SSRF (Server Side Request Forgery)

74% of Poem 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.