HIGH bola idornestjsapi keys

Bola Idor in Nestjs with Api Keys

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

Broken Object Level Authorization (BOLA) occurs when an API fails to enforce proper ownership or scope checks between a subject (e.g., a user or service) and the object they are trying to access. Using API keys in a NestJS service can inadvertently create BOLA when keys are treated as a global identity without scoping each request to the key’s associated tenant or user context.

Consider a typical API key setup where a key is mapped to an organization or customer in a database. If a route like /organizations/:orgId/resource/:resourceId uses the API key only for authentication (verifying the key is valid) but does not ensure the authenticated key’s organization owns the requested orgId, an attacker can manipulate orgId or resourceId to access data belonging to another organization. This is BOLA: the API key proves identity but not authorization for the specific resource.

In NestJS, this often happens when controllers retrieve resources by ID without cross-checking the key’s metadata. For example, a service might fetch an organization by the ID provided in the URL, then pass it to a repository method. If the repository does not filter by the authenticated key’s organization, the request succeeds regardless of whether the key belongs to that organization. Attackers can enumerate IDs or guess predictable IDs (e.g., UUIDs or sequential integers) and observe differences in behavior or data returned, leading to data exposure.

Additionally, BOLA can be chained with other issues. If input validation is weak, an attacker might use path traversal or type confusion to escalate impact. Rate limiting that is scoped to the endpoint rather than to the key can allow a compromised key to be abused for enumeration at higher volumes. Because API keys are often long-lived credentials, a leaked key can facilitate sustained BOLA attacks across many endpoints if the backend does not enforce per-request ownership checks.

To detect this during scanning, middleBrick runs unauthenticated tests that probe predictable resource IDs while using a single API key, looking for unauthorized data access. It also checks whether authorization logic references the key’s associated scope (e.g., organization ID) on every request. These runtime checks complement spec analysis, where middleBrick resolves OpenAPI $ref chains to verify whether security schemes are applied consistently across path parameters and request bodies.

Api Keys-Specific Remediation in Nestjs — concrete code fixes

Remediation centers on ensuring that each authorized request validates ownership or scope tied to the API key, not just the key’s validity. Below are concrete patterns you can apply in NestJS.

1. Scoped key mapping with a guard

Create an API key guard that enforces scope before allowing access to a route. The guard resolves the key, attaches tenant or org metadata, and ensures that any resource-level operation includes a match between requested IDs and the key’s scope.

import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { ApiKeyService } from './api-key.service';

@Injectable()
export class ApiKeyScopeGuard implements CanActivate {
  constructor(private readonly apiKeyService: ApiKeyService) {}

  async canActivate(context: ExecutionContext): Promise {
    const request = context.switchToHttp().getRequest();
    const key = request.headers['x-api-key'];
    if (!key) return false;

    const scopedKey = await this.apiKeyService.validateAndScope(key);
    if (!scopedKey) return false;

    // Attach scoped identity for downstream use
    request.scopedKey = scopedKey;
    return true;
  }
}

2. Enforce scope in the service layer

Never trust URL IDs alone. Your service method should require the scoped key and use it to filter queries. Here is a service that fetches an organization resource only when the scoped key’s organization matches the requested orgId.

import { Injectable, NotFoundException } from '@nestjs/common';
import { Repository } from 'typeorm';
import { Organization } from './organization.entity';

interface ScopedKey {
  orgId: string;
  permissions: string[];
}

@Injectable()
export class ResourceService {
  constructor(
    @InjectRepository(Organization)
    private readonly orgRepo: Repository,
    private readonly scopedKey: ScopedKey,
  ) {}

  async getResource(orgId: string, resourceId: string) {
    if (orgId !== this.scopedKey.orgId) {
      throw new NotFoundException('Resource not found');
    }
    const resource = await this.orgRepo
      .createQueryBuilder('org')
      .where('org.id = :orgId', { orgId })
      .andWhere('org.resources @> :resources', { resources: [resourceId] })
      .getOne();
    if (!resource) {
      throw new NotFoundException('Resource not found');
    }
    return resource;
  }
}

3. Apply the guard globally or per-controller

Register the guard globally or on specific controllers to ensure consistent enforcement. Combine with built-in validation pipes for IDs to reduce injection surface.

import { Module } from '@nestjs/common';
import { APP_GUARD } from '@nestjs/core';

@Module({
  providers: [
    {
      provide: APP_GUARD,
      useClass: ApiKeyScopeGuard,
    },
  ],
})
export class AuthModule {}

4. Use parameterized queries and avoid concatenation

Always use parameterized queries or query builders. Do not concatenate IDs into raw SQL or command strings, even after scope checks, to prevent injection that could bypass intended scoping.

5. Rotate keys and monitor usage

While not a code fix, operational practices reduce exposure. Rotate API keys periodically and log access with key identifiers to detect anomalous patterns that may indicate BOLA probing.

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 if IDs are predictable?
No. API keys authenticate identity but do not enforce ownership. If endpoints do not scope each request to the key’s associated tenant or user, predictable IDs can be accessed across organizations, enabling BOLA.
Does validating the API key in a guard guarantee BOLA protection?
Not by itself. The guard must also ensure that every data access includes a check that the requested resource ID belongs to the key’s scope. Skipping per-request scope checks leaves BOLA possible.