Phishing Api Keys in Actix with Mutual Tls
Phishing API Keys in Actix with Mutual TLS — how this specific combination creates or exposes the vulnerability
When an Actix web service uses mutual TLS (mTLS) for client authentication, the presence of a valid client certificate strongly signals that the request is trusted. If the application then leaks an API key—whether in logs, error messages, HTTP redirects, or JSON error payloads—an attacker who has obtained or spoofed a certificate can use that signal to phish for additional credentials. The mTLS layer provides transport assurance but does not prevent the application from inadvertently exposing secrets, so the combination can amplify the impact of a key leak.
For example, an Actix endpoint that authenticates with mTLS and returns a detailed error containing an AWS access key in a JSON field creates a phishing vector: an attacker with a valid cert can make repeated requests and harvest keys from verbose responses. This pattern maps to common OWASP API Top 10 risks such as Improper Error Handling and Sensitive Data Exposure. Even with mTLS, if the API key is embedded in client-side JavaScript, stored insecurely, or echoed in logs, a phishing site can trick a user or integration into revealing the key, especially if the key appears in predictable locations like query parameters or headers that are logged by backend services.
In an unauthenticated black-box scan, middleBrick tests for data exposure by probing endpoints that accept client certificates and checking whether API keys appear in responses or redirects. The LLM/AI Security checks run active prompt injection-style probes and inspect outputs for PII and API keys. Even without authentication bypass, an API key returned in a 500 error or a redirect Location header can be captured and reused. This is especially relevant when mTLS is used for identity assurance but developers assume it also hides sensitive data, leading to insufficient output validation and insecure default behaviors.
An example of a risky pattern in Actix occurs when a handler uses .map_err to convert errors and inadvertently includes secrets in the response body. Consider a handler that reads a bearer token or API key from a header and, on failure, returns a detailed message containing the key. Even with mTLS ensuring the client is who they claim, the key is exposed to anyone who can trigger the error path. The scanner checks for such exposures across response codes and content types, noting whether keys appear in JSON, XML, or plain text.
middleBrick’s OpenAPI/Swagger spec analysis helps identify risky endpoints by resolving $ref chains and cross-referencing definitions with runtime findings. If the spec defines security schemes for mTLS but does not restrict which headers or query parameters can be returned in errors, the scan highlights the gap. The tool also checks for missing input validation and improper error handling, which are common contributors to key leakage. By correlating spec intent with actual responses, the scanner shows where mTLS is present but data exposure controls are weak.
Remediation guidance emphasizes treating mTLS as one layer and never assuming it protects sensitive data. Developers should sanitize all outputs, avoid echoing secrets in responses or logs, and enforce strict error formats that do not include keys. Rate limiting and monitoring can reduce the impact of phishing attempts that rely on repeated key harvesting. In the CI/CD flow, the GitHub Action can enforce a threshold so that builds fail if any endpoint returns patterns resembling API keys in error payloads, preventing risky code from reaching production.
Mutual TLS-Specific Remediation in Actix — concrete code fixes
Secure Actix applications should combine mTLS with strict output hygiene and explicit error handling to prevent API key leakage. Below are concrete code examples that demonstrate how to configure mTLS and ensure API keys are never exposed.
use actix_web::{web, App, HttpResponse, HttpServer, Responder};
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
fn create_ssl_config() -> SslAcceptor {
let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
builder.set_private_key_file("key.pem", SslFiletype::PEM).unwrap();
builder.set_certificate_chain_file("cert.pem").unwrap();
// Require client certificates for mTLS
builder.set_verify(openssl::ssl::SslVerifyMode::PEER | openssl::ssl::SslVerifyMode::FAIL_IF_NO_PEER_CERT);
builder.check_private_key().unwrap();
builder.build()
}
async fn handler_with_mtls(req: actix_web::HttpRequest) -> impl Responder {
// Avoid logging or returning API keys
let api_key = req.headers().get("X-API-Key");
match api_key {
Some(key) if is_valid_key(key) => HttpResponse::Ok().json(serde_json::json!({ "status": "ok" })),
Some(_) => {
// Return a generic error without exposing the key
HttpResponse::Unauthorized().json(serde_json::json!({ "error": "invalid_key" }))
}
None => HttpResponse::BadRequest().json(serde_json::json!({ "error": "missing_key" })),
}
}
fn is_valid_key(key: &actix_web::http::HeaderValue) -> bool {
// Validate key format without echoing it
key.to_str().map(|s| s.starts_with("ak_")).unwrap_or(false)
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let ssl = create_ssl_config();
HttpServer::new(|| {
App::new()
.wrap(actix_web::middleware::Logger::default())
.route("/secure", web::get().to(handler_with_mtls))
})
.bind_openssl("127.0.0.1:8443", ssl)?
.run()
.await
}
This example shows how to require client certificates and handle API keys safely. The key is read from headers but never included in responses or logs. Generic error messages prevent attackers from harvesting information. The middleware and handlers avoid panics that could leak stack traces or keys, and the SSL builder enforces peer verification.
Another important practice is to avoid storing API keys in places that could be exposed via misconfigured logging. In Actix, you can customize the Logger to redact sensitive headers:
use actix_web::middleware::Logger;
let logger = Logger::builder()
.format(|buf, req| {
// Redact API key from logs
if let Some(key) = req.headers().get("X-API-Key") {
buf.write_fmt(format_args!(r#" X-API-Key: "#)).unwrap();
buf.write_all(b"[REDACTED]").unwrap();
} else {
buf.write_fmt(format_args!(r#" X-API-Key: "#)).unwrap();
buf.write_all(b"-").unwrap();
}
// Continue with other fields as needed
})
.build();
By redacting sensitive headers in logs, you reduce the risk that API keys are inadvertently stored or exposed through log aggregation systems. The scanner checks whether endpoints return API keys in responses and whether logs could contain sensitive data, so these mitigations help align runtime behavior with secure design expectations.
For CI/CD, the middleBrick CLI can be integrated so that each build runs a scan against staging endpoints. If any response contains patterns resembling API keys, the job can fail before deployment. This ensures that code paths which could expose keys are caught early, complementing mTLS with automated prevention. The dashboard and alerts further support ongoing monitoring, helping teams detect regressions in how errors handle sensitive data.