CWE-285 in APIs
- CWE ID
- CWE-285
- Category
- Bfla Authorization
- Severity
- CRITICAL
- Short Name
- Improper Authz
What is CWE-285?
CWE-285 (Improper Authorization) is a weakness where an application fails to properly verify that a user has the necessary permissions to access a resource or perform an action. This fundamental authorization flaw allows users to access data, functionality, or operations they should not be permitted to use.
The weakness manifests when access control checks are missing, incorrectly implemented, or bypassed entirely. Attackers exploit this by sending requests to endpoints they shouldn't have access to, often by simply changing resource identifiers in the request (like user IDs or document IDs) and observing that the system grants access without proper verification.
Unlike authentication weaknesses (where attackers gain access to the system), CWE-285 occurs after authentication is successful—the attacker is a valid user but performs actions beyond their authorized scope.
CWE-285 in API Contexts
APIs are particularly vulnerable to CWE-285 due to their stateless nature and the way they handle resource identifiers. In RESTful APIs, resources are often identified by IDs passed in URLs or request bodies. Without proper authorization checks, attackers can easily modify these IDs to access other users' data.
Common API manifestations include:
- Direct Object References: APIs expose internal object identifiers (user IDs, document IDs) that attackers can manipulate to access unauthorized resources
- Missing Authorization Headers: APIs fail to validate that the authenticated user has permission to access the requested resource
- Horizontal Privilege Escalation: Users access other users' data within the same privilege level
- Vertical Privilege Escalation: Users access higher-privilege functionality (admin features from regular user accounts)
Consider this vulnerable API endpoint:
GET /api/users/{userId}/profileIf the implementation only checks that a user is authenticated but not whether they're authorized to view that specific user's profile, any authenticated user can access any profile by changing the {userId} parameter.
Detection
Detecting CWE-285 requires both manual code review and automated testing. The weakness is often missed in development because it requires thinking like an attacker—attempting to access resources you shouldn't have permission to view.
Manual detection techniques include:
- Parameter Tampering: Modify resource identifiers in requests to access other users' data
- Role Switching: Test endpoints with different user roles to verify authorization boundaries
- Missing Authorization Checks: Review code paths to ensure authorization is validated before resource access
Automated detection with middleBrick scans for CWE-285 by testing unauthenticated endpoints for authorization bypass vulnerabilities. The scanner attempts to access protected resources without proper authorization tokens and analyzes responses for data exposure. For authenticated endpoints, middleBrick tests BOLA (Broken Object Level Authorization) by systematically modifying resource identifiers and checking if unauthorized access is granted.
middleBrick's Property Authorization check specifically targets CWE-285 by verifying that users can only access properties they're authorized to view, preventing data exposure through improper authorization controls.
Remediation
Fixing CWE-285 requires implementing proper authorization controls throughout your API. The key principle: never trust the client, always verify permissions on the server.
Here's a vulnerable Node.js example:
// VULNERABLE - Missing authorization check
app.get('/api/users/:userId/profile', async (req, res) => {
const userId = req.params.userId;
const profile = await getUserProfile(userId); // No permission check!
res.json(profile);
The secure implementation adds authorization verification:
// SECURE - Proper authorization check
app.get('/api/users/:userId/profile', async (req, res) => {
const userId = req.params.userId;
const authenticatedUserId = req.user.id; // From JWT or session
// Verify the user is authorized to view this profile
if (authenticatedUserId !== userId && !req.user.isAdmin) {
return res.status(403).json({
error: 'Forbidden: You do not have permission to view this profile'
});
}
const profile = await getUserProfile(userId);
res.json(profile);
For more complex authorization scenarios, implement a centralized authorization service:
class AuthorizationService {
static async canAccessResource(user, resourceType, resourceId) {
switch(resourceType) {
case 'userProfile':
return user.id === resourceId || user.isAdmin;
case 'document':
const document = await getDocument(resourceId);
return document.ownerId === user.id || user.isAdmin;
case 'project':
const project = await getProject(resourceId);
return project.teamMembers.includes(user.id) || user.isAdmin;
default:
return false;
}
}
}
// Usage in API endpoint
app.get('/api/projects/:projectId', async (req, res) => {
const { projectId } = req.params;
const user = req.user;
const hasAccess = await AuthorizationService.canAccessResource(
user, 'project', projectId
);
if (!hasAccess) {
return res.status(403).json({ error: 'Access denied' });
}
const project = await getProject(projectId);
res.json(project);
Additional best practices:
- Defense in Depth: Implement authorization at multiple layers (API gateway, service layer, database)
- Least Privilege: Grant users only the minimum permissions they need
- Audit Logging: Log all authorization decisions for security monitoring
- Regular Testing: Include authorization testing in your security QA process
middleBrick helps verify your fixes by scanning for residual authorization weaknesses and providing a security score that reflects your API's authorization posture.