Skip to content

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
  • 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}
  • HTTP Method Bypass: Testing alternative methods when one is protected:
    • GET /admin → 403, but POST /admin → 200
    • DELETE /api/users/123 accessible when GET requires auth
  • Path Traversal in Authorization: Testing URL normalization bypasses:
    • /admin/../admin/users bypassing /admin/* protection
    • /api/public/../private/data accessing 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.

Additional Resources