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.