Zip Slip in Actix with Mutual Tls
Zip Slip in Actix with Mutual Tls — how this specific combination creates or exposes the vulnerability
Zip Slip is a path traversal vulnerability that occurs when an API constructs file paths by directly concatenating user-supplied input with a base directory. In Actix applications that also enforce Mutual TLS (mTLS), the presence of client certificate authentication can create a false sense of security. Operators may assume that because mTLS strongly authenticates clients, input validation and path sanitization are less critical. This assumption is dangerous: mTLS does not limit what an authenticated client can request the server to do. An authenticated client can still supply malicious path fragments (e.g., ../../etc/passwd) that traverse directories if the server does not strictly validate and sanitize paths.
When mTLS is enabled in Actix, the server verifies client certificates before application logic runs. If the application layer then uses unchecked user input to build filesystem paths—such as when extracting archives or serving uploaded files—an attacker authenticated via mTLS can exploit path traversal to read arbitrary files or write outside the intended directory. The combination exposes the vulnerability because mTLS reduces the attack surface to authenticated identities but does not constrain the operations those identities can request. For example, an authenticated service account might have permissions to read configuration files, and a Zip Slip payload can leverage that access to exfiltrate sensitive data.
Consider an Actix endpoint that accepts a filename and extracts a zip archive into a configured directory. If the code does not canonicalize and validate each entry against the base directory, an archive containing entries like ../../../secrets/config.yaml can escape the target location. The mTLS handshake completes successfully, but the server performs no additional checks on the archive contents. This specific combination—mTLS for transport and identity assurance plus unchecked path construction—amplifies the impact by allowing authenticated clients to reach sensitive files they should not access.
Mutual Tls-Specific Remediation in Actix — concrete code fixes
To remediate Zip Slip in Actix while using Mutual TLS, focus on strict path validation and isolation of user input, independent of the mTLS layer. Always canonicalize and verify that resolved paths remain within the intended base directory. Below are concrete, secure patterns for Actix with Rust.
1. Secure path resolution utility
Use a helper that canonicalizes and validates paths. This utility should reject any path that escapes the base directory, regardless of client certificate status.
use std::path::{Path, PathBuf};
/// Ensure a requested path is within the allowed base directory.
/// Returns `Ok(SanitizedPath)` or an error.
fn sanitize_path(base: &Path, requested: &str) -> std::io::Result<PathBuf> {
// Normalize the requested path to remove `.` and `..` components
let requested_path = Path::new(requested).components().collect::>();
let mut resolved = base.to_path_buf();
for component in requested_path {
match component {
std::path::Component::Normal(segment) => resolved.push(segment),
// Explicitly reject parent directory traversal attempts
std::path::Component::ParentDir => return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"path traversal detected",
)),
// Reject absolute paths and other unsafe components
_ => return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"invalid path component",
)),
}
}
// Ensure the final path is canonical and still within base
let canonical = resolved.canonicalize()?;
if canonical.starts_with(base) {
Ok(canonical)
} else {
Err(std::io::Error::new(
std::io::ErrorKind::PermissionDenied,
"path escapes base directory",
))
}
}
2. Actix handler using mTLS and safe path handling
In your Actix handler, enforce mTLS (via middleware or extractor) and then apply path sanitization before any filesystem operation.
use actix_web::{web, HttpResponse, Result};
use std::path::PathBuf;
async fn download_file(
// Assume mTLS client identity is available via request extensions or a custom extractor
req: actix_web::HttpRequest,
path: web::Path, // user-supplied filename or subpath
) -> Result<HttpResponse> {
let base_dir = PathBuf::from("/srv/allowed-directory");
// Validate and sanitize the user input
let safe_path = sanitize_path(&base_dir, &path).map_err(|e| {
actix_web::error::ErrorBadRequest(e.to_string())
})?;
// Perform filesystem operations only on the sanitized path
let contents = tokio::fs::read(safe_path).await.map_err(|e| {
actix_web::error::ErrorInternalServerError(e.to_string())
})?;
Ok(HttpResponse::Ok().body(contents))
}
3. Middleware or extractor for mTLS (example integration)
Ensure mTLS is enforced before reaching handlers. This example shows a lightweight guard that checks client certificate presence and subject; integrate with your certificate verification pipeline as needed.
use actix_web::{dev::ServiceRequest, Error, middleware::Next};
use actix_web::body::BoxBody;
use actix_web::http::StatusCode;
use actix_web::middleware::Next;
use actix_web::dev::ServiceResponse;
use std::future::{ready, Ready};
/// A simple guard that checks if mTLS client cert is present.
/// Replace with your actual certificate validation logic.
async fn verify_client_cert(req: &ServiceRequest) -> Result<(), Error> {
// In practice, inspect TLS peer certificate from request extensions
let cert_present = true; // placeholder for real check
if cert_present {
Ok(())
} else {
Err(actix_web::error::ErrorUnauthorized("missing client certificate"))
}
}
/// A guard function usable in Actix route configuration.
fn with_mtls() -> impl Fn(ServiceRequest, Next<BoxBody>) -> _ {
|req, srv| {
let fut = verify_client_cert(&req);
async move {
match fut.await {
Ok(_) => srv.call(req).await,
Err(e) => Ok(ServiceResponse::new(
req.into_parts().0,
BoxBody::default(),
).with_status(StatusCode::UNAUTHORIZED).map_into_right_body()),
}
}
}
}
By combining these patterns, you ensure that authenticated clients cannot exploit Zip Slip: path validation is strict, and mTLS only handles identity, not authorization over paths. This approach aligns with secure-by-default practices and reduces the risk of directory traversal in Actix services using Mutual TLS.