HIGH crlf injectionnestjshmac signatures

Crlf Injection in Nestjs with Hmac Signatures

Crlf Injection in Nestjs with Hmac Signatures — how this specific combination creates or exposes the vulnerability

Crlf Injection occurs when an attacker can inject a Carriage Return (CR, \r) and/or Line Feed (LF, \n) into a header or status-line value. In NestJS applications that construct HTTP responses or forward requests, injecting these characters can allow splitting headers, injecting additional headers, or performing response splitting. When Hmac Signatures are used—commonly to sign request parameters or a canonical string for integrity verification—the impact of Crlf Injection can extend into security-sensitive flows such as signature validation, redirection, or cache poisoning.

Consider a NestJS endpoint that builds a URL for signed requests using Hmac Signatures. If user-controlled input (e.g., a redirect URL or a resource path) is concatenated into the string that is signed without proper sanitization, an attacker can inject \r\n to add extra headers or change the request path within the signature context. For example, a crafted input like example.com/path%0d%0aX-Injected: value can introduce a new header line after the signature is verified, potentially bypassing intended validation logic or causing the server to forward requests to attacker-controlled locations.

In more advanced scenarios, if the NestJS application uses Hmac Signatures to authorize query parameters (e.g., for time-limited tokens or presigned URLs), an injected CRLF can manipulate the request line or headers seen by downstream services. This can lead to request smuggling-style effects where the signed request is interpreted differently by proxies or backend handlers. Because Hmac Signatures bind a canonical string, injected line breaks can change the parsed structure of that string, causing signature mismatches or, worse, allowing an attacker to inject additional parameters that are incorrectly accepted as valid.

Middleware or guards that validate signatures by reconstructing a canonical string from headers, method, and path are especially at risk if they do not sanitize line breaks before hashing. If the reconstruction logic includes user-supplied headers or query values directly, CRLF Injection can alter which data is included in the signature, undermining integrity checks. Even with strict validation, lack of input sanitization on headers like Referer or custom headers used in the signing process can expose the application to injection attacks that modify the effective request scope without invalidating the Hmac Signature.

Because middleBrick tests unauthenticated attack surfaces, it can surface endpoints where CRLF Injection is possible alongside Hmac Signature usage. Findings typically highlight places where newline characters in inputs affect header construction or redirect targets, emphasizing the need to treat Hmac-signed data with the same rigor as any other untrusted input.

Hmac Signatures-Specific Remediation in Nestjs — concrete code fixes

Remediation focuses on strict input validation, canonicalization before signing, and safe construction of headers and redirects. Never directly concatenate user input into strings that form the signature base or into HTTP headers and status lines. Use NestJS built-in validation and encoding utilities to neutralize CR and LF characters.

1. Input validation and encoding

Use NestJS pipes to reject or sanitize inputs that contain CR or LF. For path or query parameters used in signing, enforce a strict pattern and remove or encode newline characters before constructing the canonical string.

import { PipeTransform, Injectable, BadRequestException } from '@nestjs/common';

@Injectable()
export class NoCrlfPipe implements PipeTransform {
  transform(value: string): string {
    if (typeof value !== 'string') {
      return value;
    }
    if (value.includes('\r') || value.includes('\n')) {
      throw new BadRequestException('Invalid input: CRLF not allowed');
    }
    return value;
  }
}

Apply the pipe in your DTOs or route handlers to ensure inputs are clean before they reach signing logic.

2. Safe construction of the canonical string for Hmac signing

When building the string to sign, explicitly normalize line endings and avoid including user-controlled headers or parameters raw. Use deterministic ordering and percent-encode where necessary.

import { createHmac } from 'crypto';

function buildCanonicalString(method: string, path: string, headers: Record<string, string>, timestamp: string): string {
  // Normalize line endings to \n and exclude any header values that may contain CRLF
  const normalizedPath = path.replace(/\r|\n/g, '');
  const normalizedMethod = method.toUpperCase();
  const timestampHeader = `x-timestamp:${timestamp}`;
  // Ensure header values are also sanitized
  const sanitizedHeaders = Object.entries(headers)
    .map(([k, v]) => `${k}:${v.replace(/\r|\n/g, '')}`)
    .join('\n');
  return [normalizedMethod, normalizedPath, timestampHeader, sanitizedHeaders].join('\n');
}

function signPayload(secret: string, method: string, path: string, headers: Record<string, string>, timestamp: string): string {
  const canonical = buildCanonicalString(method, path, headers, timestamp);
  return createHmac('sha256', secret).update(canonical).digest('hex');
}

3. Safe redirects and header setting

If your signed flow involves redirects, validate the target URL and avoid using user input directly in the Location header. Use the built-in NestJS response utilities and ensure the URL does not contain embedded line breaks.

import { Res } from '@nestjs/common';
import { Response } from 'express';

@Res()
redirect(@Param('url', new NoCrlfPipe()) url: string, response: Response) {
  // Ensure url is an absolute, validated URL with no embedded newlines
  const target = new URL(url, 'https://yourdomain.com');
  response.redirect(302, target.toString());
}

4. Middleware/guard for signature verification

When verifying Hmac Signatures, reconstruct the canonical form using only sanitized inputs and fail the request if unexpected line characters are detected in headers or parameters.

import { ExecutionContext, Injectable, NestInterceptor, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';

@Injectable()
export class HmacValidationInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const request = context.switchToHttp().getRequest();
    const receivedSignature = request.headers['x-signature'];
    const timestamp = request.headers['x-timestamp'];
    const sanitizedHeaders = this.sanitizeHeaders(request.headers);
    const canonical = buildCanonicalString(request.method, request.path, sanitizedHeaders, timestamp);
    const expectedSignature = this.computeHmac(canonical, process.env.HMAC_SECRET);
    if (!this.timingSafeEqual(receivedSignature, expectedSignature)) {
      throw new Error('Invalid signature');
    }
    return next.handle();
  }

  private sanitizeHeaders(headers: Record<string, string>): Record<string, string> {
    const sanitized: Record<string, string> = {};
    for (const [k, v] of Object.entries(headers)) {
      sanitized[k] = typeof v === 'string' ? v.replace(/\r|\n/g, '') : String(v);
    }
    return sanitized;
  }

  private timingSafeEqual(a?: string, b?: string): boolean {
    if (!a || !b) return false;
    const bufA = Buffer.from(a);
    const bufB = Buffer.from(b);
    return crypto.timingSafeEqual
      ? crypto.timingSafeEqual(bufA, bufB)
      : bufA.equals(bufB);
  }

  private computeHmac(data: string, secret: string): string {
    return createHmac('sha256', secret).update(data).digest('hex');
  }
}

These patterns ensure that CRLF characters are removed before they can affect header parsing, signature canonicalization, or redirect execution. By combining strict validation, canonicalization, and safe output construction, you reduce the risk of CRLF Injection compromising Hmac-based integrity checks in NestJS.

Frequently Asked Questions

Can CRLF Injection affect Hmac-signed requests even if the signature algorithm itself is sound?
Yes. If user input is included in the canonical string or headers without removing CR/LF characters, an attacker can manipulate how the canonical string is parsed or how headers are split, potentially bypassing intended validation or injecting malicious headers that appear covered by a valid signature.
Does middleBrick detect CRLF Injection risks in endpoints that use Hmac Signatures?
middleBrick scans unauthenticated attack surfaces and flags locations where newline characters in inputs can affect header construction, redirects, or signature canonicalization. Findings include severity, remediation guidance, and mappings to frameworks like OWASP API Top 10 to help prioritize fixes.