HIGH path traversalactixapi keys

Path Traversal in Actix with Api Keys

Path Traversal in Actix with Api Keys — how this specific combination creates or exposes the vulnerability

Path Traversal occurs when an API endpoint uses user-supplied input to construct file system paths without adequate validation or sanitization. In Actix web applications, this typically manifests through route parameters, query strings, or request headers that influence which file is opened. When Api Keys are used for identification but not tightly coupled to authorization checks, the risk profile changes in two ways.

First, an Api Key can grant access to a broader set of endpoints or data directories than intended. If a key is scoped to a tenant or customer, but the application resolves paths like format!("/var/data/{}", user_input) without enforcing tenant boundaries, a request with a valid key can traverse outside the allowed directory. Second, logging and audit mechanisms that include the Api Key can inadvertently expose keys in log files stored in parent directories if path construction is not controlled, creating a secondary exposure path.

Consider an Actix handler that serves user documents:

use actix_web::{web, HttpResponse, Responder};
use std::path::PathBuf;

async fn get_document(
    path: web::Path,
    api_key: web::Header<String>,
) -> impl Responder {
    let base = "/srv/documents";
    let requested = path.into_inner();
    let full_path = PathBuf::from(base).join(requested);
    // Unsafe: no validation of `full_path` is within base
    actix_files::NamedFile::open(full_path).map_err(|e| ... )
}

If an attacker provides ../../../etc/passwd as path, the resolved path escapes the intended directory. The presence of a valid Api Key in the header does not mitigate this; it only confirms that the request comes from an authenticated client, not that the requested resource is authorized. This is distinct from authentication failures because the key is accepted, but path resolution is unsafe.

The interaction with middleware can exacerbate the issue. If an Actix middleware extracts the Api Key and attaches it to request extensions for downstream handlers, but those handlers later use unchecked user input in paths, the key’s presence creates a false sense of security. The key identifies the caller but does not constrain the filesystem namespace the caller is allowed to traverse.

Real-world analogies include CVE-2021-23352 patterns where path traversal in Rust web servers allowed reading arbitrary files when query parameters were concatenated without normalization. In an Actix context, the same class of vulnerability emerges whenever PathBuf::join or similar operations are driven by unchecked input, regardless of how the request was authenticated.

Api Keys-Specific Remediation in Actix — concrete code fixes

Remediation focuses on ensuring that Api Key authentication is paired with strict path confinement and input validation. Do not rely on the key alone to enforce data isolation; enforce it in the handler logic.

1. Use a base directory and validate that the resolved path remains within it. Prefer canonicalize and prefix checks:

use actix_web::{web, HttpResponse, Responder};
use std::path::{Path, PathBuf};

async fn get_document(
    path: web::Path,
    api_key: web::Header<String>,
    // Assume a function that maps key to allowed tenant directory
    key_to_dir: web::Data<KeyToDirService>,
) -> impl Responder {
    let requested = path.into_inner();
    let tenant_dir = key_to_dir
        .get_dir_for_key(&api_key)
        .unwrap_or("/srv/documents"); // fallback

    let base = Path::new(tenant_dir);
    let requested_path = Path::new(&requested);

    // Normalize and resolve
    let resolved = base.join(requested_path).canonicalize().map_err(|e| {
        actix_web::error::ErrorBadRequest("invalid path")
    })?;

    // Ensure the resolved path is still within base after canonicalization
    if !resolved.starts_with(base) {
        return HttpResponse::Forbidden().finish();
    }

    actix_files::NamedFile::open(resolved).map_err(|e| ... )
}

2. If Api Keys are tied to specific scopes or prefixes, encode those constraints in the path itself. For example, if each key maps to a subdirectory, include that subdirectory as a static segment and reject any user input that attempts to escape it:

use actix_web::web;
use std::path::PathBuf;

async fn scoped_get(
    path: web::Path<(String, String)>, // (key_segment, user_file)
) -> Result<impl Responder, actix_web::Error> {
    let (key_segment, user_file) = path.into_inner();
    // key_segment is part of the route or derived from Api Key mapping
    let mut full = PathBuf::from("/srv/data");
    full.push(key_segment);
    // Further restrict: do not allow additional traversal beyond key_segment
    if user_file.contains("..") || user_file.starts_with('/') {
        return Err(actix_web::error::ErrorBadRequest("invalid"));
    }
    full.push(user_file);
    // ... open file
    Ok(actix_files::NamedFile::open(full)?)
}

3. Leverage Actix extractors to centralize path validation. Create a custom extractor that normalizes and bounds the path before it reaches the handler:

use actix_web::{dev::Payload, FromRequest, HttpMessage, HttpRequest};
use std::future::{ready, Ready};
use std::path::PathBuf;

struct SafePath(PathBuf);

impl FromRequest for SafePath {
    type Error = actix_web::Error;
    type Future = Ready<Result<Self, Self::Error>>;

    fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
        let path_str = req.match_info().get("path");
        match path_str {
            Some(raw) => {
                // Basic guard: reject sequences that escape
                if raw.contains("..") || raw.ends_with('/') {
                    ready(Err(actix_web::error::ErrorBadRequest("invalid")))
                } else {
                    let base = PathBuf::from("/srv/tenant");
                    let resolved = base.join(raw).canonicalize().unwrap_or(base);
                    if resolved.starts_with(&base) {
                        ready(Ok(SafePath(resolved)))
                    } else {
                        ready(Err(actix_web::error::ErrorForbidden()))
                    }
                }
            }
            None => ready(Err(actix_web::error::ErrorBadRequest("missing path"))),
        }
    }
}

// Usage in route:
// async fn handler(safe: SafePath) { ... }

These examples show how Api Key context can inform directory scoping while path validation remains strict. The key enables tenant selection, but the handler must still enforce filesystem boundaries explicitly.

Related CWEs: inputValidation

CWE IDNameSeverity
CWE-20Improper Input Validation HIGH
CWE-22Path Traversal HIGH
CWE-74Injection CRITICAL
CWE-77Command Injection CRITICAL
CWE-78OS Command Injection CRITICAL
CWE-79Cross-site Scripting (XSS) HIGH
CWE-89SQL Injection CRITICAL
CWE-90LDAP Injection HIGH
CWE-91XML Injection HIGH
CWE-94Code Injection CRITICAL

Frequently Asked Questions

Can middleware that reads Api Keys inadvertently enable path traversal?
Middleware that extracts Api Keys and attaches them to request extensions does not introduce path traversal by itself. However, if downstream handlers use unchecked user input in file paths, the presence of a key does not constrain filesystem access. Ensure path validation is independent of authentication data.
How does middleBrick report on Path Traversal in Actix with Api Keys?
middleBrick scans unauthenticated attack surfaces and tests path resolution using techniques such as directory traversal sequences (e.g., ../../../etc/passwd). It checks whether the endpoint respects intended boundaries and reports findings with severity and remediation guidance, mapping to relevant frameworks like OWASP API Top 10.