Token Leakage in Feathersjs with Api Keys
Token Leakage in Feathersjs with Api Keys — how this specific combination creates or exposes the vulnerability
Token leakage in a FeathersJS application that uses API keys occurs when secret or session tokens are inadvertently exposed through API responses, logs, or error messages. This risk arises from a mismatch between authentication intent and runtime behavior. FeathersJS is a framework that typically relies on authentication hooks and may pass tokens through contexts, hooks, or service methods without adequate sanitization.
API keys in FeathersJS are often implemented as a custom authentication strategy where a key is validated on each request. If the key is stored or echoed back in responses, included in logs, or returned in error payloads, it can be captured by attackers via logs, browser consoles, or network inspection. For example, a hook that attaches the full API key object to the Feathers context may inadvertently propagate the key into downstream service methods or client responses, especially if the developer does not explicitly strip sensitive fields.
Another leakage vector involves misconfigured CORS or HTTP headers that expose tokens to origins that should not have access. If an API key is embedded in client-side JavaScript to authorize calls, and the API responses include stack traces or detailed errors, the key can be extracted from those error payloads. FeathersJS hooks that do not properly scope context.data or fail to clear authentication metadata between internal calls can also propagate tokens across services unintentionally.
Compliance mappings such as OWASP API Top 10 (2023) highlight API1:2023 Broken Object Level Authorization as a relevant risk when token leakage enables horizontal privilege escalation. Data Exposure checks within middleBrick specifically flag endpoints that return authentication artifacts or secrets in responses, emphasizing the need to audit response schemas and hook behavior. PCI-DSS and SOC2 also require protection of authentication materials, making token leakage a control concern for regulated workloads.
In a middleBrick scan, token leakage findings would appear under Data Exposure and Unsafe Consumption checks, with severity aligned to the scope and accessibility of the exposed token. The report would include remediation guidance focused on sanitizing responses, tightening hook logic, and ensuring tokens are never echoed or logged in clear text.
Api Keys-Specific Remediation in Feathersjs — concrete code fixes
To remediate token leakage when using API keys in FeathersJS, apply strict response filtering, minimize context propagation, and avoid echoing secrets in logs or client responses. Below are concrete code examples that demonstrate secure patterns.
Example 1: Secure API key authentication hook
This hook validates an API key and ensures the key itself is never added to the Feathers context or response.
// src/hooks/authenticate-api-key.js
module.exports = function authenticateApiKey(options = {}) {
return async context => {
const { apikey } = context.data || {};
if (!apikey) {
throw new Error('API key is required');
}
// Validate the API key against your store (e.g., database, env)
const isValid = await validateApiKeyAgainstStore(apikey);
if (!isValid) {
throw new Error('Invalid API key');
}
// Explicitly do NOT attach the raw key to context
// Instead attach a minimal identity for downstream use
context.params.apiKeyId = 'redacted';
return context;
};
};
function validateApiKeyAgainstStore(apikey) {
// Replace with your secure lookup, e.g., a database query
const storedKey = process.env.FEATHERS_API_KEY;
return Promise.resolve(apikey === storedKey);
}
Example 2: Service method that avoids leaking tokens
This service method ensures sensitive fields are omitted before sending the response.
// src/services/users/users.class.js
const { Service } = require('feathersjs');
class UsersService extends Service {
async find(params) {
const result = await super.find(params);
// Remove any authentication tokens or secrets from the response
if (Array.isArray(result.data)) {
result.data = result.data.map(user => this.sanitizeUser(user));
} else if (result.data) {
result.data = this.sanitizeUser(result.data);
}
return result;
}
sanitizeUser(user) {
const { apiKey, refreshToken, ...safeUser } = user.toObject ? user.toObject() : user;
return safeUser;
}
}
module.exports = function setupApp(app) {
app.use('/users', new UsersService({ Model: app.get('User') }));
};
Example 3: Global response sanitizer to prevent token leakage
Use a hook to strip sensitive fields from all responses, ensuring tokens do not reach the client.
// src/hooks/response-sanitize.js
module.exports = function responseSanitize(options = {}) {
return async context => {
const { result } = context;
if (result && typeof result === 'object') {
const { apiKey, secret, token, ...safe } = result;
context.result = safe;
}
return context;
};
};
// In src/app.js after service setup
app.hooks.after.push(responseSanitize());
Operational practices to reduce risk
- Never log API keys or include them in error messages.
- Use environment variables for key storage and rotate keys periodically.
- Apply strict CORS policies to limit which origins can call key-validated endpoints.
- Run middleBrick scans regularly to detect exposed endpoints that may leak tokens.