Bleichenbacher Attack in Axum with Mutual Tls
Bleichenbacher Attack in Axum with Mutual Tls — how this specific combination creates or exposes the vulnerability
A Bleichenbacher attack exploits adaptive padding errors in RSA encryption, typically observed when a server reveals whether a decrypted ciphertext has valid padding. In an Axum service using Mutual TLS (mTLS), transport-layer authentication ensures both client and server present valid certificates, but it does not inherently protect application-layer cryptographic operations. If Axum (or the application built on it) performs RSA decryption of request data—such as encrypted API keys, JWTs, or session tokens—and returns distinct errors for padding failures versus other decryption failures, an attacker can iteratively craft ciphertexts to decrypt secret data without knowing the private key.
In the mTLS context, the attacker first establishes a valid TLS handshake using a compromised or rogue client certificate to bypass network-level access controls. Once the encrypted channel is established, the attacker sends manipulated ciphertexts to the Axum service, observing differences in HTTP status codes, response times, or error messages. Because mTLS only authenticates endpoints, the application remains responsible for validating and handling decrypted content securely. If the Axum application uses non-constant-time padding checks or exposes padding errors via responses, the attacker can gradually recover the plaintext, one byte at a time, leveraging the oracle created by the service’s behavior.
For example, an Axum endpoint that accepts encrypted JSON payloads and decrypts them using RSA-OAEP may inadvertently create an oracle when it returns a 400 error for invalid padding and a 401 for other failures. An attacker with a valid mTLS certificate can automate requests that tweak the ciphertext, using the response codes as feedback. This is not a flaw in mTLS itself, but a consequence of how the application handles decryption errors. The combination of mTLS and a vulnerable decryption routine can therefore amplify risk: mTLS provides strong identity assurance, but if the application layer leaks padding validation behavior, the encrypted data can be exfiltrated despite transport-layer security.
Real-world impact includes exposure of API keys, session tokens, or other sensitive payloads protected by RSA encryption. This aligns with OWASP API Top 10 controls around cryptography and data exposure, and can also intersect with insecure direct object references (BOLA/IDOR) when decrypted content includes identifiers. Unlike pure transport attacks, a Bleichenbacher oracle in an mTLS-enabled Axum service is particularly dangerous because the attacker must first obtain a valid client certificate, which can be achieved through compromised credentials, misconfigured issuance policies, or stolen certificates.
To detect this during a middleBrick scan, the engine runs parallel security checks including Input Validation, Authentication, and Data Exposure, while applying its LLM/AI Security module to identify patterns that could indicate adaptive padding behavior. The scanner cross-references OpenAPI specifications—resolving $ref definitions—with runtime responses to detect discrepancies in error handling that may expose cryptographic oracles. Even though mTLS is enforced at the transport layer, the scan focuses on application-level responses to ensure that padding errors do not become a side channel.
Mutual Tls-Specific Remediation in Axum — concrete code fixes
Remediation centers on ensuring that decryption operations do not leak information through timing or error messages. In Axum, this means using constant-time padding validation and avoiding early returns that distinguish between padding errors and other failures. Below are concrete code examples demonstrating secure handling of RSA decryption within an Axum handler.
1. RSA Decryption with Constant-Time Padding Check
Use cryptographic libraries that support constant-time operations. In Rust, the rsa crate combined with pkcs1 or pkcs8 can be configured to avoid early error differentiation.
use axum::{routing::post, Router};
use rsa::{RsaPrivateKey, PaddingScheme};
use std::sync::Arc;
struct AppState {
private_key: Arc,
}
async fn decrypt_handler(
State(state): State>,
Json(payload): Json,
) -> Result, (StatusCode, String)> {
let padding = PaddingScheme::new_pkcs1v15_encrypt();
let mut decrypted = vec![0u8; state.private_key.size()];
// Perform decryption; do not branch on padding errors
match state.private_key.decrypt(padding, &payload.ciphertext, &mut decrypted) {
Ok(len) => {
// Truncate to actual length without revealing which part failed
decrypted.truncate(len);
// Further validation should be constant-time where possible
let _ = validate_decrypted_data(&decrypted); // custom constant-time checks
Ok(Json(DecryptedPayload { data: decrypted }))
}
Err(_) => {
// Return a generic error to avoid leaking padding vs other failures
Err((StatusCode::BAD_REQUEST, String::from("decryption_failed")))
}
}
}
The key is to ensure that the error path does not reveal whether the failure was due to padding or another issue. Always return the same status code and message for any decryption failure.
2. mTLS Configuration in Axum with Tower
Enforce mTLS at the connection level using Tower middleware, ensuring that only clients with valid certificates can reach the Axum service. This does not fix application-layer crypto issues but reduces the attack surface.
use axum::Server;
use hyper_rustls::TlsAcceptor;
use std::net::SocketAddr;
use tokio_rustls::rustls::{ServerConfig, NoClientAuth};
async fn run_mtls_server() {
let mut config = ServerConfig::builder()
.with_safe_defaults()
.with_no_client_auth() // For mTLS, use WithClientCertVerifier
.with_client_cert_verifier(Arc::new(MyCertVerifier));
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
let make_svc = make_service_fn(|_conn| async { Ok::<_, Infallible>(service_fn(app)) };
let server = Server::builder(hyper_rustls::TlsAcceptor::from(Arc::new(config)))
.serve(make_svc);
server.await.unwrap();
}
Replace NoClientAuth with a proper client certificate verifier for mTLS. This ensures that only authenticated clients can initiate requests, but again, application-layer handling of decrypted data must remain constant-time and non-informative.
3. Secure Error Handling and Logging
Avoid logging decryption errors in a way that could aid an attacker. Ensure that logs do not include ciphertexts or partial decryption results.
// Bad: logs sensitive context
error!("Decryption failed: {:?}", err);
// Good: generic logging
error!("Decryption failed");
Combine these practices with regular middleBrick scans to verify that error responses remain uniform and that no cryptographic side channels are exposed.