HIGH crlf injectionnestjsdynamodb

Crlf Injection in Nestjs with Dynamodb

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

Crlf Injection occurs when user-controlled data is written into HTTP headers without validation, enabling attackers to inject additional header lines (CRLF = Carriage Return + Line Feed). In a NestJS application that uses DynamoDB as a data store, the risk arises when application code reads user input and places it into header-like values that are later forwarded to downstream services or reflected into HTTP responses.

Consider a NestJS service that stores and retrieves custom metadata in DynamoDB. If an attacker can control a metadata value and the application later uses that value in an HTTP header (for example, when generating a redirect or forwarding requests), a newline sequence (%0D%0A or \r\n) can split the header and inject new headers or response body content. DynamoDB itself does not introduce Crlf Injection; the risk is in how your NestJS code handles data retrieved from or stored into DynamoDB before it is used in HTTP messaging.

For example, storing a user-controlled location field into DynamoDB and then returning it in a custom header on an HTTP response can lead to injection:

  • An attacker provides location as OK%0D%0ASet-Cookie:%20session=attacker.
  • Data is persisted in DynamoDB unchanged.
  • When the NestJS controller reads the item from DynamoDB and places the value into a response header, the injected CRLF causes the new Set-Cookie header to be interpreted by the client.

Even when using the AWS SDK for JavaScript with DynamoDB DocumentClient in NestJS, there is no automatic sanitization of header values. If you construct HTTP responses or forward headers using values stored in DynamoDB, you must treat them as untrusted. This is particularly important when combining DynamoDB with features like server-side redirects, pre-signed URL generation, or custom header manipulation in your NestJS controllers or gateway layer.

LLM/AI Security checks available in middleBrick are valuable here because they test for output injection and data exposure risks that may arise when AI-generated or unchecked data from DynamoDB is reflected into headers or logs. These checks include system prompt leakage patterns and active prompt injection probes that help identify unexpected data paths.

Dynamodb-Specific Remediation in Nestjs — concrete code fixes

Remediation focuses on input validation, output encoding, and strict separation of data and control headers. Do not place user-controlled values into HTTP headers. If you must store metadata in DynamoDB and later use it in HTTP responses, treat the data as opaque and avoid header context.

Validate and sanitize on input and enforce strict allow-lists for known fields. For string fields stored in DynamoDB, reject or encode newline characters before persistence. When returning data to clients, use safe serialization formats (e.g., JSON) and set restrictive Content-Type headers to avoid misinterpretation.

Example: safe handling of a location field in a NestJS service using DynamoDB DocumentClient:

import { Injectable } from '@nestjs/common';
import { DynamoDBDocumentClient, PutCommand, GetCommand } from '@aws-sdk/lib-dynamodb';
import { ddbDocClient } from './ddb-client';

@Injectable()
export class MetadataService {
  private readonly TABLE = process.env.METADATA_TABLE;

  // Validate and sanitize before storing
  async storeMetadata(userId: string, location: string): Promise {
    if (!userId || !location) {
      throw new Error('Missing required fields');
    }
    // Reject or encode newline characters to prevent header injection
    if (/[\r\n]/.test(location)) {
      throw new Error('Invalid location: newline characters not allowed');
    }
    const params = {
      TableName: this.TABLE,
      Item: {
        userId,
        location, // stored as-is after validation
        updatedAt: new Date().toISOString(),
      },
    };
    await ddbDocClient.send(new PutCommand(params));
  }

  // Retrieve and use safely in HTTP responses without header injection
  async getMetadata(userId: string): Promise<{ location: string }> {
    const params = {
      TableName: this.TABLE,
      Key: { userId },
    };
    const { Item } = await ddbDocClient.send(new GetCommand(params));
    if (!Item) {
      throw new Error('Not found');
    }
    // Return as JSON body, not as custom headers
    return { location: Item.location };
  }
}

Example: controller that returns safe JSON instead of injecting headers:

import { Controller, Get, Param, ForbiddenException } from '@nestjs/common';
import { MetadataService } from './metadata.service';

@Controller('metadata')
export class MetadataController {
  constructor(private readonly metadataService: MetadataService) {}

  @Get(':userId')
  async getMetadata(@Param('userId') userId: string) {
    const meta = await this.metadataService.getMetadata(userId);
    if (!meta) {
      throw new ForbiddenException('Access denied');
    }
    return meta; // JSON response, safe from header injection
  }
}

Additional measures:

  • Use schema validation (e.g., class-validator) to enforce allowed characters on input fields stored in DynamoDB.
  • When generating pre-signed URLs or interacting with other AWS services, ensure URL parameters are encoded and not derived from unchecked user input that could contain CRLF.
  • Log and monitor responses for unexpected header-like content; middleBrick’s Data Exposure and Output Scanning checks can help detect accidental leakage of sensitive or structured data into logs or responses.

Frequently Asked Questions

Can DynamoDB itself introduce CRLF Injection risks?
No. DynamoDB stores data as attribute-value pairs and does not interpret CRLF characters. The risk comes from how your NestJS application uses data retrieved from DynamoDB, such as placing it into HTTP headers without validation or encoding.
Does middleBrick test for CRLF Injection in API scans?
Yes. middleBrick includes checks for input validation and output encoding as part of its 12 security checks. It can surface CRLF Injection findings when user-controlled input from DynamoDB or other sources is reflected into headers or responses, and it provides remediation guidance.