Hallucination Attacks in Feathersjs with Hmac Signatures
Hallucination Attacks in Feathersjs with Hmac Signatures — how this specific combination creates or exposes the vulnerability
A hallucination attack in a Feathers service occurs when an attacker induces the service to produce fabricated or misleading responses, such as returning records the caller should not see or inventing data that never existed. This can happen when authorization logic is misaligned with how requests are authenticated and verified. Using Hmac Signatures for request integrity is a common pattern to ensure the request body and parameters have not been tampered with, but if the service treats the Hmac verification as the sole authorization check, it can hallucinate a trusted context and expose sensitive data or unsafe operations.
In Feathers, a typical vulnerable pattern is to verify the Hmac signature and then directly use user-supplied query or body parameters to build a database query without enforcing proper ownership or scope checks. For example, an attacker can craft a valid Hmac-signed request with a modified userId in the payload or query string. Because the Hmac validates the content but the service trusts the provided userId, the server may hallucinate that the request is from the correct user and return or modify records belonging to another user. This maps to BOLA/IDOR and can leak private data or allow unauthorized changes.
Another scenario involves pagination and filtering parameters. If the service applies Hmac verification and then blindly uses attacker-controlled filter values to construct queries, the attacker can hallucinate filters that bypass intended access controls. Consider an endpoint that lists invoices; a signed request can include a crafted filter that removes the tenant or user restriction on the server side, causing the service to hallucinate an unrestricted dataset. Because Feathers apps often chain multiple hooks, a vulnerable hook can pass tainted parameters to subsequent hooks or services, amplifying the impact.
Hmac Signatures do not inherently bind the request to a specific identity or tenant. If the signature is computed over a subset of the request (e.g., the body) but the server derives the user or scope from other mutable fields, the trust boundary is misaligned. An attacker who can partially control the Hmac-signed portion or can replay a previously signed request with altered non-sensitive fields can exploit this mismatch. For instance, replaying a valid invoice creation request with a different accountId can hallucinate a new invoice under another account if ownership is not re-validated after signature verification.
To summarize the risk: Hmac Signatures ensure integrity but do not enforce authorization. In Feathers, failing to re-validate identity, tenant, and object ownership after verifying the Hmac creates a hallucination attack surface where the service may expose or modify data it should not. Complementary issues such as missing rate limiting or improper result filtering can further enable these attacks.
Hmac Signatures-Specific Remediation in Feathersjs — concrete code fixes
Remediation centers on ensuring that Hmac verification is one layer and that every service enforces strict ownership and scoping after the signature check. Do not trust any client-supplied identifiers for access control. Below are concrete Feathers hooks and service configurations to mitigate hallucination attacks.
Example Hmac verification hook (signature computed over selected body fields)
const crypto = require('crypto');
function verifyHmac(req, secret) {
const { timestamp, nonce, ...payload } = req.body;
const stringToSign = `${timestamp}.${nonce}.${JSON.stringify(payload)}`;
const expected = crypto
.createHmac('sha256', secret)
.update(stringToSign, 'utf8')
.digest('hex');
const received = req.headers['x-hmac-signature'];
if (!received || !crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(received))) {
throw new Error('Invalid Hmac signature');
}
return { timestamp, nonce, ...payload };
}
module.exports = function hmacVerification(secret) {
return function(context) {
const { params } = context;
const raw = params.raw || {};
const body = raw.body || {};
try {
const verified = verifyHmac({ body, headers: params.headers }, secret);
// Replace body with verified content to ensure no tampered fields are used downstream
context.data = verified;
context.params.raw.body = verified;
} catch (error) {
throw new context.app.errors.Unauthorized(error.message);
}
return context;
};
};
Feathers service hook enforcing ownership after Hmac verification
After Hmac verification, re-derive the user identity from a trusted source (e.g., session or JWT) and ensure every query filters by that identity.
const { iff, isProvider } = require('feathers-hooks-common');
function scopeByUserId(userId) {
return (context) => {
const { data, params } = context;
// For find/update/remove, enforce a top-level userId filter
if (isProvider('external')(context)) {
if (!data.userId) {
data.userId = userId;
} else if (String(data.userId) !== String(userId)) {
throw new context.app.errors.Forbidden('Cannot access another user\'s resource');
}
}
// Ensure query filters include userId
if (context.params.query) {
context.params.query.userId = userId;
}
return context;
};
}
// Usage in a Feathers service hooks
const userService = app.service('invoices');
userService.hooks({
before: {
all: [/* other hooks */],
find: [iff(isProvider('external'), scopeByUserId(currentUserIdFromToken))],
get: [iff(isProvider('external'), scopeByAuthenticatedUser)],
create: [hmacVerification(process.envHMAC_SECRET), scopeByAuthenticatedUser],
update: [hmacVerification(process.envHMAC_SECRET), scopeByAuthenticatedUser],
patch: [hmacVerification(process.envHMAC_SECRET), scopeByAuthenticatedUser],
remove: [hmacVerification(process.envHMAC_SECRET), scopeByAuthenticatedUser]
}
});
Safe pagination and filtering to prevent hallucination via parameter manipulation
Do not allow client-supplied skip/limit or filters to remove tenant scoping. Reapply scoping after hook execution if needed.
function safePagination() {
return (context) => {
const { params } = context;
const query = params.query || {};
// Enforce defaults and forbid removal of userId filter
query.$limit = Math.min(query.$limit || 50, 100);
query.$skip = Math.max(query.$skip || 0, 0);
// Ensure tenant/user filter is present and not overridden
if (!query.userId) {
throw new context.app.errors.BadRequest('Missing userId filter');
}
params.query = query;
return context;
};
}
Defense-in-depth recommendations
- Treat Hmac as integrity only; always re-validate identity, tenant, and object ownership in service hooks.
- Use
feathers-hooks-commonhelpers likeiffandisProviderto conditionally apply scoping for external vs internal calls. - Avoid mapping client fields directly to database queries without strict allowlists.
- Log suspicious mismatches between Hmac claims and actual user identifiers for anomaly detection.
Related CWEs: llmSecurity
| CWE ID | Name | Severity |
|---|---|---|
| CWE-754 | Improper Check for Unusual or Exceptional Conditions | MEDIUM |