HIGH crlf injectionnestjscockroachdb

Crlf Injection in Nestjs with Cockroachdb

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

Crlf Injection occurs when an attacker can inject a Carriage Return (CR, \r) and Line Feed (\n) sequence into a header or log entry, causing the server to prematurely terminate a line and inject additional lines. In a NestJS application interfacing with CockroachDB, this risk arises not from CockroachDB itself, but from how user-controlled input is handled before being used in logging, HTTP responses, or passed into query-building contexts. If user input containing \r\n is reflected in HTTP response headers, Set-Cookie values, or server-side logs, it can enable response splitting, header injection, or log forging.

When NestJS applications build SQL queries or pass data into the database layer, developers may inadvertently use unsanitized input in logging, error messages, or dynamic query parameters. CockroachDB, while robust, does not inherently sanitize input strings; it executes SQL as provided. If a developer constructs dynamic SQL using string concatenation or template literals with user input, and that input includes \r\n, an attacker can manipulate log lines or, in certain configurations, influence how intermediate proxies or drivers interpret boundaries between statements. For example, a malicious user ID like admin\r\nSet-Cookie: session=attacker could, when naively concatenated into a log entry or response, split headers and cause the client to accept a rogue cookie. Even when using an ORM like TypeORM with CockroachDB, if input is used directly in query building or logging without validation, the injection surface remains.

Another vector involves error handling. If a NestJS service catches database errors and includes raw user input in error messages written to logs, \r\n in that input can forge additional log entries, complicating audit trails. Although CockroachDB returns structured errors, the surrounding application logic must ensure that user input is sanitized before inclusion in any log line or header. MiddleBrick’s LLM/AI Security checks can detect patterns where large language models interact with such endpoints, identifying prompt injection or data exfiltration attempts that may accompany injection flaws.

Cockroachdb-Specific Remediation in Nestjs — concrete code fixes

Remediation focuses on strict input validation, parameterized queries, and avoiding direct concatenation of user input into logs or headers. Never trust request parameters when building responses or logs. Use NestJS pipes for validation and always prefer parameterized queries with CockroachDB to ensure user input is treated as data, not executable content.

1. Use parameterized queries with TypeORM or pg driver

Using placeholders ensures that user input is never interpreted as SQL or header content. Below is a concrete example using TypeORM with CockroachDB, where a user-supplied email is safely used in a query.

// user.entity.ts
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  email: string;

  @Column()
  tenantId: number;
}

// user.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User)
    private readonly userRepository: Repository,
  ) {}

  async findByEmail(email: string): Promise {
    // Parameterized query prevents injection into SQL and avoids header/log injection risks
    return this.userRepository.createQueryBuilder('user')
      .where('user.email = :email', { email })
      .andWhere('user.tenantId = :tenantId', { tenantId: 1 })
      .getMany();
  }
}

If using the native pg driver directly, use query parameters as shown:

// cockroachdb.query.ts
import { Pool } from 'pg';
const pool = new Pool({ connectionString: process.env.DATABASE_URL });

// Safe parameterized query
const queryText = 'SELECT * FROM users WHERE email = $1 AND tenant_id = $2';
const values = [email, tenantId];
const res = await pool.query(queryText, values);

2. Validate and sanitize headers and logs

Ensure that any data used in headers or logs is stripped of \r\n. Implement an interceptor or guard to clean sensitive fields before they reach logging or header-setting code.

// crlf.interceptor.ts
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { map } from 'rxjs/operators';
import { Observable } from 'rxjs';

@Injectable()
export class SanitizeHeaderInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable {
    return next.handle().pipe(
      map((data) => {
        // Example: scrub user-controlled fields that may be used in logging later
        if (data && typeof data === 'object') {
          this.scrubObject(data);
        }
        return data;
      }),
    );
  }

  private scrubObject(obj: any): void {
    for (const key of Object.keys(obj)) {
      const val = obj[key];
      if (typeof val === 'string') {
        obj[key] = val.replace(/[\r\n]+/g, '');
      } else if (typeof val === 'object' && val !== null) {
        this.scrubObject(val);
      }
    }
  }
}

Additionally, configure your logging provider (e.g., Winston, Pino) to filter out \r\n in transport layouts, preventing log injection that could be exploited for further attacks.

3. Apply NestJS validation pipes strictly

Use whitelist and forbidNonWhitelisted options to drop unexpected properties and sanitize strings.

// dto/create-user.dto.ts
import { IsEmail, Matches } from 'class-validator';
export class CreateUserDto {
  @IsEmail()
  @Matches(/^[^\r\n]+$/, { message: 'Newlines and carriage returns are not allowed' })
  email: string;

  @Matches(/^[a-zA-Z0-9_-]+$/, { message: 'Only safe characters allowed' })
  username: string;
}

// user.controller.ts
import { Controller, Post, Body, UsePipes, ValidationPipe } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UserService } from './user.service';

@Controller('users')
export class UserController {
  constructor(private readonly userService: UserService) {}

  @Post()
  @UsePipes(new ValidationPipe({ whitelist: true, forbidNonWhitelisted: true }))
  async create(@Body() createUserDto: CreateUserDto) {
    return this.userService.create(createUserDto);
  }
}

By combining parameterized queries, strict validation, and header/log sanitization, you reduce the attack surface for Crlf Injection in NestJS with CockroachDB. These practices align with secure coding guidance and help ensure that user-supplied data cannot manipulate protocol boundaries.

Frequently Asked Questions

Can Crlf Injection affect CockroachDB queries even when using an ORM?
Yes, if user input is concatenated into raw SQL strings or used in logging and headers, an ORM cannot fully protect against injection. Always use parameterized queries and validate input before it reaches logs or HTTP messages.
Does middleBrick test for Crlf Injection in NestJS APIs?
Yes, as part of its Input Validation and Header/Log integrity checks, middleBrick scans endpoints for injection risks including Crlf Injection. The CLI (middlebrick scan ) and GitHub Action can surface these findings, and the Web Dashboard tracks related issues over time.