HIGH crlf injectionsails

Crlf Injection in Sails

How Crlf Injection Manifests in Sails

CRLF injection in Sails applications occurs when untrusted user input containing carriage return ( ) and line feed ( ) characters is incorporated into HTTP headers without proper sanitization. Sails, built on Express.js, inherits Express's header processing behavior, making it vulnerable to this attack when developers inadvertently allow CRLF characters to reach the response headers.

The most common manifestation in Sails occurs through dynamic header manipulation. Consider this typical Sails controller pattern:

module.exports = {
  setCustomHeader: async function (req, res) {
    const headerName = req.query.headerName;
    const headerValue = req.query.headerValue;
    
    res.set(headerName, headerValue);
    res.ok();
  }
};

This code allows an attacker to inject arbitrary headers by crafting requests like:

GET /setCustomHeader?headerName=Location&headerValue=%0d%0a%20Set-Cookie:%20session=malicious HTTP/1.1

The URL-encoded %0d%0a represents CRLF characters. When Sails processes this, it interprets the line break and adds a Set-Cookie header, enabling session fixation attacks.

Another common pattern involves Sails's response object methods that accept dynamic header values:

module.exports = {
  redirectWithHeader: async function (req, res) {
    const redirectUrl = req.query.url;
    const customHeader = req.query.header;
    
    res.set('X-Custom-Header', customHeader);
    res.redirect(redirectUrl);
  }
};

An attacker could exploit this with:

GET /redirectWithHeader?url=https://evil.com&header=%0d%0aSet-Cookie:%20session=malicious HTTP/1.1

Sails's Waterline ORM can also be a vector when query results are used in headers without validation. If a database field contains CRLF characters and is directly used in a response header, injection occurs:

module.exports = {
  showUserProfile: async function (req, res) {
    const userId = req.params.id;
    const user = await User.findOne({ id: userId });
    
    res.set('X-User-Info', user.customHeader);
    res.ok();
  }
};

If the customHeader database field contains malicious CRLF sequences, headers can be manipulated without any URL parameter tampering.

Sails-Specific Detection

Detecting CRLF injection in Sails requires examining both code patterns and runtime behavior. The most effective approach combines static analysis of controller code with dynamic scanning of running endpoints.

Static code analysis should look for these specific Sails patterns:

// Dangerous patterns to flag
res.set(dynamicHeaderName, dynamicValue);
res.set(dynamicValue); // when value contains header
res.location(dynamicUrl); // when URL is user-controlled
res.redirect(dynamicUrl); // when URL is user-controlled

Automated tools can scan Sails projects for these patterns, but runtime scanning provides definitive detection. middleBrick's black-box scanning approach is particularly effective for Sails applications because it tests the actual running API without requiring source code access.

When middleBrick scans a Sails endpoint, it performs these specific CRLF injection tests:

GET /vulnerable-endpoint?header=%0d%0aSet-Cookie:%20session=malicious HTTP/1.1

The scanner monitors the response for unexpected headers, status code changes, or content modifications that indicate successful injection. middleBrick's 12 parallel security checks include specific CRLF detection that examines:

  • Response headers for unauthorized additions
  • HTTP status code manipulation
  • Content-Type header changes
  • Unexpected Set-Cookie headers
  • Cache-control header modifications

For Sails applications using the built-in policies system, middleBrick can scan policy endpoints to verify that request preprocessing doesn't inadvertently introduce CRLF vulnerabilities:

module.exports.policies = {
  '*': ['sanitizeRequest']
};

The scanner tests whether the sanitizeRequest policy properly handles header manipulation attempts, providing a comprehensive security assessment of the entire Sails application stack.

Sails-Specific Remediation

Remediating CRLF injection in Sails applications requires a defense-in-depth approach using Sails's native features and Express.js security practices. The most effective strategy combines input validation, output encoding, and secure coding patterns.

The primary defense is input sanitization using Sails's built-in request object methods. Sails provides req.sanitize() through the validator middleware, which can be configured to strip dangerous characters:

module.exports = {
  sanitizeHeaders: async function (req, res) {
    const headerName = req.sanitize(req.query.headerName).replace(/[
]/g, '');
    const headerValue = req.sanitize(req.query.headerValue).replace(/[
]/g, '');
    
    res.set(headerName, headerValue);
    res.ok();
  }
};

Better yet, avoid dynamic headers entirely and use predefined header names:

module.exports = {
  setCustomHeader: async function (req, res) {
    const headerValue = req.sanitize(req.query.headerValue).replace(/[
]/g, '');
    
    // Only allow specific header names
    const allowedHeaders = ['X-Custom-Info', 'X-User-Role'];
    const headerName = allowedHeaders[0]; // or select based on safe logic
    
    res.set(headerName, headerValue);
    res.ok();
  }
};

For redirects, Sails provides res.redirect() which should be used with caution. Implement URL validation before redirecting:

const url = require('url');

module.exports = {
  safeRedirect: async function (req, res) {
    const redirectUrl = req.query.url;
    
    // Validate URL - only allow same-origin redirects
    const parsedUrl = url.parse(redirectUrl);
    const currentHost = req.get('host');
    
    if (parsedUrl.host !== currentHost) {
      return res.badRequest('Invalid redirect URL');
    }
    
    // Sanitize any headers that might be set during redirect
    const safeUrl = redirectUrl.replace(/[
]/g, '');
    res.redirect(safeUrl);
  }
};

Sails's policy system provides an excellent mechanism for centralized CRLF protection. Create a policy that sanitizes all request parameters:

// api/policies/sanitizeHeaders.js
module.exports = function sanitizeHeaders (req, res, next) {
  // Sanitize all query parameters
  Object.keys(req.query).forEach(key => {
    req.query[key] = req.query[key].replace(/[
]/g, '');
  });
  
  // Sanitize all body parameters
  if (req.body) {
    Object.keys(req.body).forEach(key => {
      if (typeof req.body[key] === 'string') {
        req.body[key] = req.body[key].replace(/[
]/g, '');
      }
    });
  }
  
  next();
};

Apply this policy globally to protect all endpoints:

module.exports.policies = {
  '*': ['sanitizeHeaders']
};

For database-driven header content, implement output encoding when retrieving data:

const he = require('he'); // HTML entities encoding

module.exports = {
  showUserProfile: async function (req, res) {
    const userId = req.params.id;
    const user = await User.findOne({ id: userId });
    
    // Encode any user-controlled header content
    const safeHeader = he.encode(user.customHeader, {
      useNamedReferences: true,
      allowUnsafeSymbols: false
    });
    
    res.set('X-User-Info', safeHeader);
    res.ok();
  }
};

Finally, leverage Sails's configuration system to enforce security headers globally:

// config/security.js
module.exports.security = {
  cors: {
    origin: 'http://example.com',
    credentials: false
  },
  csp: {
    'default-src': ["'self'"]
  },
  // Other security headers automatically set by Sails
};

This configuration ensures that even if CRLF injection succeeds in adding a header, the browser's security model limits the impact through Content Security Policy and other protections.

Frequently Asked Questions

How does middleBrick detect CRLF injection in Sails applications?
middleBrick performs black-box scanning by sending requests with encoded CRLF characters (%0d%0a) in various parameters and headers. The scanner monitors responses for unexpected header additions, status code changes, or content modifications. For Sails applications, it specifically tests controller endpoints that handle dynamic headers, redirects, and user-controlled content. The 5-15 second scan provides a security score with detailed findings about CRLF vulnerabilities, including the exact request that triggered the issue and remediation guidance.
Can I scan my Sails API for CRLF injection using the middleBrick CLI?
Yes, the middleBrick CLI tool allows you to scan any running Sails API endpoint directly from your terminal. Install it with npm install -g middlebrick, then run middlebrick scan https://yourapi.com/vulnerable-endpoint. The CLI provides the same comprehensive CRLF injection testing as the web dashboard, returning a security score (A-F) with detailed findings. You can integrate this into your Sails development workflow by adding it to scripts in package.json or using the GitHub Action for automated scanning in your CI/CD pipeline.