Poodle Attack in Axum
How Poodle Attack Manifests in Axum
The Poodle attack (CVE-2014-3566) is a padding oracle attack that exploits the insecure CBC padding in SSL 3.0. An attacker can force a connection to downgrade to SSL 3.0 and then decrypt sensitive data like session cookies or API tokens. For Axum-based APIs, the vulnerability manifests depending on how TLS is handled.
Axum applications can serve HTTPS directly using TLS libraries such as native-tls or rustls, or they can sit behind a reverse proxy that terminates TLS. In both cases, if SSL 3.0 is enabled, the endpoint is vulnerable.
The Poodle attack is particularly dangerous for APIs because it can lead to unauthorized access to sensitive data and violation of compliance standards such as PCI-DSS (requirement 4.1) and GDPR. It is listed under OWASP API Top 10 2023 as part of "Security Misconfiguration".
When Axum handles TLS directly with native-tls, the vulnerability arises if the min_protocol_version is set to Protocol::Ssl3 or if the system's default TLS configuration allows SSL 3.0 (unlikely on modern systems). For example, the following Axum server configuration explicitly enables SSL 3.0:
use axum::Server;
use native_tls::TlsAcceptor;
use std::net::SocketAddr;
let addr: SocketAddr = "0.0.0.0:8443".parse().unwrap();
let tls_acceptor = TlsAcceptor::builder()
.min_protocol_version(Some(native_tls::Protocol::Ssl3)) // VULNERABLE
.build()?;
let server = Server::bind(addr)
.serve(tls_acceptor.into());
Even if you do not set min_protocol_version, native-tls defaults to the system's supported protocols. On some legacy systems, SSL 3.0 might be enabled by default, so it's crucial to explicitly set a minimum of TLS 1.2.
Axum applications using rustls are generally safe because rustls does not implement SSL 3.0 at all. However, if you use a custom configuration that somehow includes SSL 3.0 (which is impossible with current rustls), you would be vulnerable. The default rustls configuration only supports TLS 1.2 and 1.3.
If your Axum API is behind a reverse proxy such as nginx, Apache, or HAProxy, the TLS termination happens at the proxy. A misconfigured proxy that allows SSL 3.0 will expose your API to Poodle attacks, regardless of Axum's own configuration. For instance, an nginx configuration with ssl_protocols SSLv3 TLSv1; is vulnerable.
The attack typically proceeds as follows: an attacker intercepts the connection and manipulates the handshake to force SSL 3.0 (by blocking higher protocol versions). Once the connection is established using SSL 3.0, the attacker exploits the CBC padding vulnerability to gradually decrypt bytes of encrypted data. This can lead to theft of authentication tokens, personal data, or other sensitive information transmitted over the API.
Thus, ensuring that your Axum API does not support SSL 3.0 is critical for maintaining confidentiality and integrity.
Axum-Specific Detection
Detecting SSL 3.0 support can be done manually or via automated scanners. middleBrick includes an "Encryption" check that actively tests for Poodle vulnerability. When you submit your API endpoint to middleBrick, it attempts to establish a connection using SSL 3.0. If the server responds with a successful handshake, middleBrick flags a high-severity finding in the Encryption category, along with remediation guidance.
The middleBrick report will show a finding like "SSL 3.0 supported" with a description of the risk and steps to disable SSL 3.0. Because middleBrick scans in 5–15 seconds and requires no credentials, you can quickly verify your API's TLS configuration as part of development or CI/CD.
middleBrick's Encryption check not only tests for SSL 3.0 but also evaluates other TLS weaknesses like weak ciphers and protocol versions, providing a comprehensive view of your API's encryption posture.
For manual verification, you can use OpenSSL:
openssl s_client -connect api.example.com:443 -ssl3If the handshake succeeds (you see SSL-Session: details), SSL 3.0 is enabled. If it fails with protocol version error, SSL 3.0 is disabled. Tools like testssl.sh or nmap --script ssl-enum-ciphers provide more comprehensive checks.
It's important to test both the direct Axum server (if it handles TLS) and any reverse proxy in front of it. middleBrick tests the endpoint as an external client would, so it will detect SSL 3.0 support regardless of whether it's the Axum app or the proxy.
Additionally, middleBrick's scanning includes resolution of OpenAPI specifications, so it can correlate TLS findings with specific API endpoints if the spec is available.
Axum-Specific Remediation
Remediation depends on where TLS is terminated.
Remember that TLS configuration is a critical part of your API's security posture and should be regularly audited, especially after updates or changes in dependencies.
If Axum uses native-tls directly: Configure the TlsAcceptor to require at least TLS 1.2:
use axum::Server;
use native_tls::TlsAcceptor;
use std::net::SocketAddr;
let addr: SocketAddr = "0.0.0.0:8443".parse().unwrap();
let tls_acceptor = TlsAcceptor::builder()
.min_protocol_version(Some(native_tls::Protocol::Tls12)) // Disables SSL 3.0, TLS 1.0, TLS 1.1
.build()?;
let server = Server::bind(addr)
.serve(tls_acceptor.into());
You may also set max_protocol_version to limit to TLS 1.2 and 1.3 if desired. Additionally, configure strong cipher suites using cipher_list (e.g., "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256" for TLS 1.3, and "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384" for TLS 1.2).
If Axum uses rustls: The default configuration is already safe. However, if you have a custom ServerConfig, ensure you are not including rustls::ProtocolVersion::SSL3 (which is not defined). The safe default is:
use rustls::ServerConfig;
use rustls::crypto::ring::default_provider;
use std::sync::Arc;
fn main() {
default_provider().install().unwrap();
let signing_key: Arc = unimplemented!(); // Load from certificate in practice
let config = ServerConfig::builder()
.with_safe_defaults()
.with_no_client_auth()
.build(signing_key).unwrap();
// use config with axum::Server::builder(...).serve(...)
}
If behind a reverse proxy: Update the proxy configuration to disable SSL 3.0. For nginx:
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
For Apache:
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
After making changes, re-run middleBrick to verify that SSL 3.0 is no longer accepted. Note that disabling SSL 3.0 may prevent very old clients (e.g., Windows XP IE6) from connecting, but these clients are obsolete and pose a security risk. The trade-off is worthwhile for modern security.
For a quick reference, see the table below:
| Component | Vulnerable Setting | Secure Setting |
|---|---|---|
| native-tls | min_protocol_version(Some(Protocol::Ssl3)) | min_protocol_version(Some(Protocol::Tls12)) |
| nginx | ssl_protocols SSLv3 TLSv1; | ssl_protocols TLSv1.2 TLSv1.3; |
By ensuring SSL 3.0 is disabled at every layer, you protect your Axum API from Poodle attacks and maintain compliance with standards like PCI-DSS and OWASP API Top 10.