HIGH auth bypasssailshmac signatures

Auth Bypass in Sails with Hmac Signatures

Auth Bypass in Sails with Hmac Signatures — how this specific combination creates or exposes the vulnerability

Sails is a Node.js web framework that encourages rapid API development. When Hmac Signatures are used for request authentication, developers often sign a subset of the request properties (method, URL, selected headers, and a timestamp) and send the signature in a custom header. If the server-side policy does not enforce strict validation, an attacker can manipulate unsigned or weakly validated parameters to bypass intended authorization checks.

An Auth Bypass occurs when an authenticated context is assumed based on the presence of a valid Hmac Signature, but the signature scope is too narrow. For example, if the signature covers only the HTTP method and path but omits critical identifiers like the resource ID or the user ID, an attacker can reuse a captured signature for a different resource or escalate privileges across related endpoints. This is especially relevant in Sails because controllers often rely on implicit model associations; if an endpoint uses a user-supplied id parameter without verifying ownership, a reused Hmac Signature may still be accepted while granting access to another user’s data.

Another common pattern in Sails is to sign a canonical string built from selected headers and the request body. If the body or selected headers are not consistently required for every endpoint, an attacker may send a valid signed request to an endpoint where those components are missing or altered, causing the server to accept the request as legitimate. Additionally, if the server does not enforce strict timestamp validation or allows a large replay window, intercepted Hmac-signed requests can be replayed to perform actions on behalf of the original signer.

Insecure default configurations in Sails applications can exacerbate these issues. For example, if route policies rely on a simple role flag present in the request without cross-checking the Hmac context, an attacker who discovers or guesses an unsigned but authorized route may be able to pivot to endpoints that should require the Hmac Signature. The interplay between permissive CORS settings, inconsistent policy application across controllers, and missing integrity checks on the signed parameters creates conditions where authentication can be bypassed despite the presence of Hmac Signatures.

To detect this category of issue, scanners perform black-box testing by sending the same Hmac-signed request to related endpoints with modified identifiers, and by replaying captured requests with slight variations in parameters. They also check whether the signature scope includes all security-critical elements such as resource IDs, tenant identifiers, and user context. Without these protections, Sails APIs can expose an Auth Bypass that is difficult to identify without targeted, protocol-aware testing.

Hmac Signatures-Specific Remediation in Sails — concrete code fixes

Remediation focuses on ensuring the Hmac Signature covers all context required to enforce authorization, and that server-side verification is strict and consistent across controllers.

Example: Secure Hmac Signing and Verification in Sails

Below is a complete, realistic example showing how to generate and verify an Hmac Signature in a Sails API, including key components that must be signed to prevent bypass.

// api/services/hmacService.js
const crypto = require('crypto');

module.exports = {
  signPayload: function(payload, secret) {
    const stringToSign = [
      payload.method || 'GET',
      payload.path || '',
      payload.timestamp || Date.now().toString(),
      payload.nonce || crypto.randomBytes(16).toString('hex'),
      payload.bodyHash || '',
      (payload.identifiers || []).join(':')
    ].join('|');
    return crypto.createHmac('sha256', secret).update(stringToSign).digest('hex');
  },

  verifyPayload: function(payload, receivedSignature, secret) {
    const expectedSignature = this.signPayload(payload, secret);
    // Use timing-safe compare
    return crypto.timingSafeEqual(
      Buffer.from(expectedSignature),
      Buffer.from(receivedSignature)
    );
  }
};

In your controller, include critical identifiers in the payload and require them on every verified request:

// api/controllers/RecordController.js
module.exports = {
  update: async function(req, res) {
    const { id } = req.params;
    const body = req.allParams();
    const secret = sails.config.custom.hmacSecret;

    const payload = {
      method: req.method,
      path: `/records/${id}`,
      timestamp: req.headers['x-timestamp'],
      nonce: req.headers['x-nonce'],
      bodyHash: hashBody(body),
      identifiers: [sails.models.record.getTenantId(req), id, req.session.userId || '']
    };

    const signature = req.headers['x-signature'];
    if (!hmacService.verifyPayload(payload, signature, secret)) {
      return res.unauthorized();
    }

    // Ensure ownership before proceeding
    const record = await Record.findOne(id);
    if (!record || record.userId !== payload.identifiers[2]) {
      return res.forbidden('Access denied to this resource');
    }

    // Proceed with update
    return res.ok(await Record.updateOne(id).set(body));
  }
};

function hashBody(body) {
  const crypto = require('crypto');
  return crypto.createHash('sha256').update(JSON.stringify(body)).digest('hex');
}

Key remediation practices:

  • Include the resource identifier (e.g., record ID) and tenant or user context in the signed string.
  • Require the same set of signed parameters on every endpoint that enforces authorization.
  • Use crypto.timingSafeEqual for signature comparison to prevent timing attacks.
  • Validate and parse timestamps on the server to mitigate replay attacks; reject requests with excessive clock skew.
  • Ensure nonces are unique and optionally short-lived to prevent reuse within the same context.
  • Apply these checks consistently across all controllers and policies; avoid relying on route-level flags that do not validate the Hmac scope.

By tying the Hmac Signature to the full security context — method, path, identifiers, and body — Sails applications can avoid Auth Bypass scenarios where unsigned or weakly scoped signatures grant unintended access.

Related CWEs: authentication

CWE IDNameSeverity
CWE-287Improper Authentication CRITICAL
CWE-306Missing Authentication for Critical Function CRITICAL
CWE-307Brute Force HIGH
CWE-308Single-Factor Authentication MEDIUM
CWE-309Use of Password System for Primary Authentication MEDIUM
CWE-347Improper Verification of Cryptographic Signature HIGH
CWE-384Session Fixation HIGH
CWE-521Weak Password Requirements MEDIUM
CWE-613Insufficient Session Expiration MEDIUM
CWE-640Weak Password Recovery HIGH

Frequently Asked Questions

Why does including the resource ID in the Hmac signature help prevent Auth Bypass in Sails?
Including the resource ID ensures the signature is tied to a specific resource. Without it, an attacker can reuse a valid signature across different IDs, allowing unauthorized access across records and enabling privilege escalation across related endpoints.
How does timestamp and nonce usage improve Hmac security in Sails APIs?
Timestamps allow the server to reject requests with excessive clock skew, reducing the window for replay attacks. Nonces provide uniqueness per request, preventing the same signed payload from being accepted more than once within the allowed time window.