SECURE_NODE // ATHENS_GR
← BACK TO RESEARCH Technique · Auth · Account Takeover

2FA Bypass via Password Reset: One Link, Full Admin Takeover

03 JUL 2026| ≈ 4 MIN READ| 2FAMFABypassAccountTakeoverBrokenAuth
SANITIZED ▸ Methodology only. No client name, real host, real data, or live finding. Reproduced against a lab environment with test accounts.

Two-factor authentication is a meaningful control, right up until there is a code path that bypasses it entirely. The most common bypass is not a cryptographic weakness or a brute-force attack. It is a logic gap in a secondary flow that the developers treated as a different feature and forgot to enforce 2FA on. Password reset is the classic one, and this engagement confirmed it on a 2FA-protected admin account in production.

SEVERITY
High
full admin account takeover
COMPLEXITY
High
requires email access
ROOT CAUSE
2FA not enforced post-reset
logic gap in reset flow

The gap in the logic

The application had a standard TOTP-based 2FA implementation. When a user with 2FA enabled tried to log in through the normal login page, the server correctly challenged them for the second factor after verifying the password. The 2FA check was in the login code path.

The password reset flow was a separate code path. It issued a time-limited token to the registered email address, and clicking the link in that email authenticated the user straight into the account, the assumption being that having the email proved identity well enough. There was no branch in the reset completion logic that checked whether the account had 2FA enabled and, if so, prompted for the second factor before granting the session.

The result: an attacker who can receive or intercept the password reset email for an account, whether through phishing, email compromise, a forwarding rule, or a shared mailbox, gains full access to that account regardless of whether 2FA is configured. The second factor is completely bypassed. For admin accounts, this is a full application compromise.

The test timeline

T+0:00 · SETUP

Enabled TOTP-based 2FA on a lab admin account. Verified that normal login correctly challenged for the second factor after password entry.

T+0:05 · TRIGGER RESET

Submitted a password reset request for the same account. The application sent a reset link to the registered email address.

T+0:07 · CLICK THE LINK

Followed the reset link from a fresh browser session. The link accepted the token and proceeded.

T+0:08 · BYPASS CONFIRMED

The application granted a fully authenticated admin session with no 2FA challenge. The account settings page loaded with full admin access: no TOTP prompt, no SMS, no secondary factor of any kind.

T+0:10 · VERIFICATION

Confirmed via the account settings API response that isTwoFactorAuthActivated: true on the account, yet the session was established without the factor being checked.

The request flow

First, TOTP-based 2FA is enabled and confirmed active on the admin account:

POST /admin/2fa-setup/ HTTP/2
Host: store.lab.example.test
Content-Type: multipart/form-data; boundary=----BoundaryLab
Cookie: PHPSESSID=<admin-session>

------BoundaryLab
Content-Disposition: form-data; name="action"

verifyTwoFactorAuth
------BoundaryLab
Content-Disposition: form-data; name="token"

<TOTP-code>
------BoundaryLab
Content-Disposition: form-data; name="secret"

<TOTP-secret>
------BoundaryLab
Content-Disposition: form-data; name="__csrf__"

csrf_lab_token
------BoundaryLab--

HTTP/2 200 OK
Content-Type: application/json
{"code":200,"payload":{"success":true}}
# 2FA now active; normal login correctly challenges for TOTP before granting a session

With 2FA confirmed active, the reset request is initiated from a fresh browser session:

POST /admin/reset-password/ HTTP/2
Host: store.lab.example.test
Content-Type: application/x-www-form-urlencoded

action=sendAccessHash&email=admin@store.lab.example.test&__csrf__=csrf_lab_token

Following the emailed link returns a redirect directly into the admin panel:

HTTP/2 302 Found
Location: https://store.lab.example.test/admin/account-settings/
Set-Cookie: PHPSESSID=<new-session>; path=/; secure; HttpOnly

That 302 is the problem. There is no intermediate step where the server checks the account's 2FA status and routes accordingly. The flow simply trusts the token and opens the session.

A subsequent request to the account settings endpoint confirms the authenticated state and, critically, confirms that isTwoFactorAuthActivated is true on the account. The server was aware 2FA was active; it simply never enforced it on this code path:

GET /admin/account-settings/ HTTP/2
Host: store.lab.example.test
Cookie: PHPSESSID=<new-session>

HTTP/2 200 OK
{"isTwoFactorAuthActivated": true, "isTwoFactorAuthModuleActive": true, ...}

Why this pattern is common

2FA implementations are often bolt-ons. The login flow gets updated to include the second-factor check; the password reset flow, the magic-link login, the SSO callback, and any other alternative authentication paths do not. Each of those paths is a potential bypass. If any one of them lands the user in an authenticated session without completing the second factor, the protection is broken, not just for that flow but for the account as a whole.

Fixing it

  • Enforce 2FA at the session-creation layer, not the login-form layer. Any code path that results in an authenticated session for a 2FA-enabled account must complete the second-factor challenge before issuing that session. This includes password reset, magic links, SSO callbacks, and any API-based authentication.
  • Check 2FA status centrally. A helper function that checks whether a given account requires a second factor, called at every point where a new authenticated session is established, is harder to forget than per-flow 2FA enforcement scattered across the codebase.
  • Treat password reset as a sensitive action requiring re-authentication, not as a bypass token. A reset link proves email access. It does not prove that the person clicking it is the account owner, particularly when accounts are protected by additional factors for exactly that reason.
  • Audit all alternative authentication paths. Login is one entry point. List every other flow that produces an authenticated session and verify that 2FA is enforced on each of them.

The takeaway

Two-factor authentication is only as strong as the weakest code path to an authenticated session. A login page that correctly challenges for a second factor and a password reset endpoint that does not is not a 2FA-protected application. It is an application with a false sense of security. Security controls need to be enforced everywhere they apply, not just in the obvious place.