HIGH bola idorhapiapi keys

Bola Idor in Hapi with Api Keys

Bola Idor in Hapi with Api Keys — how this specific combination creates or exposes the vulnerability

Broken Access Control (BOLA/IDOR) occurs when an API exposes one user’s resources through predictable identifiers and insufficient ownership checks. Using API keys with Hapi can inadvertently create or expose BOLA when keys are treated as global credentials without scoping each request to the key owner’s data. If endpoints use keys only for authentication and then directly interpolate user-controlled path or query parameters (e.g., /users/:id/resource/:resourceId) without verifying that the resource belongs to the key holder, attackers can manipulate IDs to access other users’ data.

Hapi does not enforce ownership by default; it provides request objects and validation utilities, but developers must implement authorization. For example, an endpoint like GET /users/{userId}/profile protected by an API key will be vulnerable if the handler does not compare the authenticated key’s associated user ID with the userId in the URL. Attackers can iterate through numeric or guessable IDs, and because API keys often lack per-request context (such as tenant or user scope), the server may return 200 with sensitive data instead of 403/404.

Another scenario arises with opaque API keys stored in a database with relations to roles or tenants. If the authorization logic performs a lookup like db.users.find({ apiKey: key }) but then uses unchecked request parameters to build queries, the boundary between authentication (key validation) and authorization (resource ownership) blurs. Hapi request.pre can be populated with the key’s metadata, but if the handler later uses unvalidated parameters to fetch or modify records, BOLA occurs. Common root causes include missing tenant_id checks, insufficient parameter validation, and assuming route-level authentication substitutes for object-level authorization.

Real-world attack patterns mirror OWASP API Top 10 A01:2023 broken access control and CWE-639. For instance, an attacker can send requests with modified IDs while keeping the same API key, testing endpoints such as /v1/accounts/{id}/settings or /v1/customers/{id}/invoices. If responses differ by data presence rather than 403, sensitive information is leaked. In PCI-DSS and SOC2 contexts, this violates separation of duties and access control requirements. The risk is elevated when APIs expose numeric or UUID identifiers without verifying that the authenticated subject (via key claims) owns that identifier.

Api Keys-Specific Remediation in Hapi — concrete code fixes

Remediation centers on enforcing ownership and tenant boundaries at the handler level and centralizing authorization logic. Never rely on route authentication alone; bind the API key to a subject (user or service) and ensure every data access uses that subject as a filter. Below are concrete Hapi examples that demonstrate secure patterns.

Example 1: Key-to-user binding with strict ownership check

const Hapi = require('@hapi/hapi');

// Simulated key store: key -> { userId, tenantId }
const keyStore = {
  'sk-abc123': { userId: 'u-100', tenantId: 't-1' },
  'sk-xyz789': { userId: 'u-200', tenantId: 't-2' }
};

const validateApiKey = async (request, h) => {
  const key = request.headers['x-api-key'];
  if (!key || !keyStore[key]) {
    return { isValid: false };
  }
  const credentials = { key, ...keyStore[key] };
  return { isValid: true, credentials };
};

const decorate = async (request, h) => {
  return h.continue({ apiKeyInfo: request.auth.credentials });
};

const server = Hapi.server({ port: 4000, host: 'localhost' });

server.route({
  method: 'GET',
  path: '/users/{userId}/profile',
  options: {
    auth: false,
    pre: [
      {
        assign: 'apiKeyInfo',
        method: validateApiKey
      },
      {
        assign: 'auth',
        method: decorate
      }
    ],
    handler: async (request, h) => {
      // Enforce ownership: the URL param must match the key-bound user
      const { userId } = request.params;
      const { apiKeyInfo } = request.pre;
      if (!apiKeyInfo || apiKeyInfo.userId !== userId) {
        return h.response({ error: 'Forbidden' }).code(403);
      }
      // Fetch data scoped to userId (and tenant if applicable)
      return { userId, profile: 'secure-data' };
    }
  }
});

server.start();

Example 2: Tenant-aware handler with centralized authorization

const validateAndScope = (key) => {
  if (!key || !keyStore[key]) return null;
  return keyStore[key];
};

server.route({
  method: 'GET',
  path: '/v1/accounts/{accountId}/settings',
  options: {
    auth: false,
    pre: [
      {
        assign: 'scope',
        method: (request, h) => {
          const key = request.headers['x-api-key'];
          const scope = validateAndScope(key);
          return h.continue(scope ? { scope } : null);
        }
      }
    ],
    handler: async (request, h) => {
      const { scope } = request.pre;
      const { accountId } = request.params;
      if (!scope) {
        return h.response({ error: 'Unauthorized' }).code(401);
      }
      // Ensure account belongs to the key’s tenant and user
      const account = await db.accounts.findOne({
        _id: accountId,
        tenantId: scope.tenantId,
        userId: scope.userId
      });
      if (!account) {
        return h.response({ error: 'Forbidden' }).code(403);
      }
      return account.settings;
    }
  }
});

General guidelines

  • Always treat API keys as credentials that bind to a subject (user/service) and include tenant or role metadata.
  • Validate and sanitize all user-controlled parameters before using them in data queries; never trust route or query IDs alone.
  • Use Hapi’s pre extensions to centralize authorization and keep handlers focused on business logic.
  • Return 403 for forbidden access and 404 for non-existent resources to avoid leaking existence via differences in response behavior.

These patterns reduce BOLA risk by ensuring authentication (API key validation) and authorization (resource ownership) are consistently coupled. They align with findings that middleBrick reports under the Authentication and Authorization checks, where missing ownership validation is a common detection.

Related CWEs: bolaAuthorization

CWE IDNameSeverity
CWE-250Execution with Unnecessary Privileges HIGH
CWE-639Insecure Direct Object Reference CRITICAL
CWE-732Incorrect Permission Assignment HIGH

Frequently Asked Questions

Can API keys alone prevent BOLA in Hapi?
No. API keys provide authentication but do not enforce object-level authorization. You must explicitly validate that each request’s resource identifiers belong to the authenticated subject (key holder) in your handler logic.
How does middleBrick relate to BOLA findings in Hapi API scans?
middleBrick scans unauthenticated attack surfaces and can detect missing ownership checks that lead to BOLA. Its findings include severity, guidance, and mapping to frameworks like OWASP API Top 10 to help prioritize fixes.