HIGH header injectionfeathersjs

Header Injection in Feathersjs

How Header Injection Manifests in Feathersjs

Header injection vulnerabilities in Feathersjs applications typically occur when user-controlled data flows into HTTP response headers without proper validation or sanitization. In Feathersjs, this often happens through dynamic header construction in service hooks, middleware, or custom response handling.

A common Feathersjs pattern that creates injection risk is building Location headers from user input:

app.service('users').hooks({
  after: {
    create: async (context) => {
      const { email } = context.result;
      // Vulnerable: user-controlled email in Location header
      context.response.headers.location = `/verify?email=${email}`;
    }
  }
});

If an attacker registers with an email like [email protected]%0d%0aX-Injected: malicious-value, the Location header becomes:

Location: /[email protected]%0d%0aX-Injected: malicious-value

This breaks the header structure, injecting arbitrary header fields. Feathersjs's response object, being Express-compatible, processes these as separate headers.

Another Feathersjs-specific scenario involves dynamic header setting in custom service methods:

class CustomService {
  async create(data, params) {
    const { customHeader } = data;
    // Vulnerable: arbitrary header injection
    this.app.response.set(customHeader, 'some-value');
    return data;
  }
}

Header injection can also occur when Feathersjs services proxy requests to external APIs and forward headers without validation:

app.service('proxy').hooks({
  before: {
    find: async (context) => {
      const { forwardedHeaders } = context.params.query;
      // Vulnerable: user controls which headers are forwarded
      Object.keys(forwardedHeaders).forEach(key => {
        context.app.response.set(key, forwardedHeaders[key]);
      });
    }
  }
});

These patterns are particularly dangerous in Feathersjs because the framework's hook system makes it easy to manipulate responses across the entire application lifecycle.

Feathersjs-Specific Detection

Detecting header injection in Feathersjs requires examining both the codebase and runtime behavior. Start by auditing your hooks and service methods for dynamic header construction patterns.

Static analysis should focus on:

# Search for header manipulation patterns
grep -r "\.set(" services/ hooks/ middleware/
grep -r "headers\." services/ hooks/ middleware/
grep -r "Location" services/ hooks/ middleware/

Look for patterns where header names or values contain user input without validation. Pay special attention to hooks that manipulate context.response or use hook.app.response.

For runtime detection, middleBrick's black-box scanning identifies header injection vulnerabilities by:

  • Testing for CRLF injection in parameters that might affect headers
  • Analyzing response headers for unexpected fields
  • Checking for header injection in OpenAPI spec compliance

middleBrick specifically tests Feathersjs applications by sending payloads designed to trigger header injection and analyzing the responses for injected headers:

# Scan your Feathersjs API with middleBrick
middlebrick scan https://your-feathersjs-app.com/api

# Or use the CLI for detailed output
middlebrick scan --verbose https://your-feathersjs-app.com/api

The scanner checks for common injection patterns like:

%0d%0aContent-Type: text/html%0d%0a%0d%0a<script>alert(1)</script>

middleBrick's LLM security module also detects if your Feathersjs app has AI endpoints vulnerable to prompt injection that could lead to header manipulation through indirect prompt injection attacks.

Feathersjs-Specific Remediation

Remediating header injection in Feathersjs requires a defense-in-depth approach. Start by validating and sanitizing all user input that might affect headers.

For header name validation, use a whitelist approach:

const VALID_HEADER_NAMES = new Set([
  'content-type', 'location', 'x-custom-header'
]);

function sanitizeHeaderName(name) {
  const lowerName = name.toLowerCase();
  if (!VALID_HEADER_NAMES.has(lowerName)) {
    throw new Error(`Invalid header name: ${name}`);
  }
  return lowerName;
}

// In your hooks
app.service('users').hooks({
  after: {
    create: async (context) => {
      const { email } = context.result;
      const sanitizedEmail = encodeURIComponent(email);
      context.response.headers.location = `/verify?email=${sanitizedEmail}`;
    }
  }
});

For header value sanitization, use a dedicated library:

const { sanitizeHeader } = require('header-sanitizer');

app.service('proxy').hooks({
  before: {
    find: async (context) => {
      const { forwardedHeaders } = context.params.query;
      
      Object.keys(forwardedHeaders).forEach(key => {
        const sanitizedKey = sanitizeHeaderName(key);
        const sanitizedValue = sanitizeHeader(forwardedHeaders[key]);
        context.app.response.set(sanitizedKey, sanitizedValue);
      });
    }
  }
});

Implement a security middleware for comprehensive protection:

const headerSecurityMiddleware = async (context, next) => {
  // Validate before hooks
  if (context.type === 'before') {
    const { headers } = context.params;
    Object.keys(headers).forEach(key => {
      if (!VALID_HEADER_NAMES.has(key.toLowerCase())) {
        throw new Error(`Forbidden header: ${key}`);
      }
    });
  }
  
  // Validate after hooks
  await next();
  
  if (context.type === 'after') {
    const responseHeaders = context.response.headers;
    Object.keys(responseHeaders).forEach(key => {
      if (!VALID_HEADER_NAMES.has(key.toLowerCase())) {
        delete responseHeaders[key];
      }
    });
  }
};

// Apply globally
app.hooks({
  before: headerSecurityMiddleware,
  after: headerSecurityMiddleware
});

For Feathersjs applications with TypeScript, add type safety:

type SanitizedHeaderName = 
  | 'content-type' 
  | 'location' 
  | 'x-custom-header';

interface HeaderSanitizationHook {
  (context: HookContext): Promise<void>;
}

const headerSanitizationHook: HeaderSanitizationHook = async (context) => {
  const { headers } = context.params;
  const sanitizedHeaders: Record<SanitizedHeaderName, string> = {};
  
  Object.keys(headers).forEach(key => {
    const lowerKey = key.toLowerCase() as SanitizedHeaderName;
    if (VALID_HEADER_NAMES.has(lowerKey)) {
      sanitizedHeaders[lowerKey] = headers[key];
    }
  });
  
  context.params.headers = sanitizedHeaders;
};

middleBrick's Pro plan includes continuous monitoring that can automatically scan your Feathersjs API on a schedule, alerting you if new header injection vulnerabilities are introduced through code changes.

Frequently Asked Questions

How can I test my Feathersjs app for header injection vulnerabilities?
Use middleBrick's black-box scanning by running middlebrick scan https://your-feathersjs-app.com/api. The scanner tests for CRLF injection, analyzes response headers, and checks for injection in OpenAPI spec compliance. For manual testing, send requests with %0d%0a sequences in parameters and check if they create new headers in the response.
Does middleBrick's LLM security module help with header injection?
Yes, middleBrick's unique LLM security module detects AI endpoints vulnerable to prompt injection that could lead to header manipulation through indirect prompt injection attacks. It also checks for excessive agency in LLM responses that might allow unintended header manipulation. This is particularly relevant for Feathersjs apps using AI services like OpenAI or Anthropic.