turkmany.dev ← All writeups
Web · Authentication · Access Control

Authentication Bypass via Forced Browsing: When MFA Isn't Actually Enforced

Severity: High CWE-306 ~6 min read

Multi-factor authentication is one of the most effective controls a web application can deploy. But a control is only as strong as the point at which it's enforced. This writeup walks through a class of vulnerability where the MFA step looks mandatory in the browser, yet the server never actually requires it — allowing an attacker to walk straight past it. Everything below is presented on a generic, illustrative scenario for educational purposes.

How authentication is supposed to work

A typical login flow with a second factor looks like this:

  1. The user submits a valid username and password.
  2. The server verifies the credentials and issues a temporary, partially-authenticated session.
  3. The application asks for a one-time password (OTP).
  4. Only after the correct OTP is submitted does the server upgrade the session to fully authenticated and grant access to protected pages.

The critical word here is server. Each of these checks must be enforced on the backend. The browser only reflects the flow — it should never be the thing that decides whether a step was completed.

Where it breaks

The vulnerability appears when the application treats a valid username and password as sufficient to grant a fully privileged session, and relies on the front-end to "guide" the user to the OTP screen — rather than the server blocking access until the OTP is verified.

In other words, the OTP page is a signpost, not a gate. Nothing on the server stops a user from simply walking around it.

Root cause

The session is elevated to full access after the password step. The OTP prompt is enforced only in the UI, so any request that skips it still carries an authorized session.

Steps to reproduce

On a vulnerable application, the flow to demonstrate the bypass is straightforward:

  1. Authenticate once normally and complete the OTP so the account is in a known-good state.
  2. Log out, then begin a fresh login with valid credentials.
  3. When the application presents the OTP prompt, do not submit a code.
  4. Instead, directly request a protected, post-authentication route — for example, navigating straight to the dashboard path in a new tab:
# Instead of completing the OTP step, request the protected route directly
GET https://app.example.com/dashboard

# If the server never enforced the OTP, the page loads —
# the session was already fully privileged after the password.

If the protected page renders and serves authenticated content, the second factor has been bypassed. The application verified something (the password) but never enforced the step that was supposed to make the login trustworthy.

Why this happens

This pattern shows up for a few recurring reasons:

Impact

The impact is direct: the entire value of the second factor is nullified. An attacker who has obtained valid credentials — through phishing, credential stuffing, or a prior breach — can access the account without ever needing the victim's OTP, defeating the exact scenario MFA exists to protect against. Depending on the application, this can expose personal data, account functions, and any sensitive operations behind the login.

Remediation

The fix is to enforce the authentication state where it matters — on the server:

Key takeaway

Authentication is a state the server must own and re-check on every protected request. If a security step can be skipped by requesting the next URL directly, it was never really enforced — it was only displayed.

Closing thought

The most valuable findings often aren't exotic exploits — they're places where a control that everyone assumed was working simply wasn't enforced at the right layer. Testing authentication means questioning every step: not "does the app ask for this?" but "what happens if I don't give it?"

Written by Mahmoud Turkmany ← Back to writeups