Yat 2FA Bypass: When the Client Decides Whether the Second Factor Was Required
V-Spot identified a two-factor authentication bypass on the Yat platform. Modifying the login response to change requires_2fa from GoogleAuthenticator to null was sufficient to convince the client that no second factor was required, and the session tokens already contained in the same response completed the login. The specific finding is one flipped field. The class of problem is client-authoritative authorisation, a design pattern that has produced this same bug across the industry for at least a decade.
While assessing the Yat platform, V-Spot's research division identified a two-factor authentication bypass. The login endpoint responded to a successful password submission with a JSON body containing both the session tokens and a requires_2fa field indicating which second factor should be presented next. Modifying the response body in transit to set requires_2fa to null was sufficient to convince the client that no second factor was required. The session tokens included in the same response completed the login, and the account was accessible without the second factor ever being challenged.
The specific finding is one flipped field. The class of problem is the same client-authoritative authorisation pattern V-Spot has separately documented in the Epic Games parental controls PIN bypass, the same shape as the OAuth session-elevation confusion that has produced repeated CVEs across major SSO vendors, and the same failure mode that underlies most published web-application 2FA bypass research since 2015. This is V-Spot's writeup of the specific finding and the wider structural point.
The bypass, exactly
The vulnerable endpoint accepts an email and password and returns a JSON response. Two response shapes are relevant.
Original response for an account with 2FA enabled:
{
"access_token": "**************",
"refresh_token": "**************",
"requires_2fa": "GoogleAuthenticator",
"has_password": true
}Modified response after in-flight manipulation:
{
"access_token": "**************",
"refresh_token": "**************",
"requires_2fa": null,
"has_password": true
}The single-field modification is sufficient. The reproduction is short.
1. Navigate to the sign-in page on a browser with a proxy intercepting outbound traffic.
2. Submit the email and password for an account with Google Authenticator 2FA enabled.
3. Intercept the response and change the requires_2fa field from "GoogleAuthenticator" to null.
4. Forward the modified response.
5. The client uses the access_token and refresh_token already contained in the response to complete the login, treats requires_2fa: null as "no second factor required," and skips the 2FA prompt entirely.
The account is fully accessible without ever having supplied the second factor.
Why this shape of bug is not rare
The specific manifestation is easy to fix. The underlying pattern is not.
Client-authoritative authorisation is a design where the client, after receiving a response from the server, decides what the user is now authorised to do based on the content of that response. The server participates by producing the response, but the enforcement of the authorisation decision happens on the client. The pattern is common because it maps naturally to modern SPAs: the front end holds the state, renders the UI, and gates the sensitive flows.
The pattern is also, structurally, indefensible against a determined user. Every field in the response body is under the client's control by the time the client processes it. An attacker with access to their own browser has access to every value in every response. If the authorisation decision is based on a value in the response body, the attacker can modify the value before the decision is made.
The correct alternative is server-authoritative authorisation. In the correct design, the server maintains the authoritative session state, including whether the second factor has been completed. Every action that requires 2FA calls back to the server, and the server checks its own record of whether the requirement has been met. The client never gets to decide what "requires_2fa: null" means because the client never gets asked.
Concretely, the specific fix for Yat's flow is that the response should not contain the session tokens until the second factor has been verified server-side. The first response after password submission should contain, at most, a short-lived interim token that identifies "this login attempt is in progress, second factor pending" and nothing else that would permit any authenticated action. Only after the second factor is submitted and verified should the response contain the tokens that grant access.
Why 2FA in particular is prone to this shape
Two factors make 2FA implementations especially prone to client-authoritative authorisation.
The endpoint that starts a 2FA flow is often the same endpoint that completes a non-2FA login. For users with 2FA disabled, the login endpoint returns the tokens directly. For users with 2FA enabled, the same endpoint returns something that says "wait, do 2FA first." The temptation to make that "wait" a single field alongside the tokens in the same response is high. It saves a round trip. It simplifies the client. It also puts the tokens next to the field that gates whether they should be usable, which is the specific mistake that produces this bug.
2FA is often layered onto an existing single-factor auth flow. The product ships with password login. 2FA is added later. The 2FA implementation is grafted onto the existing response shape rather than restructured into a two-step flow. The grafted design leaves the tokens in the initial response and adds a flag to control whether the tokens should be used. The flag is client-controlled by the time the client sees it.
The client-side developer and the server-side developer often work in different rhythms. The client-side developer needs a way to know whether to render the 2FA UI. The server-side developer needs a way to communicate that to the client. The path of least resistance is a boolean or a string field. Neither developer explicitly evaluates that field as a security-relevant decision, because from each developer's perspective, the other party is enforcing the check.
What Yat did well and what the pattern reveals
To be fair to Yat, and to be honest about the finding, this class of bug is not unique to any one vendor. Comparable response-manipulation bypasses and 2FA-flag-trust bypasses have been documented publicly across the web application security literature for at least a decade, on products spanning consumer SaaS, enterprise identity, and cloud provider auth flows. The Yat implementation is one instance of a pattern that is embedded deeply in how modern SPA-plus-API authentication is designed, marketed, and shipped.
The wider claim V-Spot's research division stands behind is that this pattern will continue to produce identical bugs across the industry until the design shape changes. Any authentication flow that returns session tokens in a response that also contains a "you still need to complete another step" flag has this bug in latent form. Sometimes the flag is called requires_2fa. Sometimes it is mfa_required, session_pending, or challenge_required. The name is decorative. The structural bug is the same.
Seven concrete moves for teams shipping 2FA on top of existing auth
If your product ships 2FA on top of an existing authentication flow, the moves below are the ones V-Spot researchers would prioritise:
1. Never return session tokens in the same response as the "you need 2FA next" signal. The first response returns an interim identifier that cannot authenticate any real action. Only the response after successful 2FA returns real session tokens.
2. Track the 2FA state on the server, not in the client's copy of the response. The server records, for each in-progress login attempt, whether the second factor has been completed. Every subsequent authenticated request checks this state server-side.
3. Verify that intermediate tokens have scoped capabilities. If your architecture requires returning any token before 2FA completes, that token should not grant any capability beyond "submit the second factor." Test explicitly what happens if the intermediate token is used against other endpoints.
4. Apply rate limiting to the 2FA-required and 2FA-not-required response paths equally. Some bypasses exploit differential response timing or differential rate limiting. If the "no 2FA required" path has looser controls, an attacker can force flows down that path with modified inputs.
5. Audit every field in every authentication response for what would happen if the client modified it. If any single field's modification would produce an unauthorised state, the field is a bug. This audit is short, precise, and rarely gets done.
6. Never trust an HTTP response header, JSON field, or cookie value returned to the client to gate a subsequent authorisation decision. The client can modify all of it. Every gate must be enforced against server-authoritative state.
7. Include this class of test in your standard authentication-flow QA. Response manipulation testing should be a routine part of every login flow test, not a specialised penetration testing exercise reserved for pre-launch audits.
The V-Spot lens
The Yat bypass is a compact demonstration of a bug class that will keep appearing until the authentication flow's design shape changes. The specific fix is straightforward. The structural fix requires deciding, deliberately, that the client is not a security-relevant participant in the authentication flow. The client presents the UI. The client submits the inputs. The client receives feedback. The client does not decide whether the user is authorised to proceed, because the client cannot be trusted to make that decision reliably in the presence of an attacker who controls the client.
Most product engineering organisations agree with this framing when it is presented in the abstract. Most product engineering organisations then ship authentication flows that violate the framing in the specific, because the specific case always looks like a small optimisation rather than a design commitment. The Yat finding, the Epic Games parental controls finding, and the long history of comparable published findings across the industry are the accumulated record of what happens when the small optimisation compounds.
If your authentication flow includes any point where the client interprets a server response to make an authorisation decision, or you are auditing an existing flow for this class of bug, V-Spot's research division and offensive security team can help. This class of bug is fast to find when you are looking for it, and expensive to encounter when you are not.