HIGH crlf injectionkoa

Crlf Injection in Koa

How Crlf Injection Manifests in Koa

CRLF injection in Koa applications occurs when unvalidated user input is incorporated into HTTP headers, allowing attackers to inject carriage return and line feed characters ( ) to manipulate the protocol. Koa's middleware architecture and context object make certain patterns particularly vulnerable.

The most common Koa-specific vulnerability arises from improper handling of the ctx.set() method. When developers dynamically construct header names or values from user input without sanitization, attackers can inject additional headers or split responses:

const Koa = require('koa');
const app = new Koa();

app.use(async (ctx) => {
  // VULNERABLE: User input directly in header value
  const filename = ctx.query.filename || 'default.txt';
  ctx.set('Content-Disposition', `attachment; filename="${filename}"`);
  ctx.body = 'This is a file';
});

An attacker could request /download?filename=foo.txt%0D%0A%0D%0AHTTP/1.1%20200%20OK%0D%0AContent-Type%3A%20text/plain%0D%0A%0D%0AHacked! to manipulate the response.

Another Koa-specific pattern involves the ctx.redirect() method. When redirect URLs are constructed from user input without validation, CRLF characters can be injected:

app.use(async (ctx) => {
  // VULNERABLE: No URL validation
  const redirect = ctx.query.next || '/';
  ctx.redirect(redirect);
});

Attackers could redirect to URLs containing CRLF sequences to manipulate headers or initiate HTTP response splitting attacks.

Koa's body parsing middleware can also introduce CRLF vulnerabilities when handling multipart form data. The koa-body middleware processes file uploads and form fields, but improper configuration can allow CRLF injection in content headers:

const koaBody = require('koa-body');

app.use(koaBody({
  multipart: true,
  formidable: {
    keepExtensions: true
  }
}));

app.use(async (ctx) => {
  // VULNERABLE: Directly using user-provided filename
  const file = ctx.request.files.upload;
  ctx.set('Content-Disposition', `attachment; filename="${file.name}"`);
  ctx.body = file;
});

The ctx.cookies.set() method presents another attack vector. When cookie values contain CRLF characters, they can break the HTTP response structure:

app.use(async (ctx) => {
  // VULNERABLE: No sanitization of cookie value
  const userId = ctx.query.userId || 'guest';
  ctx.cookies.set('user_id', userId);
  ctx.body = 'Welcome!';
});

Koa-Specific Detection

Detecting CRLF injection in Koa applications requires both static analysis and dynamic testing. For static analysis, look for patterns where user input flows into header-related operations:

// Patterns to search for:
ctx.set(userInput, value);
ctx.set(header, userInput);
ctx.redirect(userInput);
ctx.cookies.set(name, userInput);
ctx.append(header, userInput);

Dynamic testing should include sending payloads with percent-encoded CRLF sequences (%0D%0A) to endpoints that handle headers, redirects, or file operations. Test with payloads like:

filename=test.txt%0D%0A%0D%0AHTTP/1.1%20200%20OK%0D%0AContent-Type%3A%20text/plain%0D%0A%0D%0AHacked!
next=%2F%3Ffoo%3Dbar%0D%0ASet-Cookie%3A%20hacked%3Dtrue

middleBrick's black-box scanning approach is particularly effective for Koa applications because it tests the actual runtime behavior without requiring source code access. The scanner automatically tests for CRLF injection across all 12 security categories, including header manipulation attempts.

When middleBrick scans a Koa API endpoint, it sends specialized payloads to detect CRLF injection vulnerabilities. The scanner checks for:

  • Header injection through ctx.set() operations
  • Response splitting via ctx.redirect()
  • Cookie manipulation through ctx.cookies.set()
  • Content-Disposition header manipulation
  • Custom header injection

The scanner provides specific findings with severity levels and remediation guidance. For example, a typical finding might indicate that a specific endpoint is vulnerable to HTTP response splitting via the filename parameter, with the exact payload that triggered the vulnerability.

For Koa applications using TypeScript, additional detection considerations apply. The static type system doesn't prevent CRLF injection, so runtime validation remains essential:

app.use(async (ctx: Context) => {
  const filename = ctx.query.filename as string;
  // Type checking alone doesn't prevent CRLF injection
  ctx.set('Content-Disposition', `attachment; filename="${filename}"`);
});

Koa-Specific Remediation

Remediating CRLF injection in Koa requires input validation and sanitization before header operations. The most effective approach combines whitelist validation with proper encoding.

For filename parameters in Content-Disposition headers, implement strict validation:

const { extname, basename } = require('path');

function sanitizeFilename(input) {
  // Allow only alphanumeric, hyphens, underscores, and dots
  if (!/^[a-zA-Z0-9._-]+$/.test(input)) {
    throw new Error('Invalid filename');
  }
  
  // Prevent directory traversal
  if (input.includes('/') || input.includes('\')) {
    throw new Error('Invalid filename');
  }
  
  return input;
}

app.use(async (ctx) => {
  try {
    const filename = sanitizeFilename(ctx.query.filename || 'default.txt');
    ctx.set('Content-Disposition', `attachment; filename="${filename}"`);
    ctx.body = 'This is a file';
  } catch (err) {
    ctx.status = 400;
    ctx.body = 'Invalid filename';
  }
});

For redirect parameters, validate against a whitelist of allowed URLs or use a safe redirect helper:

function safeRedirect(ctx, url) {
  // Validate URL against whitelist
  const allowedRedirects = ['/dashboard', '/profile', '/settings'];
  
  if (!allowedRedirects.includes(url)) {
    ctx.throw(400, 'Invalid redirect URL');
    return;
  }
  
  ctx.redirect(url);
}

app.use(async (ctx) => {
  const redirect = ctx.query.next || '/';
  safeRedirect(ctx, redirect);
});

For cookie values, implement strict sanitization:

function sanitizeCookieValue(value) {
  // Remove any CRLF characters
  return value.replace(/[
]/g, '');
}

app.use(async (ctx) => {
  const userId = sanitizeCookieValue(ctx.query.userId || 'guest');
  ctx.cookies.set('user_id', userId, {
    httpOnly: true,
    secure: true
  });
  ctx.body = 'Welcome!';
});

Koa's built-in context methods provide some protection, but don't eliminate the need for validation. The ctx.assert() method can help enforce input constraints:

app.use(async (ctx) => {
  const filename = ctx.query.filename;
  
  // Assert that filename contains no dangerous characters
  ctx.assert(filename, 400, 'Filename required');
  ctx.assert(!/[\r\n%]/.test(filename), 400, 'Invalid filename');
  
  ctx.set('Content-Disposition', `attachment; filename="${filename}"`);
  ctx.body = 'This is a file';
});

For applications using third-party middleware like koa-body, configure proper validation at the middleware level:

const koaBody = require('koa-body');

app.use(koaBody({
  multipart: true,
  formidable: {
    onPart: (part) => {
      // Validate header names and values
      if (part.headers['content-disposition']) {
        // Check for CRLF in content-disposition
        if (/[\r\n]/.test(part.headers['content-disposition'])) {
          part.resume(); // Skip this part
          return;
        }
      }
      part.read();
    }
  }
}));

middleBrick's remediation guidance for Koa applications includes specific code examples like these, mapped to the exact vulnerability detected. The scanner's findings help developers understand which endpoints and parameters are vulnerable, making targeted remediation straightforward.

Frequently Asked Questions

How does middleBrick detect CRLF injection in Koa applications without access to the source code?
middleBrick uses black-box scanning to test the runtime behavior of your Koa API endpoints. The scanner sends specialized payloads containing percent-encoded CRLF sequences (%0D%0A) to parameters that might be used in header operations. It then analyzes the HTTP responses to detect whether the injection was successful, checking for response splitting, header injection, or other manipulation indicators. This approach works regardless of whether your application is written in JavaScript, TypeScript, or uses any specific middleware.
Can CRLF injection in Koa lead to more serious attacks beyond response manipulation?
Yes, successful CRLF injection can enable several escalation paths. HTTP response splitting can be used for cache poisoning, where malicious content is stored in proxy caches and served to other users. In some cases, it can facilitate cross-site scripting (XSS) by injecting script tags into responses. For APIs that serve downloadable content, it can be used to manipulate file names or content types. Additionally, if combined with other vulnerabilities like open redirects, attackers can create more sophisticated phishing or credential harvesting attacks.