Broken Authentication in Feathersjs with Mongodb
Broken Authentication in Feathersjs with Mongodb — how this specific combination creates or exposes the vulnerability
FeathersJS is a framework for real-time APIs that often uses Mongodb as a persistence layer. Broken Authentication can occur when authentication state and credential validation are not handled securely, enabling attackers to bypass login, hijack sessions, or escalate privileges. With Mongodb, misconfigured queries, weak field selection, or insecure merging of user input into database operations can expose authentication-relevant data or allow unauthorized access.
One common pattern in FeathersJS is the use of authentication.js hooks and custom hooks to validate credentials against Mongodb. If these hooks construct queries by directly interpolating user-supplied values without strict schema validation or type checks, an attacker may supply a specially crafted object that changes the intended query logic. For example, a login lookup like { email: req.body.email } can be altered to { email: req.body.email, isAdmin: { $exists: true } } if input is merged unsafely, potentially bypassing intended access controls.
Mongodb’s query language supports operators such as $or, $in, and $regex, which can be misused when application code dynamically builds query objects from untrusted sources. If a FeathersJS service merges partial updates into authentication checks using patterns like {
$or: [
{ email: userInput },
{ username: userInput }
]
} without strict validation, it may inadvertently broaden the search scope and return credentials belonging to other users. This can lead to token confusion or session fixation when combined with weak token handling.
Session tokens stored or transmitted without proper protection amplify the impact. If FeathersJS relies on cookie-based sessions with weak flags (e.g., missing HttpOnly or Secure) or uses JSON Web Tokens with a weak signing algorithm, an attacker who obtains a token can impersonate a user. Mongodb entries that store refresh tokens or reset tokens must be protected with appropriate TTL indexes and strict access rules; otherwise, leaked tokens can be reused across sessions.
Authorization flaws often accompany authentication weaknesses. After authentication, FeathersJS services may fetch user documents from Mongodb and apply role or scope checks in application logic rather than enforcing them at the data access layer. If a query such as usersModel.find({ _id: userId }) is used without ensuring that the requesting user can only access their own document, an attacker may modify the userId parameter to enumerate or manipulate other accounts (a Broken Level of Authorization scenario).
To detect these issues, middleBrick scans the unauthenticated attack surface of a FeathersJS + Mongodb API, checking for authentication bypass vectors, unsafe query construction, token handling weaknesses, and inconsistent authorization enforcement. The scanner cross-references runtime behavior against the OpenAPI specification when available, correlating declared authentication mechanisms with observed responses to highlight gaps such as missing rate limiting on login endpoints or missing password strength enforcement.
Mongodb-Specific Remediation in Feathersjs — concrete code fixes
Remediation focuses on strict query construction, parameter validation, and secure token handling. Always validate and sanitize user input before using it in Mongodb queries, and avoid merging raw user data into query objects.
Secure login hook with strict query
Use a fixed query shape and avoid dynamic injection of fields. Here is an example of a safe login hook in a FeathersJS service file:
// src/hooks/authentication-hook.js
const { Forbidden } = require('@feathersjs/errors');
module.exports = function authenticationHook(options = {}) {
return async context => {
const { email, password } = context.data;
if (!email || !password) {
throw new Forbidden('Missing credentials');
}
// Strict query: only allow known fields, no operator injection
const user = await context.app.service('users').Model.findOne({
email: email,
isActive: true
});
if (!user) {
throw new Forbidden('Invalid credentials');
}
// Compare password using a secure library (e.g., bcrypt)
const valid = await user.comparePassword(password);
if (!valid) {
throw new Forbidden('Invalid credentials');
}
// Do not expose sensitive fields
context.result = {
accessToken: generateToken({ sub: user._id, role: user.role }),
user: {
id: user._id,
email: user.email,
role: user.role
}
};
return context;
};
};
Safe Mongodb update with validation
When updating profile data, use explicit field selection and avoid passing raw user objects directly to update operations. This prevents unwanted field modification or injection of update operators:
// src/services/user/user.service.js
const sanitizeUserUpdate = (data) => {
return {
firstName: data.firstName,
lastName: data.lastName,
email: data.email
// Do not allow _id, role, or isAdmin to be updated from client input
};
};
module.exports = {
async patch(id, data, { user }) {
const safeData = sanitizeUserUpdate(data);
return this.Model.updateOne({ _id: id, 'meta.ownedBy': user.id }, safeData);
}
};
Token handling and query safety
Store tokens securely and enforce strict ownership checks. When querying tokens in Mongodb, use exact matches and avoid regex on sensitive fields. Example of a secure token verification flow:
// src/hooks/token-validation.js
module.exports = function tokenValidationHook(options = {}) {
return async context => {
const token = context.params.query.access_token || context.headers.authorization;
if (!token) {
throw new NotAuthenticated('Access token required');
}
const decoded = verifyToken(token); // Use a trusted JWT library
const user = await context.app.service('users').Model.findOne({
_id: decoded.sub,
tokens: { $in: [token] } // Exact token match, avoid regex
});
if (!user) {
throw new NotAuthenticated('Invalid token');
}
context.params.user = user;
return context;
};
};
Prevent NoSQL injection in Mongodb queries
Never directly pass user input into query operators. Use parameterized values and whitelisted fields. For example, avoid:
// Unsafe
const query = {
$or: [
{ email: userInput },
{ username: userInput }
]
};
// Safer: validate and normalize input first, then use a fixed structure
const safeQuery = {
$or: [
{ email: normalizeEmail(userInput) },
{ username: sanitizeUsername(userInput) }
]
};
Additionally, enforce schema-level constraints in Mongodb (e.g., unique indexes on email) and set appropriate TTL indexes for temporary tokens to reduce the window of exposure.
Related CWEs: authentication
| CWE ID | Name | Severity |
|---|---|---|
| CWE-287 | Improper Authentication | CRITICAL |
| CWE-306 | Missing Authentication for Critical Function | CRITICAL |
| CWE-307 | Brute Force | HIGH |
| CWE-308 | Single-Factor Authentication | MEDIUM |
| CWE-309 | Use of Password System for Primary Authentication | MEDIUM |
| CWE-347 | Improper Verification of Cryptographic Signature | HIGH |
| CWE-384 | Session Fixation | HIGH |
| CWE-521 | Weak Password Requirements | MEDIUM |
| CWE-613 | Insufficient Session Expiration | MEDIUM |
| CWE-640 | Weak Password Recovery | HIGH |