Http Request Smuggling in Express with Hmac Signatures
Http Request Smuggling in Express with Hmac Signatures — how this specific combination creates or exposes the vulnerability
HTTP request smuggling arises from mismatched parsing of requests by front-end proxies and the origin server. In Express applications that use HMAC signatures to authenticate requests, the vulnerability can be triggered when the proxy and Express parse the same request differently, allowing an attacker to smuggle a request across trust boundaries. A common pattern is a client sending a request with Transfer-Encoding: chunked to a front-end load balancer that supports chunked encoding, while the origin Express server (without explicit body-parser configuration) may fall back to Node’s native http module parsing, which can be more lenient.
With HMAC signatures, the client typically computes a signature over selected headers and the message body. If the proxy normalizes or strips headers before forwarding (e.g., removing hop-by-hop headers, altering Transfer-Encoding, or recomputing the body), the signature verified by Express may no longer align with the proxy’s view of the request. An attacker can exploit this by smuggling a second request inside the body or headers of the first, causing the smuggled request to be interpreted differently by the backend. For example, if the proxy treats the request as having Content-Length while Express parses it as chunked, the boundary between requests can shift, letting a smuggled request bypass authentication or reach an unintended route.
Consider an Express route that expects a JSON body and validates an X-API-Signature header covering the raw body. If the proxy modifies the body encoding (e.g., decompressing or rechunking) before it reaches Express, the signature check may still pass (if computed on the transformed body), but the request interpretation changes. In a smuggling scenario, an attacker can send a request with Content-Length: 0 and Transfer-Encoding: chunked, causing the proxy to forward one message while Express parses an additional request from the body. This can lead to authentication bypass, request tampering, or cache poisoning. The risk is amplified when HMAC verification is performed before proper normalization, allowing a malicious request to be treated as authenticated and processed by a vulnerable route.
Hmac Signatures-Specific Remediation in Express — concrete code fixes
To mitigate request smuggling when using HMAC signatures in Express, ensure consistent parsing and signature verification across all proxies and the application. Use a body-parser middleware (e.g., express.json()) before your signature verification so that the request body is normalized before hashing. Compute the HMAC over the raw bytes exactly as the client did, and avoid recomputing or modifying the body between the proxy and the verification step.
Below are concrete code examples for secure HMAC handling in Express.
const express = require('express');
const crypto = require('crypto');
const app = express();
// Use a body parser that preserves raw body for signature verification
app.use(express.json({ verify: (req, res, buf) => { req.rawBody = buf; } }));
function verifyHmac(req, res, next) {
const signature = req.headers['x-api-signature'];
if (!signature) return res.status(401).send('Missing signature');
const hmac = crypto.createHmac('sha256', process.env.HMAC_SECRET);
hmac.update(req.rawBody); // use the raw body as received
const expected = 'sha256=' + hmac.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
return res.status(401).send('Invalid signature');
}
next();
}
app.post('/api/endpoint', verifyHmac, (req, res) => {
res.json({ received: req.body });
});
app.listen(3000, () => console.log('Server running on port 3000'));
Key practices to prevent smuggling:
- Ensure the proxy does not modify the body encoding; if it does, recompute HMAC on the transformed body and coordinate with the client.
- Disable chunked transfer encoding at the proxy or ensure consistent parsing by explicitly setting Content-Length when possible.
- Validate and normalize headers consistently; avoid relying on headers that may be stripped or altered by intermediaries.
- Use fixed-length or explicit content-length checks where feasible, and avoid mixing Transfer-Encoding and Content-Length in the same request.
These steps reduce the risk that an attacker can exploit parsing discrepancies to smuggle requests across the proxy and backend boundary while still using HMAC signatures for integrity.