HIGH man in the middlefeathersjshmac signatures

Man In The Middle in Feathersjs with Hmac Signatures

Man In The Middle in Feathersjs with Hmac Signatures — how this specific combination creates or exposes the vulnerability

FeathersJS is a framework for real-time web applications that commonly uses transport-agnostic services. When Hmac Signatures are implemented for message integrity, a Man In The Middle (MitM) scenario can still occur if the signature is computed over a subset of the message or if the transport layer is not protected. For example, an attacker positioned between client and server could intercept and modify non-signature parts of the request, such as headers or URL parameters, while the body signature remains valid but no longer reflects the intended operation.

Consider a FeathersJS service that signs only the JSON payload using an Hmac key shared between client and server. If the request path, query parameters, or timestamp are not included in the signed data, an attacker can alter these elements in transit. This leads to Insecure Direct Object References (IDOR) or BOLA-style issues where the victim’s identity or resource ownership is changed without invalidating the signature. Because the server validates only the signature and not the full context of the request, the tampered request may be processed as legitimate.

Another specific risk arises during service discovery or load-balanced deployments where multiple backend instances share the same Hmac key. If a request is forwarded through an untrusted proxy that reorders or duplicates parts of the message, the integrity checks may pass while the effective behavior diverges from the client’s intent. This is especially dangerous when the signature does not cover the entire HTTP method and target path, enabling privilege escalation or unauthorized data access within the same authenticated session.

LLM/AI Security considerations also intersect here: if service endpoints expose verbose error messages or reflection of input within responses, an attacker can iteratively probe how signatures are constructed and which fields are included. Without active prompt injection testing and output scanning, subtle leakage about the signing logic may be revealed through error payloads or logs. middleBrick’s LLM/AI Security checks, including system prompt leakage detection and active prompt injection probes, are designed to surface these risks in unauthenticated scenarios where endpoints are accessible.

Additionally, if an unauthenticated LLM endpoint is used to generate or transform API payloads, a MitM can substitute malicious instructions that still pass Hmac verification because the signature scope is too narrow. This underscores the importance of including method, path, and critical headers in the signed string, and of continuous monitoring for changes in the API surface. middleBrick’s scan can detect whether your OpenAPI/Swagger spec (2.0, 3.0, 3.1) with full $ref resolution aligns with runtime behavior, highlighting gaps where signature coverage is incomplete.

Hmac Signatures-Specific Remediation in Feathersjs — concrete code fixes

To mitigate MitM risks when using Hmac Signatures in FeathersJS, ensure the signature covers all components that an attacker can influence: HTTP method, path, selected headers, and the request body. Below are concrete code examples that demonstrate a robust approach.

Signing the full request context

Create a utility that builds the string to sign from the incoming request data. This example shows a client-side signing function and a corresponding server-side verification in a FeathersJS hook.

// client-side signing utility
function buildStringToSign(method, path, headers, body) {
  const timestamp = Date.now().toString();
  const headersToSign = headers['x-api-key'] + headers['x-request-id'];
  const payload = typeof body === 'string' ? body : JSON.stringify(body);
  return [
    method.toUpperCase(),
    path,
    timestamp,
    headersToSign,
    payload
  ].join('\n');
}

async function signRequest(method, path, headers, body, hmacKey) {
  const stringToSign = buildStringToSign(method, path, headers, body);
  const encoder = new TextEncoder();
  const key = await crypto.subtle.importKey('raw', encoder.encode(hmacKey), { name: 'HMAC', hash: { name: 'SHA-256' } }, false, ['sign']);
  const signature = await crypto.subtle.sign('HMAC', key, encoder.encode(stringToSign));
  return {
    stringToSign,
    signature: Buffer.from(signature).toString('base64'),
    timestamp: stringToSign.split('\n')[2]
  };
}

On the server, use a FeathersJS before hook to verify the signature and reject requests where critical components differ between client and server reconstruction.

// server-side hook (e.g., in src/hooks/verify-hmac.hooks.js)
const crypto = require('crypto');

function verifyHmac(request) {
  const { method, url, headers, body } = request;
  const timestamp = headers['x-timestamp'];
  const clientSignature = headers['x-signature'];
  const apiKey = headers['x-api-key'];

  if (!timestamp || !clientSignature || !apiKey) {
    throw new Error('Missing authentication headers');
  }

  // Reject stale requests to prevent replay
  const age = Date.now() - Number(timestamp);
  if (age > 30000) { // 30 seconds
    throw new Error('Request expired');
  }

  const path = new URL(request.url, `http://${headers.host}`).pathname;
  const headersToSign = apiKey + headers['x-request-id'];
  const payload = typeof body === 'string' ? body : JSON.stringify(body);
  const stringToVerify = [
    method.toUpperCase(),
    path,
    timestamp,
    headersToSign,
    payload
  ].join('\n');

  const hmac = crypto.createHmac('sha256', Buffer.from(process.env.HMAC_SECRET, 'utf8'));
  hmac.update(stringToVerify);
  const expected = hmac.digest('base64');

  if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(clientSignature))) {
    throw new Error('Invalid signature');
  }
}

module.exports = function () {
  return {
    before: {
      all: [verifyHmac]
    }
  };
};

Include full $ref resolution in your OpenAPI/Swagger spec so that generated clients and validators can reconstruct the same string to sign. When using middleBrick’s OpenAPI/Swagger analysis, ensure definitions are consistently referenced to avoid mismatches between documented and actual signed fields.

Transport and key management

Always serve FeathersJS APIs over TLS to prevent on-path modification of headers and body. Rotate Hmac keys periodically and avoid sharing keys across unrelated services. In a load-balanced setup, use a centralized secret store rather than embedding keys in instance-local configuration.

middleBrick’s CLI tool can be integrated into scripts to validate that your endpoints require appropriate authentication and that no unauthenticated LLM endpoints expose signing logic. Use the GitHub Action to fail builds if risk scores degrade, and consider the Pro plan for continuous monitoring of these Hmac-signed services across multiple APIs.

Frequently Asked Questions

What should be included in the string to sign to prevent MitM with Hmac in FeathersJS?
Include the HTTP method, the request path (excluding query parameters that do not affect authorization), a timestamp to prevent replay, any headers used for authorization (e.g., x-api-key, x-request-id), and the request body. This ensures that any modification to these components will cause signature verification to fail.
How does middleBrick help detect risks related to Hmac signature scope in API specs?
middleBrick scans your OpenAPI/Swagger spec (2.0, 3.0, 3.1) with full $ref resolution and compares the documented authentication scheme against runtime checks. It highlights gaps where signatures may not cover critical request dimensions such as method, path, or headers, and flags unauthenticated endpoints that could be probed for signing logic.