Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Testing OAuth Authorization Server Weaknesses
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-15 | ✗→✓ | ▲ Improved | 204% | 0% |
| case-21 | ✗→✓ | ▲ Improved | 485% | 0% |
| case-04 | ✓→✓ | = Same ✓ | 161% | 0% |
| case-05 | ✓→✓ | = Same ✓ | 233% | 0% |
| case-06 | ✓→✓ | = Same ✓ | 188% | 0% |
WSTG-AUTHZ-05.1
Testing OAuth Authorization Server Weaknesses
The OAuth Authorization Server is responsible for authenticating users, obtaining consent, and issuing access tokens. Vulnerabilities in the authorization server can compromise the entire OAuth ecosystem, leading to unauthorized access to protected resources across all client applications. This test focuses on identifying weaknesses specific to the authorization server implementation.
| Vulnerability | Description | | ----------------------------- | ------------------------------ | | Weak token generation | Predictable tokens | | Insufficient token validation | Missing signature verification | | Client impersonation | Weak client authentication | | Token leakage | Logging, error messages | | Consent bypass | Auto-approval issues |
bash# OAuth Authorization Server Metadata curl -s "https://auth.target.com/.well-known/oauth-authorization-server" | jq '.' # OpenID Connect Discovery curl -s "https://auth.target.com/.well-known/openid-configuration" | jq '.' # Check for exposed information # - Supported grant types # - Token endpoint auth methods # - Scopes supported # - Response types supported # - PKCE support # Look for insecure configurations: # - "response_types_supported": ["token"] (implicit flow) # - "token_endpoint_auth_methods_supported": ["none"] # - Missing "code_challenge_methods_supported"
bash#!/bin/bash # Test authorization endpoint weaknesses AUTH_URL="https://auth.target.com/oauth/authorize" CLIENT_ID="test_client" # Test response_type variations response_types=("code" "token" "id_token" "code token" "code id_token" "token id_token" "code token id_token") for rt in "${response_types[@]}"; do response=$(curl -s -I "$AUTH_URL?client_id=$CLIENT_ID&response_type=$rt&redirect_uri=https://client.com/callback&scope=openid" 2>/dev/null | head -20) echo "response_type=$rt" echo "$response" | grep -iE "location|error" echo "---" done # Test scope handling scopes=("openid" "profile" "email" "admin" "write" "delete" "all" "*") for scope in "${scopes[@]}"; do response=$(curl -s "$AUTH_URL?client_id=$CLIENT_ID&response_type=code&redirect_uri=https://client.com/callback&scope=$scope" 2>/dev/null) if echo "$response" | grep -qi "invalid_scope"; then echo "Scope '$scope': Rejected" else echo "Scope '$scope': Potentially accepted" fi done
bash#!/bin/bash # Test token endpoint weaknesses TOKEN_URL="https://auth.target.com/oauth/token" # Test without client authentication curl -s -X POST "$TOKEN_URL" \ -d "grant_type=authorization_code&code=AUTH_CODE&redirect_uri=https://client.com/callback" # Test with various client auth methods # client_secret_post curl -s -X POST "$TOKEN_URL" \ -d "grant_type=authorization_code&code=AUTH_CODE&redirect_uri=https://client.com/callback&client_id=CLIENT&client_secret=SECRET" # client_secret_basic curl -s -X POST "$TOKEN_URL" \ -u "CLIENT:SECRET" \ -d "grant_type=authorization_code&code=AUTH_CODE&redirect_uri=https://client.com/callback" # Test grant types grant_types=("authorization_code" "client_credentials" "password" "refresh_token" "urn:ietf:params:oauth:grant-type:jwt-bearer") for gt in "${grant_types[@]}"; do response=$(curl -s -X POST "$TOKEN_URL" \ -d "grant_type=$gt&client_id=CLIENT&client_secret=SECRET") echo "Grant type: $gt" echo "$response" | head -c 200 echo -e "\n---" done
python#!/usr/bin/env python3 import requests import time import hashlib from collections import Counter class TokenAnalyzer: def __init__(self, token_url, client_id, client_secret): self.token_url = token_url self.client_id = client_id self.client_secret = client_secret self.tokens = [] def collect_tokens(self, count=10): """Collect multiple tokens for analysis""" print(f"[*] Collecting {count} tokens...") for i in range(count): try: response = requests.post( self.token_url, data={ "grant_type": "client_credentials", "client_id": self.client_id, "client_secret": self.client_secret, "scope": "openid" } ) if response.status_code == 200: token = response.json().get("access_token") if token: self.tokens.append({ "token": token, "timestamp": time.time(), "length": len(token) }) time.sleep(0.5) # Avoid rate limiting except Exception as e: print(f"[ERROR] {e}") print(f"[*] Collected {len(self.tokens)} tokens") return self.tokens def analyze_entropy(self): """Analyze token entropy""" print("\n[*] Analyzing token entropy...") for token_data in self.tokens: token = token_data["token"] # Character frequency freq = Counter(token) unique_chars = len(freq) total_chars = len(token) # Simple entropy approximation entropy = sum((count/total_chars) * (-1 * (count/total_chars)) for count in freq.values()) * -1 print(f"Token length: {total_chars}, Unique chars: {unique_chars}") def check_predictability(self): """Check for predictable patterns""" print("\n[*] Checking for predictable patterns...") if len(self.tokens) < 2: print("[!] Need more tokens for pattern analysis") return # Check if tokens are sequential token_hashes = [hashlib.md5(t["token"].encode()).hexdigest() for t in self.tokens] # Check for common prefixes common_prefix = "" tokens_list = [t["token"] for t in self.tokens] for i, char in enumerate(tokens_list[0]): if all(t[i] == char for t in tokens_list if len(t) > i): common_prefix += char else: break if len(common_prefix) > 10: print(f"[WARN] Common prefix found: {common_prefix}") # Check for timestamp-based patterns for token_data in self.tokens: token = token_data["token"] ts = str(int(token_data["timestamp"])) if ts[:6] in token: print(f"[VULN] Timestamp may be embedded in token") def analyze_jwt_tokens(self): """Analyze if tokens are JWTs""" print("\n[*] Analyzing JWT tokens...") import base64 import json for token_data in self.tokens: token = token_data["token"] parts = token.split(".") if len(parts) == 3: try: header = json.loads( base64.urlsafe_b64decode(parts[0] + "==") ) payload = json.loads( base64.urlsafe_b64decode(parts[1] + "==") ) print(f"\nJWT detected:") print(f" Algorithm: {header.get('alg')}") print(f" Type: {header.get('typ')}") # Check for weak algorithms if header.get('alg') in ['none', 'HS256']: print(f" [WARN] Potentially weak algorithm: {header.get('alg')}") # Check for sensitive data sensitive_keys = ['password', 'secret', 'ssn', 'credit_card'] for key in payload: if any(s in key.lower() for s in sensitive_keys): print(f" [VULN] Sensitive data in payload: {key}") except: pass # Usage analyzer = TokenAnalyzer( "https://auth.target.com/oauth/token", "client_id", "client_secret" ) analyzer.collect_tokens(10) analyzer.analyze_entropy() analyzer.check_predictability() analyzer.analyze_jwt_tokens()
bash#!/bin/bash # Test client authentication security TOKEN_URL="https://auth.target.com/oauth/token" CLIENT_ID="known_client" # Test common/default client secrets secrets=("secret" "password" "123456" "client_secret" "$CLIENT_ID" "") for secret in "${secrets[@]}"; do response=$(curl -s -X POST "$TOKEN_URL" \ -d "grant_type=client_credentials&client_id=$CLIENT_ID&client_secret=$secret") if echo "$response" | grep -q "access_token"; then echo "[VULN] Weak client secret found: '$secret'" fi done # Test client_id enumeration for i in {1..100}; do client="client_$i" response=$(curl -s -X POST "$TOKEN_URL" \ -d "grant_type=client_credentials&client_id=$client&client_secret=test") error=$(echo "$response" | jq -r '.error_description // .error') if [ "$error" != "invalid_client" ]; then echo "Client '$client': $error" fi done
bash# Token introspection endpoint INTROSPECT_URL="https://auth.target.com/oauth/introspect" # Test introspection without auth curl -s -X POST "$INTROSPECT_URL" \ -d "token=SOME_TOKEN" # Test with client credentials curl -s -X POST "$INTROSPECT_URL" \ -u "CLIENT:SECRET" \ -d "token=SOME_TOKEN" # Test token revocation REVOKE_URL="https://auth.target.com/oauth/revoke" curl -s -X POST "$REVOKE_URL" \ -u "CLIENT:SECRET" \ -d "token=SOME_TOKEN&token_type_hint=access_token" # Verify token is actually revoked curl -s -X POST "$INTROSPECT_URL" \ -u "CLIENT:SECRET" \ -d "token=SOME_TOKEN"
bash#!/bin/bash # Test if consent can be bypassed AUTH_URL="https://auth.target.com/oauth/authorize" CLIENT_ID="test_client" # Test with prompt=none (should fail if no prior consent) curl -s "$AUTH_URL?client_id=$CLIENT_ID&response_type=code&redirect_uri=https://client.com/callback&scope=openid&prompt=none" # Test with approval_prompt=auto curl -s "$AUTH_URL?client_id=$CLIENT_ID&response_type=code&redirect_uri=https://client.com/callback&scope=openid&approval_prompt=auto" # Test with auto-approved client # Some clients may be pre-approved (first-party apps) # Check for scope creep # If initially granted "read", can we silently add "write"? curl -s "$AUTH_URL?client_id=$CLIENT_ID&response_type=code&redirect_uri=https://client.com/callback&scope=openid+profile+email+admin&prompt=none"
bash#!/bin/bash # Test ROPC (Resource Owner Password Credentials) grant TOKEN_URL="https://auth.target.com/oauth/token" # Test if ROPC is enabled (should be disabled for most apps) curl -s -X POST "$TOKEN_URL" \ -d "grant_type=password&username=test&password=test&client_id=CLIENT&client_secret=SECRET" # If enabled, test for brute force protection for i in {1..20}; do response=$(curl -s -X POST "$TOKEN_URL" \ -d "grant_type=password&username=admin&password=password$i&client_id=CLIENT&client_secret=SECRET") status=$(echo "$response" | jq -r '.error // "success"') echo "Attempt $i: $status" if [ "$status" == "too_many_requests" ]; then echo "Rate limited after $i attempts" break fi done
| Tool | Description | Usage | | ---------------------- | ---------------- | --------------------- | | Burp Suite | Traffic analysis | Intercept OAuth flows | | Postman | API testing | Test endpoints | | oauth2-test-server | Test server | Development testing |
| Tool | Description | | --------------- | ------------------ | | jwt.io | JWT decoder | | jwt_tool | JWT security | | jwt-cracker | Weak secret finder |
pythonimport secrets import hashlib import time import jwt class SecureTokenGenerator: def __init__(self, secret_key, issuer): self.secret_key = secret_key self.issuer = issuer def generate_opaque_token(self, length=32): """Generate cryptographically secure opaque token""" return secrets.token_urlsafe(length) def generate_jwt_token(self, user_id, client_id, scopes, expiry=3600): """Generate secure JWT token""" now = int(time.time()) payload = { "iss": self.issuer, "sub": str(user_id), "aud": client_id, "exp": now + expiry, "iat": now, "jti": secrets.token_hex(16), # Unique token ID "scope": " ".join(scopes), } return jwt.encode( payload, self.secret_key, algorithm="RS256" # Use asymmetric algorithm ) def generate_authorization_code(self): """Generate secure authorization code""" return secrets.token_urlsafe(32)
pythonimport bcrypt import secrets from enum import Enum class ClientAuthMethod(Enum): NONE = "none" SECRET_POST = "client_secret_post" SECRET_BASIC = "client_secret_basic" PRIVATE_KEY_JWT = "private_key_jwt" TLS_CLIENT_AUTH = "tls_client_auth" class ClientAuthenticator: def authenticate(self, client_id, request): """Authenticate OAuth client""" client = Client.query.get(client_id) if not client: return None, "invalid_client" auth_method = client.token_endpoint_auth_method if auth_method == ClientAuthMethod.SECRET_BASIC: return self._auth_basic(client, request) elif auth_method == ClientAuthMethod.SECRET_POST: return self._auth_post(client, request) elif auth_method == ClientAuthMethod.PRIVATE_KEY_JWT: return self._auth_jwt(client, request) else: return None, "unsupported_auth_method" def _auth_basic(self, client, request): """HTTP Basic authentication""" auth = request.authorization if not auth: return None, "missing_credentials" if not secrets.compare_digest(auth.username, client.client_id): return None, "invalid_client" if not bcrypt.checkpw(auth.password.encode(), client.secret_hash): return None, "invalid_client" return client, None def _auth_jwt(self, client, request): """JWT client assertion authentication""" assertion = request.form.get("client_assertion") assertion_type = request.form.get("client_assertion_type") if assertion_type != "urn:ietf:params:oauth:client-assertion-type:jwt-bearer": return None, "invalid_assertion_type" try: # Verify JWT with client's public key payload = jwt.decode( assertion, client.public_key, algorithms=["RS256"], audience=self.token_endpoint_url ) if payload.get("sub") != client.client_id: return None, "invalid_client" return client, None except jwt.InvalidTokenError: return None, "invalid_assertion"
pythonclass ConsentManager: def check_consent(self, user_id, client_id, requested_scopes): """Check if user has consented to requested scopes""" existing_consent = Consent.query.filter_by( user_id=user_id, client_id=client_id ).first() if not existing_consent: return False, set(requested_scopes) # Check if all requested scopes are already consented consented_scopes = set(existing_consent.scopes.split()) requested_set = set(requested_scopes) missing_scopes = requested_set - consented_scopes if missing_scopes: return False, missing_scopes return True, set() def record_consent(self, user_id, client_id, scopes): """Record user consent""" consent = Consent.query.filter_by( user_id=user_id, client_id=client_id ).first() if consent: # Add new scopes to existing consent existing = set(consent.scopes.split()) existing.update(scopes) consent.scopes = " ".join(existing) else: consent = Consent( user_id=user_id, client_id=client_id, scopes=" ".join(scopes) ) db.session.add(consent) db.session.commit()
| Finding | CVSS | Severity | | ----------------------------- | ---- | -------- | | Weak token generation | 9.1 | Critical | | Missing client authentication | 8.8 | High | | Consent bypass | 7.5 | High | | Token leakage in logs | 6.5 | Medium | | ROPC enabled | 6.5 | Medium |
| CWE ID | Title | Description | | ----------- | ------------------------ | ------------------ | | CWE-330 | Insufficient Randomness | Weak tokens | | CWE-287 | Improper Authentication | Client auth issues | | CWE-862 | Missing Authorization | Consent bypass | | CWE-532 | Information in Log Files | Token leakage |
[ ] Discovery endpoints analyzed
[ ] Authorization endpoint tested
[ ] Token endpoint authenticated
[ ] Token generation strength analyzed
[ ] Client authentication tested
[ ] Token introspection tested
[ ] Token revocation tested
[ ] Consent handling verified
[ ] ROPC grant checked
[ ] JWT tokens analyzed
[ ] Findings documented
[ ] Remediation recommendations providedOther measured skills in the registry, with their headline benchmark lift.