Broken Authentication in Express with Firestore
Broken Authentication in Express with Firestore — how this specific combination creates or exposes the vulnerability
Broken Authentication in an Express + Firestore stack typically arises when application-level access controls are incomplete or when Firestore security rules do not enforce user isolation. Express does not provide authentication out of the box; developers must add it explicitly. If session tokens, API keys, or user identifiers are handled inconsistently between Express routes and Firestore rules, attackers can escalate privileges or access other users’ data.
Consider an Express route that retrieves a user profile by ID from the URL without verifying that the authenticated user owns that ID:
app.get('/profile/:uid', async (req, res) => {
const { uid } = req.params;
const snapshot = await db.collection('users').doc(uid).get();
res.json(snapshot.data());
});
If this route relies solely on a client-supplied uid and does not check whether the requesting user matches uid, it enables BOLA/IDOR. Firestore security rules may also be misconfigured to allow broad reads, for example:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read: if true; // Overly permissive
}
}
}
With such rules, any unauthenticated or low-privilege caller can read all user documents. Even when authentication is enforced at the Express layer, permissive rules nullify that protection. Attackers can iterate through numeric or predictable user IDs to harvest profiles, a classic enumeration and access control flaw mapped to OWASP API Top 10 broken authentication and authorization categories.
Another scenario involves token handling: an Express app issues a JWT with a user role claim but does not re-validate ownership on each Firestore request. If the token is stolen, an attacker can act as another user. Firestore rules that do not validate request.auth.uid against document fields enable this lateral movement. Misconfigured CORS in Express can also expose session tokens to unauthorized origins, compounding the risk.
Combinations such as public-read Firestore rules with weak Express session management amplify impact. Findings often include missing ownership checks, overly broad rule conditions, and lack of row-level security, all of which map to compliance frameworks such as OWASP API Top 10 and SOC2. Detection requires correlating runtime requests with Firestore rule behavior and Express authentication logic.
Firestore-Specific Remediation in Express — concrete code fixes
Remediation focuses on enforcing user ownership in Express logic and tightening Firestore security rules so that each user can only access their own data. Always validate the authenticated user’s ID against document paths and rule conditions, and avoid trusting client-supplied identifiers alone.
First, ensure Express routes compare the authenticated subject to the requested resource. Use the request’s authenticated identity rather than a client-provided parameter:
app.get('/profile', async (req, res) => {
// Assume req.user is populated by an auth middleware (e.g., JWT or session)
const userId = req.user.uid;
const snapshot = await db.collection('users').doc(userId).get();
if (!snapshot.exists) {
return res.status(404).json({ error: 'Not found' });
}
res.json(snapshot.data());
});
Second, tighten Firestore rules to enforce ownership and scope:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
}
}
This rule ensures that only authenticated users can read or write their own document. For broader collections, scope access using request.auth.uid in rule conditions and avoid wildcards that allow public access.
In Express, you can further reduce risk by normalizing identifiers and avoiding direct concatenation of user input into Firestore paths. Use middleware to attach user context early and consistently across routes:
function authMiddleware(req, res, next) {
const idToken = req.headers.authorization?.split('Bearer ')[1];
if (!idToken) {
return res.status(401).json({ error: 'Unauthorized' });
}
admin.auth().verifyIdToken(idToken)
.then(decoded => {
req.user = decoded; // { uid, email, roles, ... }
next();
})
.catch(() => res.status(401).json({ error: 'Invalid token' }));
}
app.use(authMiddleware);
Combine this with parameterized queries and strict rule validation to prevent IDOR and privilege escalation. Regularly review rule simulations and runtime findings; tools such as middleBrick can map these configurations to OWASP API Top 10 and compliance frameworks, providing prioritized findings and remediation guidance without claiming to fix or block issues directly.
For continuous coverage, the Pro plan supports scheduled scans and change alerts, while the CLI allows you to integrate checks into scripts. The GitHub Action can add API security checks to your CI/CD pipeline, and the MCP Server lets you scan APIs directly from your AI coding assistant.
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 |