Overview
In CVE-2026-32730, the bearer token authentication middleware in @apostrophecms/express/index.js used an incorrect MongoDB query that allowed incomplete login tokens to be treated as fully authenticated bearer tokens. Specifically, a password could be verified but MFA (TOTP) requirements were not enforced, enabling MFA bypass for any ApostropheCMS deployment relying on login-totp or custom afterPasswordVerified flows. This kind of flaw is a classic Broken Authentication issue (CWE-287, CWE-305) where authentication state is either misrepresented or insufficiently validated before granting access. The issue was fixed in version 4.28.0, which explicitly strengthens MFA enforcement during token validation.
Exploitation in the wild would typically involve obtaining a bearer token associated with a user whose password has been verified, but whose MFA state has not been validated. An attacker could reuse such a token to access protected endpoints or administrative functions without completing MFA, especially in deployments that rely on TOTP-based MFA or afterPasswordVerified hooks. The vulnerability undermines defense-in-depth and can lead to data exposure, privilege escalation, and unauthorized administrative actions.
Root cause analyses point to improper authentication checks within Node.js/Express middleware that relies on MongoDB queries. By omitting MFA state from the query (or misrepresenting MFA as satisfied when it is not), the server grants access based on password verification alone. This misalignment between credential verification and MFA enforcement is a direct manifestation of CWE-287 (Improper Authentication) and CWE-305 (Missing Authentication for Critical Function) in a web API context. The fix is to ensure that any token presented for bearer authentication is validated against both password verification and MFA state, ideally with MFA state embedded in the token or strictly enforced during token verification.
Remediation involves upgrading to 4.28.0+ to include the MFA check, auditing token issuance logic to couple MFA state with tokens, and introducing robust server-side validations for all bearer tokens. In addition, implement best practices such as short-lived tokens, token rotation, and automated tests that exercise MFA enforcement under token-based authentication in Node.js/Express environments.
Affected Versions
ApostropheCMS < 4.28.0 (i.e., 4.27.x and earlier)
Code Fix Example
Node.js (Express) API Security Remediation
// VULNERABLE PATTERN
const vulnerableVerifyBearerToken = async (req, res, next) => {
const auth = req.headers.authorization;
if (!auth || !auth.startsWith('Bearer ')) return res.status(401).send('Unauthorized');
const token = auth.slice(7);
// Vulnerable: only checks bearerToken and passwordVerified; MFA (mfaVerified) is not enforced
const user = await db.collection('users').findOne({ bearerToken: token, passwordVerified: true });
if (!user) return res.status(401).send('Unauthorized');
req.user = user;
next();
};
// FIXED PATTERN
const fixedVerifyBearerToken = async (req, res, next) => {
const auth = req.headers.authorization;
if (!auth || !auth.startsWith('Bearer ')) return res.status(401).send('Unauthorized');
const token = auth.slice(7);
// Fixed: require MFA to be verified as part of token verification
const user = await db.collection('users').findOne({ bearerToken: token, passwordVerified: true, mfaVerified: true });
if (!user) return res.status(401).send('Unauthorized');
req.user = user;
next();
};
// Express app wiring (simplified)
const express = require('express');
const app = express();
// assume db is initialized elsewhere
app.get('/secure', vulnerableVerifyBearerToken, (req, res) => {
res.send(`Welcome ${req.user.username}, you accessed a protected resource with a token that bypassed MFA.`);
});
app.get('/secure-fixed', fixedVerifyBearerToken, (req, res) => {
res.send(`Welcome ${req.user.username}, MFA-verified token used.`);
});