Pii Leakage in Actix with Api Keys
Pii Leakage in Actix with Api Keys — how this specific combination creates or exposes the vulnerability
Actix is a popular Rust web framework that enables high-performance APIs. When developers use API keys for authentication in Actix without additional safeguards, PII (personally identifiable information) can be inadvertently exposed through logs, error messages, or misconfigured middleware. API keys often appear in request headers, query parameters, or environment configurations. If these keys are logged in full alongside user data, or if error responses reveal details about authentication failures in the presence of PII, the combination creates a leakage path.
For example, an Actix handler that authenticates via an API key and then returns user profile information might log the key for debugging. If that log entry also contains the user’s email or name, an attacker with log access can correlate the API key with PII. Similarly, misconfigured tracing or metrics middleware might capture headers indiscriminately, storing API keys and associated PII together. In some cases, developers inadvertently include sensitive user data in responses when authentication succeeds but authorization is not enforced, allowing an attacker who obtains an API key to access other users’ PII through horizontal privilege boundaries.
Another vector involves error handling. If an Actix application returns detailed errors when an API key is invalid, and those errors include stack traces or variable dumps that contain PII, an attacker can harvest both authentication artifacts and sensitive user information. The framework’s default debug handlers or unwinding behavior can amplify this risk when combined with insufficient input validation or missing data minimization practices. Even middleware that adds security headers or rate limiting might inadvertently log request bodies or headers that contain PII alongside API keys if not carefully configured.
These risks are compounded when API keys are passed in non-standard headers or cookies, which may bypass existing logging filters that expect keys in the Authorization header. Without consistent redaction and strict separation between authentication material and user data, the attack surface expands. middleBrick’s scans detect scenarios where unauthenticated endpoints expose data patterns resembling PII and flag insecure handling of API keys in request flows, providing findings mapped to OWASP API Top 10 and relevant compliance guidance.
Api Keys-Specific Remediation in Actix — concrete code fixes
Remediation focuses on preventing API keys and PII from coexisting in logs, error outputs, or responses. Below are concrete Actix examples that demonstrate secure patterns.
1. Avoid logging API keys
Ensure logging middleware or custom log formats exclude sensitive headers. Use a sanitizing logger wrapper.
use actix_web::{web, App, HttpServer, HttpRequest, HttpResponse, middleware::Logger};
use std::env;
fn sanitize_headers(req: &HttpRequest) -> String {
let api_key = req.headers().get("X-API-Key");
match api_key {
Some(_) => "X-API-Key: [REDACTED]".to_string(),
None => "X-API-Key: missing".to_string(),
}
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
HttpServer::new(|| {
App::new()
.wrap(Logger::custom(|req, resp| {
format!("{} - {} {} {} {}",
req.method(),
req.path(),
resp.status(),
sanitize_headers(req),
resp.response_time().as_millis()
)
}))
.route("/profile", web::get().to(profile_handler))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
async fn profile_handler(req: HttpRequest) -> HttpResponse {
// Authentication without exposing key in logs or response
let api_key = match req.headers().get("X-API-Key") {
Some(v) => v.to_str().unwrap_or(""),
None => return HttpResponse::Unauthorized().json(serde_json::json!({ "error": "missing_key" })),
};
// Validate key (pseudocode)
if !is_valid_key(api_key) {
return HttpResponse::Forbidden().json(serde_json::json!({ "error": "invalid_key" }));
}
// Fetch user data (ensure PII fields are limited)
let user_data = get_user_data_minimal(); // returns only necessary fields
HttpResponse::Ok().json(user_data)
}
fn is_valid_key(key: &str) -> bool {
// Constant-time comparison recommended in production
key == env::var("EXPECTED_API_KEY").unwrap_or_default()
}
fn get_user_data_minimal() -> serde_json::Value {
// Return minimal PII, avoid exposing emails or identifiers unless required
serde_json::json!({ "role": "user", "scope": "read" })
}
2. Separate authentication from response data
Use extractor guards to ensure API keys are validated before any PII is constructed or serialized. Avoid returning detailed user objects when only authentication status is needed.
use actix_web::{web, App, HttpServer, HttpResponse, Error};
use actix_web::http::header::HeaderValue;
struct ApiKey(pub String);
impl actix_web::FromRequest for ApiKey {
type Error = Error;
type Future = std::future::Ready<Result<Self, Self::Error>>;
type Config = ();
fn from_request(req: &actix_web::HttpRequest, _: &mut actix_web::dev::Payload) -> Self::Future {
let valid = match req.headers().get("X-API-Key") {
Some(hv) => validate_key(hv.to_str().unwrap_or("")),
None => false,
};
let fut = if valid {
Ok(ApiKey(req.headers().get("X-API-Key").unwrap().to_str().unwrap().to_string()))
} else {
Err(actix_web::error::ErrorUnauthorized("invalid key"))
};
std::future::ready(fut)
}
}
fn validate_key(key: &str) -> bool {
key == "super-secret-key"
}
async fn restricted_endpoint(_key: ApiKey, user_id: web::Path<u32>) -> HttpResponse {
// At this point, key is validated; return minimal data
let response = format!({{ "user_id": {} }}, user_id);
HttpResponse::Ok().body(response)
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.route("/user/{user_id}", web::get().to(restricted_endpoint))
})
.bind("127.0.0.1:8081")?
.run()
.await
}
3. Redact PII in error paths and middleware
Ensure error responses do not include API keys or PII. Use custom error types and avoid exposing internal state.
use actix_web::{web, App, HttpServer, HttpResponse, ResponseError};
use actix_web::error::ErrorUnauthorized;
use serde::Serialize;
#[derive(Serialize)]
struct ErrorResponse {
error: String,
}
impl ResponseError for ApiKeyMissing {
fn error_response(&self) -> HttpResponse {
HttpResponse::Unauthorized().json(ErrorResponse {
error: "authentication required".to_string(),
})
}
}
struct ApiKeyMissing;
async fn handler_with_gated_data(key: ApiKey) -> Result<HttpResponse, ApiKeyMissing> {
// Simulate PII-gated data access
if has_user_consent() {
Ok(HttpResponse::Ok().json(serde_json::json!({ "data": "safe" })))
} else {
Err(ApiKeyMissing)
}
}
fn has_user_consent() -> bool {
// Placeholder for consent check
true
}
fn main() {}
These patterns ensure API keys are handled separately from PII, reducing the risk of combined leakage. middleBrick can detect scenarios where endpoints expose both authentication artifacts and PII, helping teams prioritize fixes.
Related CWEs: dataExposure
| CWE ID | Name | Severity |
|---|---|---|
| CWE-200 | Exposure of Sensitive Information | HIGH |
| CWE-209 | Error Information Disclosure | MEDIUM |
| CWE-213 | Exposure of Sensitive Information Due to Incompatible Policies | HIGH |
| CWE-215 | Insertion of Sensitive Information Into Debugging Code | MEDIUM |
| CWE-312 | Cleartext Storage of Sensitive Information | HIGH |
| CWE-359 | Exposure of Private Personal Information (PII) | HIGH |
| CWE-522 | Insufficiently Protected Credentials | CRITICAL |
| CWE-532 | Insertion of Sensitive Information into Log File | MEDIUM |
| CWE-538 | Insertion of Sensitive Information into Externally-Accessible File | HIGH |
| CWE-540 | Inclusion of Sensitive Information in Source Code | HIGH |