Http Request Smuggling in Actix with Hmac Signatures
Http Request Smuggling in Actix with Hmac Signatures — how this specific combination creates or exposes the vulnerability
HTTP request smuggling arises when an API gateway or intermediary parses HTTP messages differently than the backend service. In Actix-based services that use HMAC signatures to authenticate requests, smuggling can occur if the signature is computed over a message representation that diverges from how the server reconstructs the request. If the client computes the HMAC over the raw body bytes and the server parses headers or body differently before verification, an attacker can craft requests where the interpreted body and the signature verification input are misaligned.
Consider an Actix web service that expects a JSON body and validates an HMAC passed in a custom header (for example, X-API-Signature). If the application reads the request payload into a buffer for signing, but later forwards or parses the stream with different chunking or buffering logic (for example, due to middleware that clones the body or uses message-level framing), the byte sequence used to compute the HMAC may not match the bytes the server uses for routing or business logic. This mismatch can allow an attacker to smuggle a request such that one part of the message is interpreted by the signature-verification step and another part by a handler or proxy, bypassing intended integrity checks.
A concrete example involves an API that uses chunked transfer encoding. The client computes the HMAC over the concatenated chunks (the canonical representation of the body) and sends the chunks. If Actix or an intermediate layer re-chunks or buffers differently before verifying the signature, the server might verify the signature against one chunk arrangement while processing a different arrangement as the effective request. This can lead to request splitting or parameter confusion, sometimes aligned with BOLA/IDOR or BFLA patterns when the misinterpreted request targets a different resource or permission context. Because the signature validates only the byte stream the client intended, but the server interprets a different effective stream, the integrity guarantee is broken, and smuggling becomes practical.
In the context of the 12 checks run by middleBrick, this scenario maps to Input Validation, Property Authorization, and Unsafe Consumption. An unauthenticated scan can surface these inconsistencies in how the API surface normalizes and verifies requests with HMACs, especially when combined with OpenAPI/Swagger spec analysis where $ref definitions and runtime behavior diverge. The scanner does not fix the protocol mismatch, but it highlights the discrepancy between declared message formats and runtime parsing, which is a prerequisite for smuggling in HMAC-protected flows.
Because middleBrick performs black-box testing without credentials, it can detect whether an API exposes endpoints where HMAC-verified requests interact with request parsing in risky ways. The findings include severity-ranked guidance to align how the body is represented for signing and how it is consumed, which reduces the window for request smuggling. Remember, middleBrick detects and reports; remediation requires changes to how the server normalizes and verifies requests before business logic executes.
Hmac Signatures-Specific Remediation in Actix — concrete code fixes
To mitigate smuggling when using HMAC signatures in Actix, ensure the byte sequence used to compute and verify the signature is identical to the sequence used by the server for routing and processing. This typically means normalizing the request before signing and enforcing strict parsing rules. Below are concrete code examples for a secure approach.
First, compute the HMAC over the raw request body exactly as received, and avoid any re-encoding or re-chunking before verification. In Actix, you can read the payload into a Bytes object, compute the signature, and then decide whether to forward or process the body. The following snippet shows a middleware-like extractor that validates an HMAC before the handler runs:
use actix_web::{dev::ServiceRequest, Error, HttpMessage};
use actix_web::http::header::HeaderValue;
use hmac::{Hmac, Mac};
use sha2::Sha256;
type HmacSha256 = Hmac<Sha256>;
async fn validate_hmac(req: ServiceRequest) -> Result<ServiceRequest, Error> {
// read the body as bytes once
let body = req.payload().take(8192).to_bytes().await?; // adjust limit as needed
let signature_header = req.headers().get("X-API-Signature")
.ok_or_else(|| actix_web::error::ErrorBadRequest("missing signature"))?;
let received_sig = signature_header.to_str().map_err(|_| actix_web::error::ErrorBadRequest("invalid signature encoding"))?;
let mut mac = HmacSha256::new_from_slice(b"your-secure-secret")
.map_err(|_| actix_web::error::ErrorInternalServerError("hmac setup error"))?;
mac.update(&body);
let computed_sig = mac.finalize().into_bytes();
let computed_b64 = base64::encode(computed_sig);
if subtle::ConstantTimeEq::ct_eq(received_sig.as_bytes(), computed_b64.as_bytes()).into() {
req.extensions_mut().insert(body);
Ok(req)
} else {
Err(actix_web::error::ErrorUnauthorized("invalid signature"))
}
}
This example reads the body once, computes HMAC-SHA256 over those exact bytes, and compares using constant-time equality. The body is stored in request extensions for downstream handlers so it is not re-parsed or re-chunked, preserving the byte identity used for signing.
Second, if you must forward or transform the request (for example, in a proxy or gateway), canonicalize the body before recomputing the HMAC. Do not rely on framework-specific chunking or streaming behavior that can vary between layers. The following snippet shows how to reconstruct a canonical body and verify before passing the request along:
async fn forward_with_hmac(url: &str, mut req: ServiceRequest) -> Result<actix_web::HttpResponse, Error> {
let body = req.payload().take(8192).to_bytes().await?;
let mut mac = HmacSha256::new_from_slice(b"your-secure-secret")?;
mac.update(&body);
let sig = mac.finalize().into_bytes();
let signature_b64 = base64::encode(sig);
// Build a new request with the same body bytes and signature header
let client = reqwest::Client::new();
let mut downstream = client.post(url)
.header("X-API-Signature", signature_b64)
.body(body.to_vec())
.send()
.await?;
// handle response...
Ok(req.into_response(actix_web::web::block(move || downstream.bytes().await?).into()))
}
By ensuring the body bytes are identical and the signature is computed over the same canonical representation, you eliminate a major class of smuggling that exploits differences in parsing. Combine this with strict content-length or transfer-encoding handling on any intermediaries to further reduce risk. middleBrick can highlight whether your endpoints exhibit parsing mismatches, but these code-level practices are necessary to close the smuggling vector when using HMAC signatures in Actix.