HIGH bola idornestjshmac signatures

Bola Idor in Nestjs with Hmac Signatures

Bola Idor in Nestjs with Hmac Signatures — how this specific combination creates or exposes the vulnerability

Broken Object Level Authorization (BOLA) occurs when an API exposes one user’s resource through another user’s identifier, typically an unpredictable reference such as a UUID. In NestJS applications that use Hmac Signatures for request authentication, BOLA can emerge when signature validation is applied only to transport integrity (e.g., ensuring the payload was not tampered with) while authorization checks remain incomplete or misaligned with the signature context.

Consider a NestJS controller that accepts a resource ID from the URL and uses an Hmac Signature to verify request authenticity. If the signature is computed over a subset of parameters that exclude the user identifier, or if the server uses the same signing key across users without binding the signature to the actor, an attacker can manipulate the resource ID and reuse a valid signature from another resource. Because the server validates the Hmac but does not re-check whether the authenticated subject owns the target resource, BOLA is triggered.

A common pattern involves creating an Hmac signature over selected headers and the request body, then passing the user identifier (e.g., sub from a JWT) separately for authorization. If the controller resolves the resource by ID without confirming that the subject in the JWT (or session context) matches the owner of the resource, the signature verification does not prevent horizontal privilege escalation. For example, an attacker who knows another user’s resource ID could issue a PUT /projects/12345 request with a valid Hmac signature derived from a prior legitimate call, and the server may incorrectly authorize the update solely based on signature validity.

In NestJS, this often maps to the OWASP API Top 10 category Broken Object Level Authorization and can intersect with L1:2027 — Broken Object Level Authorization in the API Security Top 10. BOLA in this context is not caused by the Hmac mechanism itself, but by the way the application scopes authorization relative to the signed context. Without explicit ownership checks that are tied to the signature derivation, the unauthenticated attack surface includes ID manipulation across users, even when integrity protection is present.

Real-world analogies include scenarios where an API signs query parameters but omits the tenant or user identifier from the signed string, enabling cross-tenant access if the resource ID is predictable. Similarly, using a global signing key without per-user contextual binding can weaken the practical security of Hmac Signatures, as the signature no longer guarantees authorization within the intended access boundary.

Hmac Signatures-Specific Remediation in Nestjs — concrete code fixes

Remediation centers on ensuring that the Hmac signature scope explicitly includes the user or tenant context and that authorization checks validate ownership before acting on the resource. Below are concrete patterns and code examples for NestJS.

1. Include user identifier in the Hmac scope

When computing the Hmac, incorporate the user identifier (e.g., sub from a JWT) so that the same signature cannot be reused across different subjects. This binds integrity and authorization at the cryptographic level.

import { createHmac } from 'crypto';

export function buildHmac(
  secret: string,
  method: string,
  path: string,
  body: object,
  userId: string,
): string {
  const payload = {
    method,
    path,
    body,
    userId, // critical: include userId in the signed context
    timestamp: Date.now(),
  };
  const serialized = JSON.stringify(payload);
  return createHmac('sha256', secret).update(serialized).digest('hex');
}

2. Validate ownership in the controller

Even when the signature is valid, the controller must verify that the resource belongs to the user encoded in the signature or JWT. Do not rely on signature validity alone for authorization.

import { Controller, Param, Post, UseGuards, Body, ForbiddenException } from '@nestjs/common';
import { JwtAuthGuard } from './jwt-auth.guard';
import { ProjectsService } from './projects.service';

@Controller('projects')
export class ProjectsController {
  constructor(private readonly projectsService: ProjectsService) {}

  @Post(':projectId/update')
  @UseGuards(JwtAuthGuard)
  async updateProject(
    @Param('projectId') projectId: string,
    @Body() updateDto: any,
    @Req() req: any,
  ) {
    const userId = req.user.sub; // subject from JWT or signature context
    const project = await this.projectsService.findOne(projectId);
    if (!project) {
      throw new ForbiddenException('Not found');
    }
    if (project.ownerId !== userId) {
      throw new ForbiddenException('BOLA: you do not own this project');
    }
    return this.projectsService.update(projectId, updateDto);
  }
}

3. Use per-request signing context and constant-time comparison

Ensure that signature verification includes a timestamp or nonce to prevent replay, and compare sensitive identifiers using constant-time operations where applicable. Below is a verification helper that checks userId consistency between the signature payload and the request context.

import { createHmac, timingSafeEqual } from 'crypto';

export function verifyHmac(
  secret: string,
  method: string,
  path: string,
  body: object,
  userId: string,
  receivedSignature: string,
): boolean {
  const expected = buildHmac(secret, method, path, body, userId);
  // Use timingSafeEqual to avoid timing attacks when comparing signatures
  const received = Buffer.from(receivedSignature, 'hex');
  const expectedBuf = Buffer.from(expected, 'hex');
  if (received.length !== expectedBuf.length) return false;
  return timingSafeEqual(received, expectedBuf);
}

4. Middleware to enforce scoped signatures

Implement a NestJS middleware that validates the Hmac and enforces that the signed userId matches the resource owner for state-changing operations. This keeps authorization logic centralized and reduces the risk of missing checks in individual handlers.

import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';

@Injectable()
export class HmacScopeMiddleware implements NestMiddleware {
  constructor(private readonly configService: ConfigService) {}

  use(req: Request, res: Response, next: NextFunction) {
    if (['POST', 'PUT', 'PATCH', 'DELETE'].includes(req.method)) {
      const userId = req.headers['x-user-id'] as string;
      const signature = req.headers['x-signature'] as string;
      if (!userId || !signature) {
        res.status(401).json({ error: 'Missing signature context' });
        return;
      }
      const isValid = verifyHmac(
        this.configService.get('HMAC_SECRET'),
        req.method,
        req.path,
        req.body,
        userId,
        signature,
      );
      if (!isValid) {
        res.status(401).json({ error: 'Invalid signature' });
        return;
      }
      // At this stage, signature is valid; controller still must check ownership
    }
    next();
  }
}

5. Align OpenAPI spec with runtime checks

When using OpenAPI/Swagger, document the requirement that resource IDs must be checked against the subject in the signature context. This supports manual review and automated testing to ensure that generated clients do not omit ownership validation.

6. Key advantages in this setup

  • Hmac signatures include the user context, preventing signature reuse across subjects.
  • Authorization checks explicitly validate resource ownership, closing the BOLA gap.
  • Replay protection via timestamps or nonces reduces the window for signature replay.

By combining Hmac signature validation with strict ownership checks in both middleware and controllers, NestJS applications can mitigate BOLA risks while retaining the integrity guarantees of Hmac Signatures.

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

Does including userId in the Hmac prevent all forms of IDOR?
Including userId in the Hmac reduces the risk of cross-user signature reuse, but you must still enforce ownership checks in your controllers. BOLA can still occur if the server exposes resource IDs without validating that the subject owns them.
How should I rotate Hmac keys to limit exposure from BOLA exploits?
Rotate keys periodically and re-sign active sessions during rotation. When rotating, invalidate old signatures server-side and require clients to recompute signatures with the new key to limit the blast radius of a compromised key.