Type Confusion in Feathersjs with Hmac Signatures
Type Confusion in Feathersjs with Hmac Signatures — how this specific combination creates or exposes the vulnerability
Type confusion in a Feathers service that uses Hmac Signatures occurs when the runtime type of a value is not what the application logic expects, and this mismatch is leveraged to bypass intended authorization checks. Feathers applications commonly use hooks for authentication and to validate Hmac signatures, where a client sends a signature derived from a shared secret and a canonical representation of the request (e.g., timestamp, nonce, method, path, and body). If the application incorrectly treats a value as a specific type (e.g., string vs. object, or a numeric string vs. integer) during signature verification or during extracting identifiers used in authorization, an attacker can supply a type that causes the verification logic to behave unexpectedly.
Consider a Feathers hook that verifies an Hmac signature by computing a digest over selected request properties. If the service expects certain properties (such as userId or accountId) to be strings but receives a number or an array due to loose equality checks or inadequate parsing, the computed signature may incorrectly match or fail to match in a way that bypasses intended constraints. For example, if an authorization check relies on an extracted identifier that should be a string but is interpreted as an object or number elsewhere, an attacker might change the type to escalate privileges across resources (BOLA/IDOR). This is a type confusion issue because the comparison or processing logic does not enforce strict type expectations, allowing an attacker to move from one authorization boundary to another by manipulating the input type.
In the context of Hmac Signatures, type confusion can also arise during signature normalization. If the canonical string used to compute the Hmac is built from request fields without enforcing consistent types (e.g., concatenating a number directly into a string without conversion), two different representations of the same logical value could produce different signatures. Conversely, an attacker might supply values that, when coerced, lead to the same normalized string, causing the server to accept a malicious request as valid. Because Feathers services often rely on multiple hooks and may compose authorization rules across service methods, a type confusion vulnerability in one hook can propagate into broader authorization failures, effectively turning a localized validation bypass into an unsafe consumption or privilege escalation scenario.
Real-world patterns that can trigger such issues include using JSON parsing without schema validation, relying on JavaScript type coercion in equality checks (e.g., == instead of ===), and dynamically constructing objects from user input without enforcing strict shape checks. When combined with Hmac-based authentication, these patterns can weaken the binding between the signature and the expected request semantics, enabling an attacker to substitute or reinterpret values in a way the server misinterprets as legitimate. Therefore, enforcing strict types at both the validation and authorization layers is essential to prevent type confusion when Hmac Signatures are used in Feathersjs services.
Hmac Signatures-Specific Remediation in Feathersjs — concrete code fixes
To remediate type confusion in Feathers services using Hmac Signatures, enforce strict type checks, canonicalize inputs consistently, and validate data shapes before using them in signature computation or authorization decisions. Below are concrete code examples that demonstrate secure practices.
Example 1: Strict type checks and canonical Hmac generation
Always convert values to a consistent string type and validate types before including them in the Hmac payload. Use typeof checks and explicit serialization for non-string values.
const crypto = require('crypto');
function buildCanonicalString(req) {
const timestamp = String(req.query.timestamp); // enforce string
const method = String(req.method).toLowerCase();
const path = String(req.path);
// Ensure body fields are canonicalized; here we expect a JSON string or parsed object with strict shape
let body = '';
if (req.body && typeof req.body === 'object' && !Array.isArray(req.body)) {
// Deterministic serialization for canonical form
body = JSON.stringify(req.body, Object.keys(req.body).sort());
} else {
body = '';
}
return `${timestamp}:${method}:${path}:${body}`;
}
function verifyHmac(req, secret) {
const received = req.headers['x-hmac-signature'];
const canonical = buildCanonicalString(req);
const expected = crypto.createHmac('sha256', secret).update(canonical).digest('hex');
// Use timing-safe compare and strict type checks
return crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected));
}
// Usage in a Feathers hook
const hmacAuth = context => {
if (!verifyHmac(context.params, process.env.HMAC_SECRET)) {
throw new Error('Invalid signature');
}
return context;
};
Example 2: Schema-based validation to prevent type confusion
Use a validation library to enforce types for fields used in authorization and Hmac verification. This prevents coercion issues when request inputs vary in type.
const Ajv = require('ajv');
const ajv = new Ajv({ allErrors: true });
const requestSchema = {
type: 'object',
required: ['timestamp', 'path', 'method', 'body'],
properties: {
timestamp: { type: 'string', pattern: '^\\d{10}$' },
method: { type: 'string', enum: ['get', 'post', 'put', 'patch', 'delete'] },
path: { type: 'string' },
body: {
type: 'object',
additionalProperties: false,
properties: {
userId: { type: 'string' },
accountId: { type: 'string' }
}
}
}
};
const validateRequest = ajv.compile(requestSchema);
const validateHook = context => {
const { query, method, path, body } = context.params;
const valid = validateRequest({ timestamp: query.timestamp, method, path, body });
if (!valid) {
throw new Error('Invalid request shape');
}
// Proceed with Hmac verification using strictly typed fields
return context;
};
Example 3: Authorization with strict identifier types
When using Hmac to bind requests to a resource (e.g., an account), ensure identifiers are compared with strict types to avoid confusion between numeric IDs and string IDs, which can lead to BOLA/IDOR.
function getAccountIdFromToken(decoded) {
// Ensure accountId is always a string
const accountId = String(decoded.accountId);
if (!/^[0-9a-fA-F]{24}$/.test(accountId)) {
throw new Error('Invalid accountId');
}
return accountId;
}
// In a Feathers hook after Hmac verification
const enforceResourceOwnership = context => {
const accountId = getAccountIdFromToken(context.params.authPayload);
if (context.params.accountId !== accountId) { // strict equality after both are strings
throw new Error('Unauthorized');
}
return context;
};
By combining strict typing, schema validation, and canonical Hmac construction, you reduce the risk of type confusion when Hmac Signatures are used in Feathersjs services. These practices align with secure handling of authentication data and help maintain clear boundaries between resources.
Related CWEs: inputValidation
| CWE ID | Name | Severity |
|---|---|---|
| CWE-20 | Improper Input Validation | HIGH |
| CWE-22 | Path Traversal | HIGH |
| CWE-74 | Injection | CRITICAL |
| CWE-77 | Command Injection | CRITICAL |
| CWE-78 | OS Command Injection | CRITICAL |
| CWE-79 | Cross-site Scripting (XSS) | HIGH |
| CWE-89 | SQL Injection | CRITICAL |
| CWE-90 | LDAP Injection | HIGH |
| CWE-91 | XML Injection | HIGH |
| CWE-94 | Code Injection | CRITICAL |