HIGH padding oracleaxum

Padding Oracle in Axum

How Padding Oracle Manifests in Axum

Padding Oracle attacks exploit the behavior of cryptographic implementations when handling invalid padding during decryption. In Axum applications, this vulnerability typically manifests when using AES-CBC encryption for session tokens, JWTs, or other sensitive data transmitted between client and server.

The core issue arises when Axum handlers return different responses based on whether padding validation fails versus authentication failures. An attacker can exploit this timing difference or error message variation to gradually decrypt ciphertext without knowing the encryption key.

In Axum, this often appears in authentication middleware or session management code. Consider a typical implementation where session tokens are encrypted and sent as cookies:

use axum::extract::CookieJar;
use aes::Aes256Cbc;
use block_modes::BlockMode;
use hex::FromHex;

async fn protected_handler(
    Extension(secret_key): Extension<Vec<u8>>,
    cookies: CookieJar,
) -> impl IntoResponse {
    let token = cookies.get("session")?.value();
    let ciphertext = Vec::from_hex(token).unwrap();
    
    let cipher = Aes256Cbc::new_var(secret_key.as_slice(), &[0u8; 16]).unwrap();
    let decrypted = cipher.decrypt_vec(&ciphertext).unwrap();
    
    // If decryption fails with padding error, different response is returned
    // This timing difference is what the attacker exploits
    
    (Status::OK, "Authenticated successfully")
}

The vulnerability occurs because decrypt_vec returns different error types for padding failures versus authentication failures. An attacker can send modified ciphertext and observe whether the server responds with a padding error or a different error, allowing them to mount a chosen-ciphertext attack.

Another Axum-specific manifestation occurs when using tokio-postgres or similar database libraries where encrypted data is retrieved and decrypted. If error handling reveals whether decryption failed due to padding versus other reasons, the same vulnerability exists:

async fn get_user_data(
    pool: PgPool,
    id: i32,
) -> Result<impl IntoResponse> {
    let client = pool.get().await?;
    let row = sqlx::query!("SELECT encrypted_data FROM users WHERE id = $1", id)
        .fetch_one(&client)
        .await?;
    
    let encrypted = row.encrypted_data;
    let cipher = Aes256Cbc::new_var(key.as_slice(), &[0u8; 16]).unwrap();
    
    // This line may panic or return different errors based on padding
    let decrypted = cipher.decrypt_vec(&encrypted).map_err(|e| {
        if e.to_string().contains("padding") {
            // Different error path revealed
            ApiError::PaddingError
        } else {
            ApiError::DecryptionError
        }
    })?;
    
    Ok((Status::OK, decrypted))
}

The key insight is that Axum's async/await pattern and error handling can inadvertently create timing channels or error message variations that leak information about padding validity.

Axum-Specific Detection

Detecting Padding Oracle vulnerabilities in Axum applications requires both static analysis and dynamic testing. The middleBrick API security scanner includes specialized checks for Axum-specific patterns that commonly lead to padding oracle vulnerabilities.

middleBrick's detection engine identifies several Axum-specific indicators:

Static Analysis Patterns

The scanner examines your Axum route handlers for cryptographic operations that could be vulnerable. It looks for:

  • Direct use of block_modes::BlockMode decrypt operations without constant-time error handling
  • Cookie extraction followed by immediate decryption without uniform error responses
  • Database queries that return encrypted data processed in route handlers
  • Custom error types that differentiate between padding and other decryption failures

Dynamic Testing

middleBrick actively tests your Axum endpoints by:

  1. Intercepting encrypted tokens in cookies or headers
  2. Modifying the last block of ciphertext to test padding behavior
  3. Measuring response times and error message variations
  4. Checking for uniform error responses regardless of padding validity

To use middleBrick for Axum applications:

# Install middleBrick CLI
npm install -g middlebrick

# Scan your Axum API endpoint
middlebrick scan https://api.yourdomain.com/auth

# Or use the GitHub Action in your CI/CD
- uses: middlebrick/middlebrick-action@v1
  with:
    url: https://api.yourdomain.com
    fail_below: B

The scanner provides specific findings for Axum applications, including:

  • Exact line numbers where vulnerable decryption occurs
  • Recommended Axum middleware patterns to fix the issue
  • Comparison with OWASP API Security Top 10 A10: Insufficient Logging & Monitoring

Manual Testing Methodology

For deeper investigation, you can manually test your Axum application:

# Capture an encrypted cookie
curl -b "session=YOUR_ENCRYPTED_TOKEN" https://api.yourdomain.com/protected

# Modify the last byte and observe response
# If you get different errors for valid vs invalid padding, you have a vulnerability

middleBrick's LLM/AI security features also check if your Axum application processes encrypted AI-related data, as padding oracle attacks can be particularly damaging when targeting AI model parameters or training data.

Axum-Specific Remediation

Fixing Padding Oracle vulnerabilities in Axum requires a combination of proper cryptographic practices and uniform error handling. The most secure approach is to use authenticated encryption modes that don't allow padding oracle attacks.

Recommended Approach: Use AES-GCM

Replace CBC mode with AES-GCM, which provides authenticated encryption:

use axum::extract::CookieJar;
use aes_gcm::Aes256Gcm;
use hex::FromHex;

async fn protected_handler(
    Extension(secret_key): Extension<Vec<u8>>,
    cookies: CookieJar,
) -> impl IntoResponse {
    let token = cookies.get("session")?.value();
    let ciphertext = Vec::from_hex(token).unwrap();
    
    // Use AES-GCM instead of CBC
    let cipher = Aes256Gcm::new(secret_key.as_slice());
    let nonce = &ciphertext[0..12]; // First 12 bytes are nonce
    let ciphertext = &ciphertext[12..];
    
    // This will return Err on any authentication failure
    // No timing differences between padding and authentication failures
    let decrypted = cipher.decrypt(nonce, ciphertext.as_ref()).unwrap();
    
    (Status::OK, "Authenticated successfully")
}

Alternative: Constant-Time CBC with Uniform Error Handling

If you must use CBC mode, implement constant-time error handling:

use axum::extract::CookieJar;
use aes::Aes256Cbc;
use block_modes::BlockMode;
use subtle::ConstantTimeEq;
use hex::FromHex;

async fn protected_handler(
    Extension(secret_key): Expression<Vec<u8>>,
    cookies: CookieJar,
) -> impl IntoResponse {
    let token = cookies.get("session")?.value();
    let ciphertext = Vec::from_hex(token).unwrap();
    
    let cipher = Aes256Cbc::new_var(secret_key.as_slice(), &[0u8; 16]).unwrap();
    
    // Always perform decryption, even if padding is invalid
    let decrypted = cipher.decrypt_vec(&ciphertext);
    
    // Use constant-time comparison for any validation
    let is_valid = decrypted.is_ok() && validate_data(&decrypted.unwrap());
    
    // Return uniform response regardless of why decryption failed
    if is_valid {
        (Status::OK, "Authenticated successfully")
    } else {
        (Status::UNAUTHORIZED, "Invalid session")
    }
}

fn validate_data(data: &[u8]) -> bool {
    // Constant-time validation of decrypted data
    // Never reveal whether padding was the issue
    data.len() == 32 && data[0] == 0x01
}

Axum Middleware Pattern

Create reusable middleware for uniform error handling:

use axum::middleware::Next;
use axum::response::IntoResponse;
use tower::BoxError;

async fn padding_oracle_protection(
    mut req: axum::http::Request<axum::body::Bytes>,
    next: Next<'_, axum::body::Bytes>,
) -> Result<impl IntoResponse, BoxError> {
    let res = next.run(req).await;
    
    // Ensure uniform response times and error messages
    // This prevents timing attacks from leaking information
    Ok(res.map_err(|_| "Authentication failed".into()))
}

// Add to your Axum app
let app = Router::new()
    .route("/protected", get(protected_handler))
    .layer(axum::middleware::from_fn(padding_oracle_protection));

Additional Security Measures

  • Implement rate limiting on authentication endpoints to slow down padding oracle attacks
  • Use middleBrick's continuous monitoring to detect when padding oracle vulnerabilities reappear after code changes
  • Log all decryption failures with consistent severity levels
  • Consider using token-based authentication (JWT) with proper validation instead of encrypted cookies

middleBrick's remediation guidance specifically recommends these Axum patterns and provides code examples tailored to your application's structure.

Frequently Asked Questions

How can I test if my Axum application has padding oracle vulnerabilities?
Use middleBrick's dynamic scanning by running middlebrick scan https://yourapi.com. The scanner will actively test your endpoints by modifying encrypted tokens and analyzing response variations. You can also manually test by capturing encrypted cookies, modifying the last byte, and observing whether error messages or response times differ between valid and invalid padding.
Does middleBrick detect padding oracle vulnerabilities in Axum applications?
Yes, middleBrick includes specialized detection for Axum applications. It identifies cryptographic operations in route handlers, tests for timing differences in error responses, and checks for uniform error handling. The scanner provides specific findings with line numbers and Axum-specific remediation recommendations. Pro plan users get continuous monitoring that automatically re-tests after code changes.