HIGH request smugglingfeathersjsjwt tokens

Request Smuggling in Feathersjs with Jwt Tokens

Request Smuggling in Feathersjs with Jwt Tokens — how this specific combination creates or exposes the vulnerability

Request smuggling occurs when an attacker sends a request that is interpreted differently by a frontend (or edge) server and a backend server. In a Feathersjs application that uses JWT tokens for authentication, the framework itself does not introduce the smuggling vector, but the surrounding infrastructure and common integration patterns can expose the application if requests are handled by multiple layers with differing parsing rules.

Consider a deployment where Feathersjs runs behind a reverse proxy or load balancer that terminates TLS and forwards requests to the Node.js process. If the proxy parses and modifies headers differently than Feathersjs—for example, normalizing duplicate headers or stripping certain values—while Feathersjs parses the raw incoming stream, an attacker can craft a request that causes one layer to remove a sensitive header (like an authorization token) while the other layer still sees it. This can lead to authentication bypass or privilege escalation when JWT tokens are involved.

JWT tokens are often passed via the Authorization header (e.g., Authorization: Bearer <token>). If a proxy removes duplicate headers or reorders them, and Feathersjs uses a middleware stack that expects a specific header format, the token may be misinterpreted or omitted by the application layer even though the proxy accepted it. For instance, a client might send two Authorization headers with different casing or ordering, and some servers will merge or pick one while others treat them as distinct. Feathersjs, when used with its default REST and Socket.io transports, will read headers as they arrive; if the proxy normalizes them differently, the application may see an incomplete or missing token, potentially allowing an unauthenticated request to reach a service that should be protected.

Additionally, Feathersjs applications that accept JSON payloads can be vulnerable if the request body is parsed before headers are fully validated. An attacker might send a request with a smuggled body—such as injecting an extra HTTP request chunk—where the first request appears authenticated via JWT while the second request, interpreted by Feathersjs, lacks authentication. This is particularly relevant when Feathersjs is placed behind a gateway that buffers or transforms the request body independently.

Real-world attack patterns mirror classic CVE scenarios such as CVE-2023-23969 (request smuggling via inconsistent header parsing) and exploit the HTTP/1.1 request splitting weakness. The risk is not in Feathersjs itself but in how headers and bodies are handled across layers. When JWT tokens are the sole gatekeeper, any inconsistency in parsing can lead to unauthorized access.

To detect this during a scan, middleBrick runs checks that compare runtime behavior against expected header and body handling, including how JWT tokens are presented and whether they survive proxy transformations. The tool flags inconsistencies between declared authentication requirements and observed behavior, especially when OpenAPI specs define security schemes but runtime requests show missing or malformed tokens.

Jwt Tokens-Specific Remediation in Feathersjs — concrete code fixes

Remediation focuses on ensuring consistent header interpretation and avoiding reliance on potentially smuggled headers. In Feathersjs, enforce strict header parsing and validate JWT tokens in a centralized location before they reach service hooks.

First, configure your reverse proxy or load balancer to normalize headers consistently and avoid sending duplicate or differently cased headers to the application. Then, in Feathersjs, use a hook to verify the Authorization header explicitly and reject requests with multiple or malformed authorization headers.

// src/hooks/authentication.js
const { GeneralError } = require('@feathersjs/errors');

module.exports = function authenticationHook(options = {}) {
  return async context => {
    const { headers } = context.params;
    const authHeader = headers.authorization || headers.Authorization;

    // Reject requests with multiple authorization headers
    const authHeaders = Object.keys(headers)
      .filter(key => key.toLowerCase() === 'authorization')
      .map(key => headers[key]);

    if (authHeaders.length > 1) {
      throw new GeneralError('Multiple authorization headers not allowed', {
        code: 400,
        className: 'authentication'
      });
    }

    if (!authHeader || !authHeader.startsWith('Bearer ')) {
      throw new GeneralError('Unauthorized', { code: 401, className: 'authentication' });
    }

    const token = authHeader.slice(7);
    // Verify JWT token using your preferred library, e.g., jsonwebtoken
    try {
      const payload = verify(token, process.env.JWT_SECRET, { algorithms: ['HS256'] });
      context.params.user = payload;
    } catch (err) {
      throw new GeneralError('Invalid token', { code: 401, className: 'authentication' });
    }

    return context;
  };
};

Second, ensure that your Feathersjs application does not rely on header merging behavior. If you use custom transports or middleware, explicitly extract the token from a single, canonical source. The following example shows how to integrate the hook into a Feathersjs application using REST and Socket.io:

const feathers = require('@feathersjs/feathers');
const rest = require('@feathersjs/express/rest');
const socketio = require('@feathersjs/socketio');
const authenticationHook = require('./hooks/authentication');

const app = feathers();

// Apply the REST and Socket.io adapters
app.configure(rest()).configure(socketio());

// Apply the authentication hook globally for all services
app.hooks({
  before: {
    all: [authenticationHook()]
  }
});

// Define your services and other configuration...

Finally, validate incoming requests against your OpenAPI specification if you use one. Define the security scheme clearly and ensure that generated clients send a single, properly cased Authorization header. This alignment between spec and runtime reduces the chance that a proxy will alter the request in a way that Feathersjs misinterprets.

Frequently Asked Questions

Can request smuggling occur if Feathersjs is used without a reverse proxy?
Yes, if clients send requests with duplicate or ambiguous headers directly to the Node.js server, Feathersjs may interpret them differently depending on how the underlying HTTP parser handles header merging. Always normalize headers at the client and server.
Does middleBrick detect request smuggling vulnerabilities in Feathersjs applications using JWT tokens?
middleBrick scans the runtime behavior of your API, including how JWT tokens in Authorization headers are processed, and flags inconsistencies between expected authentication and observed request handling.