HIGH broken access controlsailshmac signatures

Broken Access Control in Sails with Hmac Signatures

Broken Access Control in Sails with Hmac Signatures — how this specific combination creates or exposes the vulnerability

Broken Access Control (BOLA/IDOR) in Sails when Hmac Signatures are used incorrectly can allow an authenticated or unauthenticated attacker to access or modify resources that should be restricted. Sails is a Node.js MVC framework that does not enforce authorization or ownership checks by default; it relies on developer code to apply access rules. When Hmac Signatures are used for request authentication, a common pattern is to sign a subset of request parameters (e.g., userId, resourceId, timestamp) and verify the signature server-side before processing the request. If the signature is verified but the application then uses user-supplied identifiers (e.g., req.param('id')) directly to load a record without confirming that the authenticated subject is allowed to act on that specific resource, the Hmac layer does not prevent horizontal privilege escalation or unauthorized object access.

For example, consider an endpoint like GET /api/account/:accountId that expects a signature covering accountId. An attacker who can obtain or guess another user’s accountId could replay a valid request with a different accountId if the server does not enforce that the authenticated principal owns that accountId. The signature may still validate because the attacker can include the target accountId in the signed payload if the signing key is leaked or if the signature does not bind the request to a specific subject. Additionally, if the signature is computed over only partial parameters and the server trusts other parameters taken from the request path or body, an attacker can modify those unchecked parameters to escalate privileges (e.g., changing role flags). This is a BOLA/IDOR issue: the server fails to ensure the requesting identity matches the resource identity. The risk is compounded when endpoints expose sensitive data or perform state-changing operations without re-checking ownership after signature verification. Even with Hmac Signatures protecting integrity and authenticity of the request, the application must enforce granular access control, ensuring that every data access respects the subject’s permissions and that identifiers are not malleable by the client.

Real-world patterns from API security testing show that these mistakes map to OWASP API Top 10 A01:2023 broken access control and can be discovered in scans that test unauthenticated and authenticated attack surfaces. Attack patterns such as IDOR via tampered object references or horizontal privilege escalation are observed when signature verification does not enforce resource ownership. In Sails, this often surfaces in controllers that load models using req.params without scoping to the requesting user or service identity. For example, using Waterline ORM without a where clause that restricts by userId can return records belonging to other users. The presence of Hmac Signatures should not reduce rigor; instead, it requires precise binding of the signature scope to authorization decisions and a clear separation between integrity checks and authorization checks.

Hmac Signatures-Specific Remediation in Sails — concrete code fixes

To remediate Broken Access Control when using Hmac Signatures in Sails, bind the signature to the authenticated subject and enforce ownership checks on every resource access. Do not trust path or body parameters after signature verification; scope all queries to the identity derived from the authentication context (e.g., from the signature payload or session). Below are concrete, working examples that demonstrate secure patterns.

Example 1: Signing and verifying a request with user context

Sign a canonical string that includes userId, a timestamp, and the intended resourceId, then verify on the server. Use crypto.createHmac with a strong algorithm (e.g., sha256) and a per-service secret stored securely. Always verify the timestamp to prevent replay.

// utils/signature.js
const crypto = require('crypto');

const SECRET = process.env.HMAC_SECRET; // store securely, rotate periodically
const EXPIRY_MS = 5 * 60 * 1000; // 5 minutes

function buildHmac(payload) {
  const sorted = Object.keys(payload)
    .sort()
    .map(k => `${k}:${payload[k]}`)
    .join('|');
  const hmac = crypto.createHmac('sha256', SECRET);
  hmac.update(sorted);
  return hmac.digest('hex');
}

function verifyHmac(payload, receivedSignature) {
  const expected = buildHmac(payload);
  const timingSafe = crypto.timingSafeEqual
    ? crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(receivedSignature))
    : expected === receivedSignature;
  // Optional: enforce expiry
  const now = Date.now();
  const isFresh = now - payload.timestamp < EXPIRY_MS;
  return timingSafe && isFresh;
}

module.exports = { buildHmac, verifyHmac };

Client example (pseudo-request):

const payload = {
  userId: 'u_123',
  accountId: 'a_456',
  timestamp: Date.now(),
  method: 'GET',
  path: '/api/account/a_456'
};
const signature = buildHmac(payload); // send signature in header x-hmac-signature

Example 2: Sails controller with ownership check after signature verification

In the controller, after verifying the Hmac, load the resource scoped to the identity extracted from the payload (not solely from request params). This ensures that even if the attacker changes the URL parameter, the query will return empty unless the resource belongs to the authenticated subject.

// api/controllers/AccountController.js
const { verifyHmac } = require('../utils/signature');

module.exports = {
  show: async function (req, res) {
    const { signature, timestamp, userId, accountId } = req.allParams();
    const payload = { userId, accountId, timestamp, method: req.method, path: req.path };

    if (!verifyHmac(payload, signature)) {
      return res.unauthorized('Invalid or expired signature');
    }

    // Enforce ownership: scope by authenticated userId from payload, not only route param
    const account = await Account.findOne({
      id: accountId,
      userId: userId // ensures the account belongs to the subject encoded in the signature
    });

    if (!account) {
      return res.notFound('Account not found or access denied');
    }

    return res.ok(account);
  }
};

Additional measures: use the Pro plan’s continuous monitoring to detect anomalies in signature usage, and leverage the GitHub Action to fail builds if risk scores drop due to missing ownership checks. For advanced setups, the MCP Server can integrate these checks into your AI coding assistant to flag insecure patterns during development.

Frequently Asked Questions

How does Hmac Signatures fail to prevent IDOR if the signature validates?
Hmac Signatures ensure request integrity and authenticity but do not enforce authorization. If the server uses user-supplied identifiers (e.g., accountId from the URL) to load resources without scoping the query to the authenticated subject, an attacker can change those identifiers to access other users’ resources even with a valid signature. The signature must be bound to the intended resource and the application must verify ownership independently.
Can middleBrick help detect these access control issues in Sails APIs?
Yes. middleBrick scans unauthenticated attack surfaces and maps findings to frameworks like OWASP API Top 10. Its checks include BOLA/IDOR and Property Authorization, which can highlight missing ownership scopes in Sails endpoints. You can run scans from the CLI with middlebrick scan , add API security checks to your CI/CD pipeline with the GitHub Action, or integrate scans directly from your IDE using the MCP Server.