Ssrf Cloud Metadata in Actix (Rust)
Ssrf Cloud Metadata in Actix with Rust — how this specific combination creates or exposes the vulnerability
Server-Side Request Forgery (SSRF) against cloud metadata endpoints is a high-impact concern when building Actix-based services in Rust. In many deployments, services rely on instance metadata services (for example, the AWS EC2 instance metadata at 169.254.169.254) to obtain credentials, configuration, or identity tokens. If an Actix application exposes an endpoint that accepts a URL and performs an HTTP request without strict allowlisting, an attacker can direct the service to the metadata address and retrieve sensitive cloud information.
Actix Web is a powerful Rust framework that makes it easy to define routes and compose middleware. However, convenience methods like web::block for offloading synchronous reqwest calls or custom handlers that forward user-supplied URLs can inadvertently create SSRF vectors. When the application forwards requests to a user-provided host without validating that the target is not a private or cloud metadata address, the unauthenticated attack surface includes cloud metadata endpoints. The scanner’s SSRF check tests for this by attempting to reach well-known metadata paths and inspecting whether responses contain cloud identity or sensitive configuration.
The risk is compounded in Rust because developers may assume that networking code is inherently safe, yet unsafe deserialization of headers, query parameters, or form fields can still lead to unintended destinations. For example, a handler that uses a raw string from a JSON payload to build a reqwest request can be tricked into accessing http://169.254.169.254/latest/meta-data/iam/security-credentials/. Because the scanner runs unauthenticated black-box tests, it can detect whether such metadata is reachable and whether the response includes sensitive data like instance profile names or temporary tokens.
In the context of the 12 parallel security checks, the SSRF detection aligns with data exposure and unsafe consumption risks. A successful metadata retrieval can lead to further attacks, such as using the exposed credentials to interact with other cloud services. The scanner reports this as a high-severity finding and provides remediation guidance, emphasizing input validation and destination allowlisting rather than relying on network-level restrictions alone.
Rust-Specific Remediation in Actix — concrete code fixes
To mitigate SSRF targeting cloud metadata in Actix services written in Rust, you must enforce strict destination allowlists and avoid forwarding user input directly to HTTP clients. Below are concrete, idiomatic code examples that demonstrate secure patterns.
Example 1: Safe request builder with allowlist validation
Instead of passing a user-provided URL to reqwest, validate the host against a set of permitted domains or a denylist of private and metadata ranges.
use actix_web::{web, HttpResponse};
use reqwest::Url;
fn is_allowed_host(url: &Url) -> bool {
let host = match url.host_str() {
Some(h) => h,
None => return false,
};
// Denylist cloud metadata and private ranges
let denylist = [
"169.254.169.254", // AWS EC2 metadata
"169.254.169.100", // GCP metadata (common range)
"metadata.google.internal", // GCP metadata DNS
"127.0.0.1",
"localhost",
];
if denylist.contains(&host) {
return false;
}
// Optionally, enforce a whitelist of known safe domains
let allowed_prefixes = ["api.github.com", "api.example.com"];
allowed_prefixes.iter().any(|p| host.ends_with(p))
}
async fn fetch_url(query: web::Query>) -> HttpResponse {
let url = match query.get("url").and_then(|s| Url::parse(s).ok()) {
Some(u) => u,
None => return HttpResponse::BadRequest().body("Invalid URL"),
};
if !is_allowed_host(&url) {
return HttpResponse::Forbidden().body("Destination not allowed");
}
match reqwest::get(url).await {
Ok(resp) => match resp.text().await {
Ok(text) => HttpResponse::Ok().body(text),
Err(_) => HttpResponse::InternalServerError().body("Failed to read response"),
},
Err(_) => HttpResponse::ServiceUnavailable().body("Request failed"),
}
}
Example 2: Using typed configuration instead of user-supplied URLs
When the use case permits, prefer configuration-driven endpoints over dynamic user input. This removes the SSRF vector entirely while still enabling legitimate integrations.
use actix_web::web;
struct IntegrationConfig {
base_url: String,
api_key: String,
}
async fn get_external_data(cfg: web::Data) -> HttpResponse {
let client = reqwest::Client::new();
let url = format!("{}/v1/resource", cfg.base_url);
match client.get(&url)
.bearer_auth(&cfg.api_key)
.send()
.await {
Ok(response) => match response.text().await {
Ok(text) => HttpResponse::Ok().body(text),
Err(_) => HttpResponse::InternalServerError().body("Failed to read response"),
},
Err(_) => HttpResponse::ServiceUnavailable().body("Request failed"),
}
}
These patterns ensure that cloud metadata endpoints are not reachable regardless of how a URL is supplied. The scanner’s findings will reflect reduced risk once such controls are in place, and you can track improvements using the middleBrick Web Dashboard or the CLI tool middlebrick scan <url> to verify remediation. For teams integrating into CI/CD, the middleBrick GitHub Action can enforce a minimum security score before deployment, while the MCP Server allows you to scan APIs directly from your Rust development environment.