Broken Access Control in Strapi with Hmac Signatures
Broken Access Control in Strapi with Hmac Signatures — how this specific combination creates or exposes the vulnerability
Broken Access Control (BOLA/IDOR) in Strapi combined with Hmac Signatures can expose sensitive data or allow unauthorized operations when signature validation is incomplete or applied only after routing decisions. Strapi is a headless CMS that often exposes REST or GraphQL endpoints; if an endpoint relies on Hmac Signatures for integrity but does not enforce authorization after signature verification, an authenticated context can be abused.
Consider a scenario where Strapi uses Hmac Signatures to verify request integrity but does not bind the signature to a specific resource ownership or tenant. An attacker who can obtain or guess a valid signature for one resource may reuse that signature to access or modify another resource because Strapi does not re-check permissions post-verification. For example, a signature generated for /api/articles/1 may be accepted for /api/articles/2 if Strapi validates the Hmac but skips checking whether the requesting user owns article 2.
Additionally, if signature generation uses predictable inputs (e.g., only the path without user or role context), an attacker might replay a signature across users or sessions. Strapi middleware that verifies Hmac Signatures should incorporate user identifiers, tenant context, and intended action into the signed payload to prevent horizontal or vertical privilege escalation. Without these safeguards, the API incorrectly treats the signature as an authorization boundary rather than an integrity check, leading to BOLA/IDOR.
Real-world attack patterns include tampering with query parameters or body fields that are excluded from the Hmac computation, allowing an attacker to modify resource identifiers while keeping the signature valid. If Strapi routes the request based on the modified identifier before validating authorization, the signature check provides a false sense of security. This aligns with OWASP API Top 10 #1 Broken Object Level Authorization, where access control decisions are incomplete or bypassed.
To detect such issues, middleBrick runs checks for BOLA/IDOR and Authentication in parallel, testing unauthentized endpoints and attempting to access resources beyond the intended scope. When combined with Hmac Signature validation logic, it can surface cases where signature integrity does not translate to proper access control.
Hmac Signatures-Specific Remediation in Strapi — concrete code fixes
Remediation requires ensuring that Hmac Signatures cover all inputs that affect authorization and that Strapi re-validates permissions after signature verification. The signature must be computed over a canonical string that includes the HTTP method, path, selected headers, body, user ID, role, and any resource identifiers. Verification must occur before routing to sensitive operations and must be tied to a per-request context that includes authorization checks.
Below are two concrete code examples for Strapi v4 using an Express-like middleware approach. The first example shows generating a secure Hmac Signature that includes user context and resource identifier. The second shows verifying the signature and enforcing authorization after verification.
Example 1: Generating Hmac Signature with user and resource context
const crypto = require('crypto');
function generateHmacSignature({ method, path, body, userId, role, resourceId, secret }) {
const payload = {
method,
path,
body,
userId,
role,
resourceId,
timestamp: Date.now(),
};
const payloadString = JSON.stringify(payload);
const hmac = crypto.createHmac('sha256', secret);
hmac.update(payloadString);
return hmac.digest('hex');
}
// Example usage within Strapi middleware
module.exports = (secret) => {
return async (ctx, next) => {
const { method, url, body } = ctx.request;
const userId = ctx.state.user?.id || null;
const role = ctx.state.user?.role || 'anonymous';
// For writes, include the resourceId from body or params
const resourceId = (method === 'POST') ? body.id : ctx.params.id;
const signature = generateHmacSignature({ method, path: url, body, userId, role, resourceId, secret });
ctx.set('X-API-Signature', signature);
await next();
};
};
Example 2: Verifying Hmac Signature and enforcing authorization
const crypto = require('crypto');
function verifyHmacSignature({ method, path, body, userId, role, resourceId, receivedSignature, secret }) {
const expectedSignature = generateHmacSignature({ method, path, body, userId, role, resourceId, secret });
// Use timing-safe compare
return crypto.timingSafeEqual(Buffer.from(expectedSignature), Buffer.from(receivedSignature));
}
// Strapi middleware to verify before proceeding
module.exports = (secret) => {
return async (ctx, next) => {
const receivedSignature = ctx.request.header['x-api-signature'];
const { method, url, body } = ctx.request;
const userId = ctx.state.user?.id;
const role = ctx.state.user?.role;
const resourceId = (method === 'POST') ? body.id : ctx.params.id;
if (!receivedSignature) {
ctx.throw(401, 'Missing signature');
}
const isValid = verifyHmacSignature({ method, path: url, body, userId, role, resourceId, receivedSignature, secret });
if (!isValid) {
ctx.throw(403, 'Invalid signature');
}
// After signature verification, enforce Strapi permissions
// Ensure the userId matches ownership or role has right to the resource
if (userId && resourceId) {
const entry = await strapi.entityService.findOne('api::article.article', resourceId, {
populate: ['author'],
});
if (!entry) {
ctx.throw(404, 'Resource not found');
}
// Horizontal privilege escalation check: user can only access their own articles
if (entry.author?.id !== userId && role !== 'admin') {
ctx.throw(403, 'Forbidden: you do not own this resource');
}
}
await next();
};
};
Key points: include user ID, role, and resource ID in the signed payload; perform timing-safe comparison; and re-check authorization after signature validation. This prevents attackers from reusing signatures across users or resources. For production, rotate secrets and consider adding nonce or timestamp windows to mitigate replay.
middleBrick’s LLM/AI Security checks can detect system prompt leakage or prompt injection attempts that might expose signing logic, while its BOLA/IDOR tests validate whether signature verification is correctly coupled with ownership checks.