CWE-284: Improper Access Control
Overview
This guidance helps you interpret and remediate findings from DAST (Dynamic Application Security Testing) tools. The scanner detected that the application granted access to resources or functionality without proper authorization checks, allowing users to access data or perform actions beyond their intended privileges. DAST tools identify this by:
Detection Methods:
- IDOR (Insecure Direct Object Reference): Manipulating identifiers to access other users' resources:
- URL parameters:
/api/users/123→/api/users/124(accessing another user's profile) - POST body IDs:
{"user_id": 124}to view/modify other accounts - Cookie values: changing user ID in session cookie
- URL parameters:
- Horizontal Privilege Escalation: Accessing resources of users at the same privilege level
- Vertical Privilege Escalation: Accessing administrative functions as a regular user:
- Testing admin URLs:
/admin,/admin/users,/api/admin/settings - Role parameter tampering:
?role=admin,{"isAdmin": true}
- Testing admin URLs:
- HTTP Method Bypass: Testing alternative methods when one is protected:
GET /admin→ 403, butPOST /admin→ 200DELETE /api/users/123accessible whenGETrequires auth
- Path Traversal in Authorization: Testing URL normalization bypasses:
/admin/../admin/usersbypassing/admin/*protection/api/public/../private/dataaccessing restricted endpoints
- Missing Authentication: Accessing protected endpoints without credentials
HTTP Evidence:
- HTTP 200 OK responses to resources that should return 401 (Unauthorized) or 403 (Forbidden)
- Successful data retrieval for other users' IDs (JSON/XML containing user 124's data when logged in as user 123)
- Administrative functionality responses accessible to non-admin accounts
- Different response sizes/content when accessing valid vs. invalid resource IDs (timing differences)
- Response headers revealing authorization bypass (missing
X-Frame-Options, lack of CSRF tokens) - Error messages revealing authorization logic ("You are not user 124", "Admin role required")
Scanner Behavior: OWASP ZAP (Access Control Testing add-on) and PortSwigger Burp Suite (Autorize extension, built-in access control testing) systematically test authorization boundaries. They replay requests with different user contexts, manipulate identifiers sequentially, and test role escalation. Advanced scanners crawl as privileged users, then replay discovered requests as unprivileged users to detect missing authorization checks.
Analyzing the Dynamic Scan Result
What the DAST Scanner Found
DAST findings typically show that requests succeed without the expected authorization context, or that modifying identifiers, roles, or request methods results in unauthorized access.
When reviewing your security scan results, you'll see:
HTTP Request Details
- URL and endpoint that triggered the finding
- HTTP method (GET, POST, etc.)
- Query parameters or form data with test payloads
- Request headers and body content
HTTP Response Evidence
- Response showing the vulnerability manifestation
- Evidence of improper handling or authorization not consistently enforced
- Runtime behavior indicators
Attack Vector
- Which parameter or input is vulnerable
- Type of exploitation possible
- Context where the vulnerability appears
Mapping DAST Findings to Source Code
Find the Vulnerable Endpoint
Use the HTTP request URL to locate the code:
# Search for the URL path in your codebase
grep -r "/api/endpoint" src/
grep -r "route.*endpoint" src/
Locate the Route Handler
Common patterns to search for:
- Python Flask/Django:
@app.route('/api/endpoint'),path('endpoint/', ...) - Node.js Express:
app.get('/api/endpoint', ...),router.get('/api/endpoint', ...) - Java Spring:
@GetMapping("/api/endpoint"),@RequestMapping("/api/endpoint") - ASP.NET:
[Route("endpoint")],MapRoute("endpoint", ...) - PHP:
$_GET['param'], route definitions in routing files
Find the Parameter Handling
Search for the vulnerable parameter name:
# Find where the parameter is accessed
grep -r "request.args.get('param')" src/ # Python Flask
grep -r "req.query.param" src/ # Node.js
grep -r "@RequestParam.*param" src/ # Java Spring
grep -r "Request.QueryString['param']" src/ # ASP.NET
grep -r "$_GET['param']" src/ # PHP
Trace to Vulnerable Operation
Look for where the parameter is used in:
- Missing or inconsistent authorization middleware, filters, or guards
- Authorization checks implemented in some routes but not others
- Authorization logic embedded in controllers instead of centralized policy
Remediation
Core Principle: Never allow untrusted input or application flow to determine authorization; access decisions must be enforced by a centralized, server-controlled policy that is evaluated for every request and resource.
→ For comprehensive remediation guidance, see Static CWE-284 Guidance
- Authorization must be enforced in a centralized layer, not scattered across handlers
- Access decisions must be evaluated for every request, regardless of route, method, or parameter
- Authorization logic must be independent of client-supplied roles, flags, or identifiers
Verification and Follow-Up Testing
After applying the fix:
Reproduce the Vulnerability
# Test access without authentication
curl "http://localhost:3000/admin"
curl "http://localhost:3000/api/users/123" # Other user's data
# Test with low-privilege account
curl -H "Authorization: Bearer user_token" "/admin"
Verify the Fix
- Confirm all protected resources require authentication
- Verify ownership checks for resource access (IDOR prevention)
- Check role-based access control enforced server-side
- Ensure horizontal and vertical access controls work
- Test that authorization cannot be bypassed
Test Edge Cases
# Access admin functions as regular user
/admin/users
/api/admin/settings
# IDOR - access other users' data
/api/users/1/profile # When logged in as user 2
/api/orders/999 # Not your order
# Parameter tampering
/api/users?role=admin
/update-profile?user_id=1 # Changing another user
# HTTP method bypass
HEAD /admin # If GET is protected
# Or use browser DevTools Network tab to copy as cURL
Re-run DAST Scanner
Run your dynamic scanner again on the fixed endpoint to confirm remediation.