Validate authorization failures including IDOR, privilege escalation, and missing access controls. Test by attempting unauthorized access with lower-privileged credentials...
Validate authorization failures by attempting actions that should be blocked based on:
Access other users' resources by manipulating object IDs.
Test Pattern: Authenticate as User A, access User B's resource (change ID in URL/params)
Expected: 403 Forbidden | Actual if vulnerable: 200 OK
Example: /api/user/456 accessed by user 123
Perform actions requiring higher privileges than possessed.
Test Pattern: Authenticate as regular user, attempt admin/privileged action
Expected: 403 Forbidden | Actual if vulnerable: 200 OK
Examples:
/admin/delete_user/update_roleAccess peer users' resources at same privilege level.
Test Pattern: Authenticate as User A (regular), access/modify User B's data (also regular)
Expected: 403 Forbidden | Actual if vulnerable: 200 OK
Example: User 2 modifies User 3's profile
Actions execute without ANY authorization check.
Test Pattern: Authenticate with minimal privileges, attempt protected action
Expected: 403 Forbidden | Actual if vulnerable: 200 OK
Example: Unauthenticated or low-privilege access to /api/admin/users
Wrong authorization logic applied to functions.
Test Pattern: Authenticate as user authorized for function X, attempt function Y (should be blocked) Expected: 403 Forbidden | Actual if vulnerable: 200 OK Example: Read-only user performs write operation
Access restricted functionality by directly requesting URLs, bypassing normal navigation flow.
Test Pattern: Request admin/protected URL directly without proper authorization flow Expected: 403 Forbidden or redirect to login | Actual if vulnerable: 200 OK Examples:
/admin/dashboard without admin session/api/internal/config endpoint/reports/confidential by guessing URL structureBefore testing, read the source code to identify:
Key insight: Each app implements authorization differently. Read the code first!
Map vulnerabilities to test types:
| CWE | Vulnerability | Test Type | Accounts Needed |
|---|---|---|---|
| CWE-639 | IDOR on /api/user/<id> |
Horizontal | 2 regular users |
| CWE-269 | Missing admin check on /update_role |
Vertical | 1 regular, 1 admin |
| CWE-862 | No authz on /admin/dashboard |
Missing | 1 regular user |
| CWE-863 | Flawed check on /api/profile/<id>/update |
IDOR | 2 regular users |
| CWE-284 | Generic access control bypass | Varies | Based on context |
| CWE-285 | Wrong authz logic on read-only endpoint | Function-level | Read-only + write user |
| CWE-425 | Direct URL access to /admin/config |
Forced browsing | 1 regular user |
If .securevibes/DAST_TEST_ACCOUNTS.json exists:
{
"accounts": [
{"username": "user1", "password": "Pass123!", "user_id": "123", "role": "user"},
{"username": "user2", "password": "Pass456!", "user_id": "456", "role": "user"},
{"username": "admin", "password": "Admin789!", "user_id": "1", "role": "admin"}
]
}
Extract credentials for:
If no test accounts:
Read application code to determine auth mechanism, then use authentication helpers from reference/auth_patterns.py:
from reference.auth_patterns import session_based_auth, jwt_bearer_auth, api_key_auth
# Session-based (Flask, Express, Django)
session = session_based_auth(target_url, user1_username, user1_password)
response = session.get(f"{target_url}/api/resource")
# JWT Bearer (REST APIs)
headers = jwt_bearer_auth(target_url, user1_username, user1_password)
response = requests.get(f"{target_url}/api/resource", headers=headers)
# API Key
headers = api_key_auth(api_key_for_user1)
response = requests.get(f"{target_url}/api/resource", headers=headers)
See reference/auth_patterns.py for additional patterns (OAuth2, Basic auth) and customization options.
Universal Pattern:
1. Authenticate with LOW privilege credentials
2. Baseline: Attempt ALLOWED action → 200 OK (verify auth works)
3. Test: Attempt BLOCKED action → ???
4. Classify:
- 200 OK: VALIDATED (authorization bypass!)
- 403/401: FALSE_POSITIVE (authorization working correctly)
- Other: UNVALIDATED (unclear/error)
Test Variants by Vulnerability Type:
# User A accesses User B's resource
auth_as(user_a) # user_id: 123
# Baseline: own resource
GET /api/user/123 → 200 OK ✓
# Test: other user's resource
GET /api/user/456 → ???
# Expected: 403 Forbidden
# Actual if vulnerable: 200 OK with user 456's data
# Classification: VALIDATED (CWE-639)
# Regular user performs admin action
auth_as(regular_user) # role: user
# Baseline: allowed action
GET /dashboard → 200 OK ✓
# Test: admin action
POST /admin/delete_user {"user_id": 123} → ???
# Expected: 403 Forbidden
# Actual if vulnerable: 200 OK, user deleted
# Classification: VALIDATED (CWE-269)
# User escalates own role
auth_as(regular_user) # user_id: 123, role: user
# Baseline: check current role
GET /api/user/123 → {"role": "user"} ✓
# Test: modify own role
POST /update_role {"user_id": 123, "role": "admin"} → ???
# Expected: 403 Forbidden
# Actual if vulnerable: 200 OK, role changed to admin
# Classification: VALIDATED (CWE-269)
# User A modifies User B's data
auth_as(user_a) # user_id: 123
# Baseline: modify own profile
POST /api/profile/123/update {"email": "me@example.com"} → 200 OK ✓
# Test: modify other user's profile
POST /api/profile/456/update {"email": "evil@attacker.com"} → ???
# Expected: 403 Forbidden
# Actual if vulnerable: 200 OK, user 456's profile modified
# Classification: VALIDATED (CWE-639)
Capture minimal structured evidence with redaction and truncation:
{
"status": "VALIDATED|FALSE_POSITIVE|PARTIAL|UNVALIDATED",
"baseline": {
"url": "http://target.com/api/user/123",
"method": "GET",
"status": 200,
"response_snippet": "{\"id\": 123, \"role\": \"user\"}",
"response_hash": "sha256:abc123...",
"truncated": false,
"original_size_bytes": 58
},
"test": {
"url": "http://target.com/update_role",
"method": "POST",
"payload": "{\"user_id\": 123, \"role\": \"admin\"}",
"status": 200,
"response_snippet": "{\"success\": true}",
"response_hash": "sha256:def456...",
"truncated": false,
"original_size_bytes": 18
},
"evidence": "User 123 escalated own role from 'user' to 'admin'"
}
Evidence Fields:
| Field | Required | Description |
|---|---|---|
response_snippet |
Yes | First 8KB of response body (text only) |
response_hash |
Yes | SHA-256 hash of complete response (format: sha256:...) |
truncated |
Recommended | true if response exceeded 8KB limit, false otherwise |
original_size_bytes |
Recommended | Full response size before truncation |
Truncation Pattern:
truncated: trueoriginal_size_bytes to show actual response sizeExample with Large Response:
{
"baseline": {
"url": "http://target.com/api/users/export",
"method": "GET",
"status": 200,
"response_snippet": "[truncated 8KB of 250KB JSON array...]",
"response_hash": "sha256:789abc...",
"truncated": true,
"original_size_bytes": 256000
}
}
CRITICAL Redaction Requirements:
Redact these sensitive field types from response snippets:
Redaction Example:
// Before redaction
{"user": {"password": "MySecret123", "ssn": "123-45-6789"}}
// After redaction
{"user": {"password": "[REDACTED]", "ssn": "[REDACTED]"}}
if response.status_code == 200:
if action_should_be_blocked:
return "VALIDATED" # Authorization bypass confirmed!
else:
return "FALSE_POSITIVE" # Action was allowed (not a vulnerability)
elif response.status_code in [401, 403]:
return "FALSE_POSITIVE" # Authorization working correctly
elif mixed_results_requiring_manual_review:
return "PARTIAL" # Some tests passed, others failed - needs human review
else:
return "UNVALIDATED" # Ambiguous result (error, timeout, etc.)
Status Type Definitions:
| Status | Meaning | When to Use |
|---|---|---|
| VALIDATED | Vulnerability confirmed | 200 OK received when accessing unauthorized resource/action |
| FALSE_POSITIVE | Security working correctly | 401/403 received, access properly denied |
| PARTIAL | Mixed results | Some operations succeeded, others failed; requires manual review |
| UNVALIDATED | Test inconclusive | Error, timeout, or ambiguous response preventing classification |
PARTIAL Status Criteria:
Example PARTIAL Scenario:
# Testing /api/document/{id} endpoint
GET /api/document/456 → 200 OK (IDOR on read)
PUT /api/document/456 → 403 Forbidden (write protected)
DELETE /api/document/456 → 403 Forbidden (delete protected)
# Classification: PARTIAL
# Reason: Read access bypassed (IDOR), but modification/deletion properly blocked
# Requires manual review to assess actual risk
CRITICAL: Keep responses concise (1-4 sentences)
Format for VALIDATED (any authz failure):
Authorization bypass on [endpoint] - [low_priv_user] successfully performed [high_priv_action] (200 OK). [Impact]. Evidence: [file_path]
Format for FALSE_POSITIVE:
Authorization check working on [endpoint] - access properly denied with [status_code]. Evidence: [file_path]
Format for PARTIAL:
Partial authorization bypass on [endpoint] - [operation1] succeeded (200 OK) but [operation2] blocked ([status_code]). Requires manual review. Evidence: [file_path]
Format for UNVALIDATED:
Authorization test incomplete on [endpoint] - [reason]. Evidence: [file_path]
Examples:
IDOR (horizontal):
Authorization bypass on /api/user - user 123 accessed user 456's PII (200 OK). Exposed email, phone, address.
Privilege escalation (vertical):
Authorization bypass on /update_role - regular user escalated to admin role (200 OK). Full system compromise possible.
Cross-user modification:
Authorization bypass on /api/profile/1/update - user 2 modified admin profile (200 OK). Account takeover risk.
What NOT to do:
This skill validates:
Skill Responsibilities:
.securevibes/dast_audit.log)Scanner Responsibilities (handled at infrastructure level):
.com, .net, api., www. domains)--allow-production flag requirement for production testingImportant: This skill focuses on testing methodology. Safety gates (production detection, confirmation prompts, reachability checks) are implemented by the SecureVibes scanner, not the skill itself.
For comprehensive vulnerability-specific examples with code and evidence, see examples.md:
IDOR Test (Horizontal):
User 123 → GET /api/user/456 → 200 OK with user 456's data
Classification: VALIDATED (CWE-639)
Vertical Escalation:
Regular user → POST /update_role {"user_id": self, "role": "admin"} → 200 OK
Classification: VALIDATED (CWE-269)
See reference/ directory for implementation examples:
auth_patterns.py: Reusable authentication functions (session, JWT, API key, OAuth2, Basic)validate_idor.py: Complete authorization testing script with redaction and classificationREADME.md: Usage guidance and adaptation notesThese are reference implementations to adapt — not drop-in scripts. Each application requires tailored logic.