HIGH auth bypasssailsapi keys

Auth Bypass in Sails with Api Keys

Auth Bypass in Sails with Api Keys — how this specific combination creates or exposes the vulnerability

Sails is a Node.js web framework that encourages convention-over-configuration and rapid development. When using API keys for authentication, developers often implement them as simple header checks without enforcing strict scoping, validation, or binding to a user context. An Auth Bypass occurs when a request that should require valid authentication is accepted because the API key check is incomplete, misapplied, or bypassed by other code paths.

In Sails, this commonly happens when policies or custom middleware check for an API key only on certain controllers or actions, leaving administrative or legacy endpoints unprotected. For example, a policy might verify req.headers['x-api-key'] on user profile endpoints but omit it for administrative controllers, enabling an unauthenticated actor to call those endpoints directly. Additionally, if API keys are accepted via query parameters or headers without constant-time comparison, attackers may exploit timing differences to infer valid keys.

Another vector specific to Sails involves Waterline ORM associations. If an endpoint uses a key to identify a parent record but fails to enforce ownership or scope checks on related models, an attacker can traverse relationships to access data belonging to other users. This intersects with BOLA/IDOR when a key grants access to a collection but does not ensure that the requesting actor is authorized for the specific resource instance.

During a black-box scan, middleBrick tests unauthenticated endpoints that expect API keys and checks whether sensitive operations or data exposure are possible without valid credentials. It also examines OpenAPI specifications to see whether key-required paths are properly defined and cross-references runtime behavior to detect mismatches between documented and actual authentication requirements.

Api Keys-Specific Remediation in Sails — concrete code fixes

Remediation focuses on consistent policy enforcement, safe key transmission, and strict validation within Sails controllers and policies. Below are concrete, working examples to harden API key usage.

1. Global policy to require and validate API keys

Create a policy that checks for a server-side stored API key and uses constant-time comparison to avoid timing attacks.

// api/policies/requireApiKey.js
const crypto = require('crypto');

module.exports = async function requireApiKey(req, res, next) {
  const requestKey = req.headers['x-api-key'];
  const serverKey = sails.config.custom.apiKeys.public; // stored securely, e.g., in environment variables

  if (!requestKey) {
    return res.unauthorized('Missing API key');
  }

  const isValid = crypto.timingSafeEqual(
    Buffer.from(requestKey),
    Buffer.from(serverKey)
  );

  if (!isValid) {
    return res.forbidden('Invalid API key');
  }
  return next();
};

Register this policy in config/policies.js to apply globally or to specific controllers:

module.exports.policies = {
  '*': 'requireApiKey',
  'admin/*': 'requireApiKey',
  'user/profile': 'requireApiKey'
};

2. Key binding to user context to prevent horizontal elevation

Ensure API keys are associated with a user or scope and validated against the requested resource. For example, a user endpoint should verify that the key’s owner matches the requested user ID.

// api/controllers/UserController.js
module.exports = {
  async me(req, res) {
    const apiKey = req.headers['x-api-key'];
    const user = await User.findOne({ apiKey }).meta({ fetch: 'user' });
    if (!user) {
      return res.unauthorized('Invalid key');
    }
    return res.ok(user);
  }
};

3. Avoid exposing keys in URLs and logs

Prefer headers over query parameters, and ensure keys are not logged by Sails. Configure transports appropriately and avoid printing req.headers in logs.

// config/log.js
module.exports.log = {
  level: 'warn',
  // Ensure API key headers are not inadvertently serialized in logs
  custom: undefined
};

4. Combine with ownership checks for sensitive actions

For endpoints that act on specific resources, add explicit checks that the authenticated key has rights to that resource.

// api/controllers/PostController.js
module.exports = {
  async destroy(req, res) {
    const { id } = req.params.all();
    const apiKey = req.headers['x-api-key'];
    const post = await Post.findOne(id);
    if (!post) {
      return res.notFound();
    }
    const user = await User.findOne({ apiKey });
    if (!user || post.userId !== user.id) {
      return res.forbidden('Not authorized');
    }
    await Post.destroyOne(id);
    return res.noContent();
  }
};

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

Can API keys alone prevent Auth Bypass in Sails if endpoints are inconsistently protected?
No. Inconsistent policy application leaves endpoints unprotected. Use a global policy in Sails and explicitly apply it to all sensitive controllers and actions; middleBrick scans can help detect unprotected endpoints.
Does middleBrick test for timing-based key validation weaknesses in unauthenticated scans?
middleBrick checks whether API key-required paths are properly defined in the OpenAPI spec and whether unauthenticated access is possible. It does not actively probe timing side channels but highlights inconsistencies between spec and runtime behavior.