Auth Bypass in Strapi with Hmac Signatures
Auth Bypass in Strapi with Hmac Signatures — how this specific combination creates or exposes the vulnerability
In Strapi, HMAC signatures are commonly used to verify the integrity and origin of webhook payloads or API requests. A misconfiguration in how the signature is computed or verified can lead to an authentication bypass. Strapi’s admin and API endpoints may rely on a shared secret to generate an HMAC, typically passed in a header such as x-hmac-signature. If the verification logic compares the computed signature with the provided signature using a non-constant time operation, an attacker can exploit timing differences to learn about the correct signature byte-by-byte. This is a classic timing side-channel that effectively bypasses the intended integrity check without needing the secret.
Another common pattern is when Strapi routes or custom controllers compute the HMAC on a subset of the payload or on normalized inputs that differ between client and server. For example, if the client includes optional fields that Strapi silently drops during canonicalization, the signatures will not match on the server. An attacker can omit optional parameters that change the request semantics—such as role, permissions, or admin flags—while still producing a valid HMAC over the reduced payload. This leads to privilege escalation or unauthorized access, a variant often seen in BOLA/IDOR and privilege escalation scenarios (BFLA).
Additionally, if the shared secret is hardcoded in client-side code, JavaScript bundles, or configuration files that are accessible to unauthenticated scans, an attacker can retrieve the secret and forge valid HMACs. middleBrick’s 12 security checks run in parallel and include Property Authorization and Unsafe Consumption tests that can surface such exposure in unauthenticated scans. When the signature algorithm is weak (e.g., MD5 or SHA1) or when the signature is only applied to GET requests while POST/PUT/DELETE lack signature checks, the attack surface expands. An attacker can replay or tamper with requests, modifying resource identifiers or ownership fields, because the server skips verification for non-GET methods or for routes not explicitly protected by the HMAC check.
Consider a Strapi webhook that processes payment events. The payload might include orderId, amount, and status. If the HMAC is computed only over orderId and amount, an attacker can change status to "completed" without invalidating the signature. If Strapi does not enforce authentication on the webhook endpoint and relies solely on HMAC, this becomes an auth bypass. The scan’s Authentication and BOLA/IDOR checks help detect missing or bypassed controls, while LLM/AI Security probes ensure no system prompt or internal instructions are leaked via verbose error messages that aid attackers.
middleBrick scans such endpoints in 5–15 seconds, testing unauthenticated attack surfaces and returning a security risk score with prioritized findings. The tool maps findings to frameworks like OWASP API Top 10 and provides remediation guidance rather than fixing the issue directly. For teams using the Pro plan, continuous monitoring can be scheduled to detect regressions, and the GitHub Action can fail builds if the score drops below a set threshold, integrating API security checks into CI/CD pipelines.
Hmac Signatures-Specific Remediation in Strapi — concrete code fixes
To remediate HMAC-related authentication bypass in Strapi, ensure the server uses a strict, constant-time comparison and signs a canonical representation of the entire request. Below is a Node.js example using the built-in crypto module. The server computes the HMAC over a canonical string that includes selected fields, a timestamp, and a nonce to prevent replay attacks. It then compares the computed MAC with the header using crypto.timingSafeEqual.
const crypto = require('crypto');
function verifyHmac(req, secret) {
const received = req.headers['x-hmac-signature'];
if (!received) return false;
// Canonicalize: include method, path, selected body fields, timestamp, nonce
const payload = [
req.method,
req.path,
JSON.stringify(req.body), // ensure consistent ordering
req.body.timestamp || '',
req.body.nonce || ''
].join('|');
const expected = crypto.createHmac('sha256', secret).update(payload).digest('hex');
const receivedBuffer = Buffer.from(received, 'hex');
const expectedBuffer = Buffer.from(expected, 'hex');
if (receivedBuffer.length !== expectedBuffer.length) {
return false;
}
return crypto.timingSafeEqual(expectedBuffer, receivedBuffer);
}
// Usage in a Strapi controller
module.exports = {
async webhook(ctx) {
const secret = process.env.HMAC_SECRET;
if (!verifyHmac(ctx.request, secret)) {
ctx.status = 401;
ctx.body = { error: 'Invalid signature' };
return;
}
// proceed with trusted payload
const data = ctx.request.body;
// ... business logic
ctx.body = { ok: true };
}
};
On the client side, the HMAC must be generated with the exact same canonical form. Here is a matching example that produces the header to send with the request.
const crypto = require('crypto');
function buildHmac(method, path, body, secret) {
const payload = [
method,
path,
JSON.stringify(body),
body.timestamp || '',
body.nonce || ''
].join('|');
return crypto.createHmac('sha256', secret).update(payload).digest('hex');
}
// Example usage
const secret = process.env.HMAC_SECRET;
const body = {
orderId: '12345',
amount: 100,
status: 'pending',
timestamp: Date.now(),
nonce: 'random-unique-value'
};
const signature = buildHmac('POST', '/webhooks/payment', body, secret);
// Set header x-hmac-signature to signature before sending
Additional remediation steps include: never exposing the shared secret in client bundles or public repositories; rotating the secret periodically; and applying the HMAC verification to all relevant HTTP methods, not just GET. For continuous protection, use the middleBrick CLI to scan from terminal with middlebrick scan <url> or integrate the GitHub Action to fail builds if security scores degrade. Teams on the Pro plan can enable continuous monitoring and receive Slack/Teams alerts, while the MCP Server allows scanning APIs directly from AI coding assistants within the IDE.
Related CWEs: authentication
| CWE ID | Name | Severity |
|---|---|---|
| CWE-287 | Improper Authentication | CRITICAL |
| CWE-306 | Missing Authentication for Critical Function | CRITICAL |
| CWE-307 | Brute Force | HIGH |
| CWE-308 | Single-Factor Authentication | MEDIUM |
| CWE-309 | Use of Password System for Primary Authentication | MEDIUM |
| CWE-347 | Improper Verification of Cryptographic Signature | HIGH |
| CWE-384 | Session Fixation | HIGH |
| CWE-521 | Weak Password Requirements | MEDIUM |
| CWE-613 | Insufficient Session Expiration | MEDIUM |
| CWE-640 | Weak Password Recovery | HIGH |