Broken Access Control in Express with Bearer Tokens
Broken Access Control in Express with Bearer Tokens — how this specific combination creates or exposes the vulnerability
Broken Access Control is an OWASP API Top 10 category that frequently appears in Express services that rely solely on Bearer Tokens for authorization without enforcing role- or scope-based checks on each route. When access controls are broken, an authenticated user can modify ID values, paths, or HTTP verbs to reach resources or actions they should not be allowed to access.
In Express, a common pattern is to verify the presence of a Bearer Token (e.g., via an Authorization header) but then omit per-route authorization checks. For example, an endpoint like GET /users/:userId might validate that a token exists but fail to ensure that the requesting user can only access their own userId or that they have the required role to view other users. This creates a BOLA/IDOR condition, which middleBrick flags as a high-severity finding under the BOLA/IDOR category of its 12 security checks.
Another scenario involves privilege escalation through missing role or scope validation. An Express route that accepts a Bearer Token might call a middleware such as authenticateToken but not validate scopes like admin:read or roles like admin. An attacker who obtains a low-privilege token could then send crafted requests to admin-only endpoints, effectively performing privilege escalation. This maps to the BFLA/Privilege Escalation checks in middleBrick’s scan. Because these checks run in parallel in 5–15 seconds, developers can quickly see whether their unauthenticated attack surface allows such elevation.
Additionally, improper enforcement of access controls on unauthenticated LLM endpoints can indirectly enable information leakage if LLM-specific routes are not scoped to authenticated roles. While middleBrick’s LLM/AI Security checks do not fix these routes, they highlight the absence of proper access governance around AI endpoints, reminding developers to apply the same authorization discipline to LLM handlers as to any other API route.
To illustrate, consider an Express app with a vulnerable route:
const express = require('express');
const app = express();
function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (token == null) return res.sendStatus(401);
// In a real app, verify signature and claims
req.user = { id: 'user-123', role: 'user' };
next();
}
// Vulnerable: no ownership or role checks
app.get('/users/:userId', authenticateToken, (req, res) => {
res.json({ message: `User data for ${req.params.userId}` });
});
app.listen(3000);
In this example, any authenticated user can request /users/any-id and receive data if the server does not enforce ownership. middleBrick would report this as a high-severity BOLA/IDOR finding, recommending that each route validate that the requesting user matches the resource owner or possesses the required scope or role.
Bearer Tokens-Specific Remediation in Express — concrete code fixes
Remediation focuses on ensuring that after Bearer Token authentication, every route enforces strict authorization based on user identity, role, and scope. Below are concrete code examples that demonstrate how to implement these controls in Express.
First, enhance your token verification to decode and validate claims, then create an authorization helper that checks ownership or scopes:
const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();
function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (token == null) return res.sendStatus(401);
jwt.verify(token, process.env.JWT_SECRET, (err, decoded) => {
if (err) return res.sendStatus(403);
req.user = decoded; // { id: 'user-123', role: 'user', scopes: ['read:users'] }
next();
});
}
function canViewUser(requestingUser, targetUserId) {
return requestingUser.id === targetUserId || requestingUser.role === 'admin';
}
function requireScope(scope) {
return (req, res, next) => {
if (!req.user.scopes || !req.user.scopes.includes(scope)) {
return res.status(403).json({ error: 'insufficient_scope' });
}
next();
};
}
// Protected route with ownership check
app.get('/users/:userId', authenticateToken, (req, res) => {
if (!canViewUser(req.user, req.params.userId)) {
return res.status(403).json({ error: 'forbidden' });
}
res.json({ message: `User data for ${req.params.userId}` });
});
// Admin-only route with scope check
app.delete('/users/:userId', authenticateToken, requireScope('admin:delete'), (req, res) => {
if (!canViewUser(req.user, req.params.userId)) {
return res.status(403).json({ error: 'forbidden' });
}
res.json({ message: `User ${req.params.userId} deleted` });
});
app.listen(3000);
This approach ensures that after Bearer Token authentication, each route explicitly validates either resource ownership or required role/scope. For broader protection, you can centralize checks using route-level middleware or a policy engine. middleBrick’s CLI tool (middlebrick scan <url>) can be integrated into development workflows to detect missing authorization controls early, while the GitHub Action can fail builds if a scan detects high-severity access control issues.
For continuous assurance, the Pro plan provides continuous monitoring and configurable scanning schedules so that regressions in access control are caught before they reach production. The Dashboard lets you track these findings over time and prioritize remediation based on severity and compliance mappings to frameworks such as OWASP API Top 10 and SOC2.
Frequently Asked Questions
How does middleBrick detect missing ownership checks in Express APIs using Bearer Tokens?
Can the free plan be used to verify Bearer Token authorization logic in Express during development?
middlebrick scan <url>) and the GitHub Action allow you to integrate scans into local workflows and CI/CD pipelines, with the Pro plan offering continuous monitoring and Slack/Teams alerts.