Web Security

What Are Authentication Vulnerabilities? Login Bypasses and Credential Attacks Explained

A complete technical guide to authentication vulnerabilities: how login mechanisms get bypassed, how credentials are stolen, and how to build resilient authentication.

Intermediate14 min·Nyxeara Security Research·2026-09-16·CWE-287
authenticationweb-securitysession-securitypassword
Prerequisites
what-is-httphow-cookies-work

Short answer

Authentication vulnerabilities are flaws in how an application verifies who a user is — enabling attackers to impersonate legitimate users, bypass login entirely, or steal credentials. These range from weak password policies and brute-forceable login endpoints to broken session tokens, JWT alg confusion, and flawed password reset flows that hand an attacker a logged-in session.

The idea in one minute

Imagine an apartment building with a front-door keypad. Every resident has a unique code. Now suppose the keypad accepts any four-digit number and just turns green — or the building manager prints every tenant's code on a sticky note posted in the lobby. Worse, imagine the "forgot my code" button that lets anyone who knows a resident's name request a new code, and the new code is simply "1234". The front door looks secure, but the system underneath is theater.

That's what broken authentication looks like in software. The login form is the front door. Weak password policies are the sticky note in the lobby. A rate-limit that kicks in after ten thousand attempts per second is the keypad that never locks out. A password reset that emails the old password in plaintext is the "forgot my code" button that hands out the same code to everyone. The application feels secure because it has a login page — but the login page itself is the weakest link.

How authentication vulnerabilities actually work

Authentication is the process of verifying three categories of evidence, called factors:

| Factor | What it is | Examples | |---|---|---| | Something you know | Knowledge | Password, PIN, security question answer | | Something you have | Possession | Phone (SMS/authenticator app), hardware token, certificate | | Something you are | Inherence | Fingerprint, face scan, behavioral typing pattern |

A system is multi-factor when it requires evidence from at least two categories. The vulnerability classes below target specific weaknesses in how each factor is implemented.

Brute force and credential stuffing. A brute-force attack enumerates all possible passwords for a known username. Credential stuffing takes username-password pairs leaked from other breaches and tries them on the target application. Both rely on the absence of rate limiting, account lockout, or proof-of-work challenges. Credential stuffing is especially effective because 65% of users reuse passwords across sites — a breach at one service becomes a master key at another.

JWT (JSON Web Token) attacks. JWTs are self-contained tokens signed by the server. Common implementation flaws include:

  • alg: none: the server accepts unsigned tokens. Setting "alg": "none" in the JWT header lets an attacker forge arbitrary tokens.
  • RS256 to HS256 confusion (key confusion): if the server uses an RSA public key to verify tokens, and an attacker changes the algorithm from RS256 (asymmetric) to HS256 (symmetric HMAC), the server may use the hardcoded public key as the HMAC secret — which the attacker knows because it's public.
  • Weak or leaked signing keys: tokens signed with "secret" as the HMAC secret can be brute-forced in seconds.
  • Missing expiration or nbf validation: tokens that never expire can be replayed indefinitely.

MFA bypass. Multi-factor authentication is not unbreakable:

  • SIMS swapping: an attacker convinces the mobile carrier to transfer the victim's phone number to a SIM the attacker controls. All SMS-based codes arrive on the attacker's device.
  • Push fatigue (MFA bombing): the attacker already has the password and triggers repeated MFA push notifications. The victim, annoyed, eventually taps "approve" — and the attacker logs in.
  • OAuth token reuse: once an OAuth session token is obtained, the MFA step is never re-challenged for subsequent API calls.
  • Backup code bypass: recovery codes, designed for when the authenticator device is lost, are often stored in plaintext in the user's account settings — an attacker who gains read access to the account can generate new backup codes and disable MFA.

Password reset flaws. The password reset flow is one of the most attacked endpoints because it is designed for users who cannot authenticate:

  • Predictable reset tokens: tokens generated from sequential IDs, timestamps, or md5(email) are guessable.
  • Token leaking in URLs: reset links sent via email that include the token in the URL are visible to email intermediaries and browser history.
  • Host header injection for token theft: attackers manipulate the Host header in the reset request, causing the server to generate a reset link pointing to the attacker's domain. The victim clicks the link, the token goes to the attacker.
  • Direct role manipulation: the reset endpoint accepts a role or is_admin parameter in the request body, allowing an attacker to reset a regular user's password and set themselves as admin.

The request flow

A typical credential-stuffing attack:

Attacker ──obtains leaked passwords──▶ Credential dump (breach)
          │
          ▼
    Identifies target application with no rate limiting
          │
          ▼
    Automated script ──POST /login──▶ Server: username=alice&password=Spring2021!
          │                                   │
          │                              Server checks hash
          │                                   │
          │                              Match? → 200 + session cookie
          │                                   │
          ├── Repeat for all leaked pairs ────┘
          │
          ▼
    Attacker now has a valid session for alice

As a sequence for JWT alg confusion:

sequenceDiagram
    participant Attacker
    participant Server
    participant Victim

    Note over Server: Has RS256 public key (public.pem)
    Attacker->>Server: GET /api/profile (no token)
    Server-->>Attacker: 401 + public key (leaked in error / config)
    Attacker->>Attacker: Creates JWT with alg:HS256, signs with public.pem as secret
    Attacker->>Server: GET /api/admin (token: forged JWT)
    Server->>Server: Verifies with alg:HS256 using public.pem
    Server-->>Attacker: 200 — admin data returned

A minimal example

A vulnerable login endpoint with no rate limiting:

from flask import Flask, request, jsonify
import hashlib

app = Flask(__name__)

USERS = {
    "alice": hashlib.sha256(b"password123").hexdigest(),
}

@app.route("/login", methods=["POST"])
def login():
    data = request.json
    username = data.get("username")
    password = data.get("password")

    # No rate limiting — attacker can send 10,000 req/s
    stored = USERS.get(username)
    if stored and hashlib.sha256(password.encode()).hexdigest() == stored:
        return jsonify({"token": "weak-jwt-" + username}), 200
    return jsonify({"error": "invalid credentials"}), 401

A JWT verification that accepts alg: none:

import jwt

def verify_token(token: str) -> dict:
    # No algorithm restriction — accepts "none"
    return jwt.decode(token, options={"verify_signature": False})

A resilient implementation:

import jwt
import re
from flask_limiter import Limiter
from datetime import datetime, timedelta

limiter = Limiter(app, key_func=lambda: request.remote_addr)

JWT_SECRET = "a-256-bit-secret-from-environment-variable"
JWT_ALGORITHM = "HS256"
ALLOWED_ALGORITHMS = {"HS256"}

# Rate-limited and algorithm-restricted
@app.route("/login", methods=["POST"])
@limiter.limit("5 per minute")
def login():
    data = request.json
    username = data.get("username", "")
    password = data.get("password", "")

    # Validate input shape
    if not re.match(r"^[a-zA-Z0-9_]{3,32}$", username):
        return jsonify({"error": "invalid username"}), 400

    user = authenticate(username, password)
    if not user:
        return jsonify({"error": "invalid credentials"}), 401

    token = jwt.encode(
        {
            "sub": user["id"],
            "iat": datetime.utcnow(),
            "exp": datetime.utcnow() + timedelta(minutes=15),
        },
        JWT_SECRET,
        algorithm=JWT_ALGORITHM,
    )
    return jsonify({"token": token}), 200

@app.route("/api/verify")
def verify():
    token = request.headers.get("Authorization", "").removeprefix("Bearer ")
    try:
        payload = jwt.decode(
            token,
            JWT_SECRET,
            algorithms=ALLOWED_ALGORITHMS,  # Rejects "none" algorithm
        )
        return jsonify(payload), 200
    except jwt.InvalidAlgorithmError:
        return jsonify({"error": "algorithm not allowed"}), 401
    except jwt.ExpiredSignatureError:
        return jsonify({"error": "token expired"}), 401

The critical differences: rate limiting with a strict per-IP cap, explicit algorithm allowlisting (which rejects alg: none and any algorithm outside HS256), and short token expiration with iat and exp claims enforced.

Why the vulnerability exists

  • Authentication is written early, hardened later. Login is often the first feature implemented and the last to be security-reviewed. Rate limiting, account lockout, and audit logging are afterthoughts.
  • Password policies are visible, but enforcement is invisible. A frontend that says "password must be 8 characters" but accepts 20,000 login attempts per second diverts attention from the real gap — rate limits are not visible in the UI.
  • Session tokens live in cookies, and cookies are hard to get right. Developers choose HttpOnly, Secure, and SameSite defaults without understanding the tradeoffs. A missing HttpOnly flag exposes the token to XSS. A missing Secure flag exposes it over HTTP. A SameSite=None without Secure is both exposed and exfiltrable.
  • Password reset flows are designed for user convenience, not attacker resistance. Short tokens, long validity windows, email-based identity verification (email is often compromised itself), and no rate limiting on the reset endpoint all lower the bar for account takeover.
  • JWTs feel like a solved problem, but the libraries have dangerous defaults. The standard jwt.decode() in many languages defaults to accepting any algorithm the token header specifies, including none.
  • MFA is treated as a binary — "we have it" — rather than a layered control. SMS-based MFA, backup codes, and support-desk bypass paths are often weaker than the primary factor they're supposed to protect.

What attackers look for

  • Login endpoints that return different response times or messages for "user exists" vs. "user doesn't exist" (user enumeration). A 2ms difference tells the attacker a username is valid.
  • Missing or weak rate limiting on login, password reset, and MFA challenge endpoints. Testing with 100 rapid requests and observing no 429 Too Many Requests or account lockout confirms the gap.
  • JWT inspection via jwt.io: attackers paste the token into a debugger and check the alg header, whether exp is set, and whether the signature verifies with an empty key or the string "secret".
  • Password reset endpoints that prefill the email from the URL, accept a manipulated Host header, or return the reset token in the response body.
  • OAuth "Log in with Google/Facebook/GitHub" flows where the callback accepts any email address in the JWT payload without verifying the token came from the correct provider.
  • Session fixation: endpoints that accept a session ID from the URL and never regenerate it after login, letting the attacker pre-set a known session ID and wait for the victim to authenticate with it.
  • Cookie attributes: inspecting Set-Cookie headers for missing HttpOnly, Secure, or SameSite.

Detection

  • Manual / code review: search for password hashing calls (bcrypt, scrypt, argon2, hashlib.sha256), JWT decode calls, rate-limiting decorators, and password reset token generation. Trace the algorithm parameter in JWT calls — if it's user-controllable or not explicitly restricted, it's a finding. Verify that password hashes use a slow, salted algorithm (argon2id preferred) and not a fast hash like SHA-256 or MD5.
  • Automated / DAST: submit credential-stuffing payloads (top-1000 breached passwords) against a known valid username. If more than a few succeed before a block, rate limiting is missing. Submit a JWT with alg: none and a modified payload; a 200 response confirms the vulnerability. Submit a JWT with alg: HS256 and an empty signature (eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.); if accepted, the server does not verify signatures.
  • Password reset: request a reset, capture the token, inspect it for patterns (timestamp, sequential integer, MD5 hash). Replay the same token multiple times — if it works more than once, the token is single-use but not invalidated on use (or not single-use at all).
  • MFA testing: obtain a valid password and then test whether the MFA challenge can be bypassed by omitting the MFA field, sending an empty MFA field, or using an old session token acquired before MFA was enabled.

Verification: real vulnerability or false positive?

A finding is confirmed when:

  • A login request with an incorrect password returns a valid session token — the authentication logic has a bypass path (e.g., treating empty password as "skip auth").
  • A JWT with alg: none and an arbitrary payload is accepted by the server and returns protected data — the library defaults are in use without algorithm restriction.
  • A password reset token is successfully guessed (e.g., sequential 1000, 1001, 1002) and used to change another user's password — the token space is too small or predictable.
  • An MFA-protected account is accessible by removing the mfa_code parameter from the login request entirely — the server only checks MFA when the field is present.
  • A rate-limit bypass is confirmed: 50 rapid login requests produce no 429 responses and at least one succeeds with a valid credential pair from a breach dump.

A rate limit that kicks in at 10,000 requests per minute is still a finding — the threshold must be low enough to make brute force impractical within the token validity window.

Real-world impact

  • Account takeover (ATO) is the direct outcome. An attacker who compromises one user account can access that user's data, perform actions as that user, and pivot to other systems if the user reuses the password. In a 2023 industry report, ATO attacks increased 300% year-over-year, driven primarily by credential stuffing.
  • Privilege escalation occurs when the compromised account has administrative access, or when the authentication bypass targets an admin account directly. In the 2021 SolarWinds attack, weak password policies on a single VPN gateway led to the initial compromise of a managed service provider, cascading into a supply-chain breach affecting 18,000 customers.
  • Credential stuffing feeds credential stuffing. Each successful account takeover reveals new possible password patterns (the user's password on site A is often similar to their password on site B), which the attacker feeds back into the attack loop.
  • MFA bypass at scale was publicly demonstrated in the 2022 Uber breach: an attacker obtained an employee's password via a credential-stuffing tool, then sent repeated MFA push notifications until the employee accepted — a technique known as MFA fatigue or push bombing. The attacker gained access to the company's internal VPN, Slack, and AWS environment.
  • JWT key confusion was notably exploited against several major platforms in 2022–2023. Researchers demonstrated that applications using public JWK endpoints for verification were susceptible to RS256→HS256 confusion attacks — recovering the public key from the JWK endpoint and using it to sign forged tokens.
  • Business impact: account recovery costs, chargeback fraud (in financial applications), reputational damage from data breach disclosures, and regulatory fines under GDPR, CCPA, and other frameworks that require prompt breach notification.

Prevention

  • Rate limit aggressively on authentication endpoints. Apply per-IP, per-username, and global rate limits on login, password reset, and MFA challenge. A common pattern is 5 attempts per IP per minute with progressive lockout — each failure doubles the wait time. Never allow more than 1000 requests to /login from a single IP without blocking.
  • Use a slow, salted password hash. Argon2id is the current standard. bcrypt with a cost factor of 12+ is acceptable. scrypt is also fine. SHA-256, MD5, and unsalted bcrypt are not acceptable — they are fast enough to brute-force billions of candidates per second on consumer GPUs.
  • Restrict JWT algorithms explicitly. Always pass an allowlist to jwt.decode(). Reject the none algorithm by never setting verify_signature=False in production. Use asymmetric algorithms (RS256, ES256) and never expose the private key — use environment variables or a secrets manager, not a file committed to the repository.
  • Enforce short token expiration. Access tokens should expire in 15–60 minutes. Refresh tokens should expire in 7–30 days and be revocable server-side. Never issue tokens that live longer than a year.
  • Regenerate session identifiers on login. This prevents session fixation. Every successful authentication should produce a new session ID that no longer accepts the pre-login session ID.
  • Implement account lockout with clear communication. Lock the account after 5–10 failed attempts for 15–30 minutes. The lockout must apply to the account, not just the IP — otherwise the attacker rotates IPs and continues. Notify the user by email when a lockout occurs.
  • Secure password reset flows. Use cryptographically random tokens (at least 128 bits from crypto.randomBytes() or equivalent). Set a short expiration (15 minutes). Invalidate the token after a single use. Never include the token in email URLs as a query parameter — use a POST-based form submission with the token in the request body. Verify that the Host header matches the application's canonical domain before generating the reset link.
  • Hardening MFA. Use TOTP or WebAuthn hardware keys instead of SMS. Rate-limit MFA challenge attempts. Implement MFA step-up for sensitive actions (password change, email change, API token creation) even when the user is already authenticated with a session token. Watch for MFA fatigue by limiting push notifications to one per 60 seconds per user.

Related vulnerabilities

  • CSRF — authentication bypass is frequently combined with CSRF: an attacker forces the victim's browser to submit a credential change request while the victim is authenticated, changing the password to one the attacker knows.
  • XSS — a single XSS vulnerability can steal session cookies, read CSRF tokens, and exfiltrate password-reset confirmation links. XSS is authentication bypass for any application that relies on cookie-based sessions.
  • Session security — weak session generation (predictable session IDs, missing HttpOnly/Secure flags) and improper session invalidation on logout are authentication vulnerabilities that fall into the session management category.
  • Open redirect — an open redirect on the login page allows an attacker to steal the authorization code in OAuth flows, or redirect a user who just logged in to a phishing page that captures the session cookie in the URL.

Testing methodology (do this safely)

  • Test on your own applications or applications you have explicit authorization to test. Credential stuffing and brute-force testing against third-party applications without authorization can be illegal and is never in scope for unauthorized testing.
  • For rate-limit testing, use your own test accounts. Create a dedicated account and automate login attempts against it. Do not test against production user accounts that you do not control.
  • For JWT testing, generate tokens with modified payloads and algorithm headers. Verify that the server rejects tokens with alg: none, modified sub, and expired exp. Test both the Authorization header and cookie-based token delivery.
  • For password reset testing, request a reset for an account you control, capture the full HTTP exchange, and inspect the reset token for predictability. Test the endpoint with manipulated Host headers and observe whether the generated reset link uses the manipulated value.
  • Document every endpoint tested, the request payload, the response status and body, and whether the behavior deviated from the expected security control. A matrix of "endpoint × attack type × result" is the most useful format for remediation.

Further reading

Nyxeara perspective

Nyxeara's scanner tests authentication endpoints through multiple vectors in a single pass: it probes rate limits by submitting bursts of requests and measuring response timing, attempts JWT algorithm confusion with crafted tokens, and triggers password reset flows to evaluate token entropy and Host header handling. The most effective approach combines credential-stuffing simulation (using breached-password datasets against test accounts) with behavioral analysis of the server's lockout and rate-limiting responses — because the absence of a block is itself the finding, not a specific error message.

Published 2026-09-16 · Updated 2026-09-16