HIGH ssrf server sideaxumfirestore

Ssrf Server Side in Axum with Firestore

Ssrf Server Side in Axum with Firestore — how this specific combination creates or exposes the vulnerability

Server-side request forgery (SSRF) in an Axum service that interacts with Google Cloud Firestore can occur when user-controlled input is used to form Firestore document IDs, collection paths, or Firestore-backed URLs for metadata or export operations. Axum routes typically capture parameters (e.g., id) and pass them into Firestore client calls. If these parameters are used directly to construct document references or to request external resources (such as Google Cloud Storage signed URLs or Firestore export URLs) without strict validation, an attacker can induce the server to reach internal metadata endpoints or unintended internal services.

For example, a route like /items/{id} might resolve a Firestore document by concatenating a user-supplied id into a path such as items/{id}. If the id can be set to a crafted value like http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token, and the server uses an HTTP client to fetch that URL to enrich Firestore data, the server can leak instance metadata. Even when using the Firestore client library, developers sometimes introduce SSRF by using user input to control Firestore export destinations or to build URLs for custom backend-for-frontend logic that reads from Firestore and proxies remote resources.

Common triggers include:

  • Using user input to form Firestore document or collection names that include host-like segments, which are later interpreted as URLs by auxiliary services.
  • Passing user input into an HTTP client on the server to fetch remote data that is then stored in or retrieved from Firestore.
  • Constructing Firestore export or backup URLs with user-controlled paths, enabling redirection to internal endpoints.
  • Trusting metadata or configuration values stored in Firestore that refer to external endpoints without strict allowlisting.

Because Firestore operations often require authentication, SSRF on the server can be combined with over-permissive service account credentials, increasing the blast radius if an internal endpoint is reachable.

Firestore-Specific Remediation in Axum — concrete code fixes

Remediation focuses on strict input validation, allowlisting, and avoiding user-controlled URLs in server-side logic. In Axum, use path extractors and strong validation layers to ensure identifiers conform to expected patterns before they are used in Firestore calls. Prefer mapping IDs to Firestore document keys via server-side lookup tables or regex patterns rather than direct concatenation.

Example: validate an item ID against a strict pattern and resolve the Firestore document server-side without echoing user input into URLs or metadata requests.

use axum::{routing::get, Router};
use google_cloud_firestore::client::Client;
use serde::Deserialize;
use std::net::SocketAddr;
use validator::Validate;

#[derive(Deserialize, Validate)]
struct ItemParams {
    #[validate(length(min = 1), custom(function = "validate_item_id"))]
    id: String,
}

fn validate_item_id(id: &str) -> Result<(), validator::ValidationErrors> {
    // Allow only alphanumeric and hyphens; prevent URL-like inputs
    let re = regex::Regex::new(r"^[a-zA-Z0-9\-]+$").unwrap();
    if re.is_match(id) {
        Ok(())
    } else {
        Err(validator::ValidationErrors::new())
    }
}

async fn get_item_handler(
    params: axum::extract::Query,
    client: &Client,
) -> Result {
    let ItemParams { id } = params.0;
    // Use server-side mapping; do not construct Firestore paths from raw user input
    let doc_ref = client.collection("items").document(&id);
    let snapshot = doc_ref.get().await.map_err(|e| (axum::http::StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
    if snapshot.exists() {
        Ok(snapshot.decode::().map_err(|e| (axum::http::StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?.to_string())
    } else {
        Err((axum::http::StatusCode::NOT_FOUND, "Item not found".to_string()))
    }
}

#[tokio::main]
async fn main() {
    let client = Client::new().await.expect("Firestore client");
    let app = Router::new().route("/items/:id", get(|axum::extract::Path(params): axum::extract::Path, client: axum::extract::State<Client>| async move {
        get_item_handler(axum::extract::Query(params), &client).await
    }));
    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
    axum::Server::bind(&addr)
        .serve(app.into_make_service())
        .await
        .unwrap();
}

Additional measures:

  • Never use user input to construct Firestore export or backup URLs; perform exports server-side with fixed paths and controlled service account permissions.
  • If you must fetch remote resources, use an allowlisted set of domains and avoid forwarding user input as URLs.
  • Apply least-privilege IAM roles to the Firestore service account to limit access to internal metadata endpoints.
  • Use Axum middleware to sanitize and validate inputs centrally before they reach handlers.

Frequently Asked Questions

Can SSRF in Axum with Firestore expose metadata endpoints?
Yes, if user-controlled input is used to form Firestore document IDs or URLs that trigger server-side HTTP requests, an attacker can redirect the server to internal metadata services such as http://metadata.google.internal. Validate and allowlist all inputs and avoid using raw user input in HTTP client calls.
How does middleBrick help detect SSRF in Firestore integrations?
middleBrick scans unauthenticated attack surfaces and tests input validation and request handling across 12 security checks, including SSRF patterns that could affect Firestore integrations in Axum. It returns a risk score with prioritized findings and remediation guidance without making changes to your environment.