I gave one OAuth client two valid callback URLs. The user authorized through callback A; I redeemed the code with callback B. XenForo 2.3.12 returned an access token.
The code had been issued for callback A. The token request accepted callback B anyway.
The missing comparison
XenForo saved the chosen URI on the OAuthRequest. During redemption, it checked the submitted redirect_uri against the client’s allowlist and skipped the URI stored with the code.
My test on build 2031270 was four requests:
- Register callback A and callback B on the same client.
- Authorize with callback A.
- Exchange the resulting code while sending callback B.
- Use the returned token at
/api/me.
The final request authenticated as the user from step two.
Exploitation requires a valid code plus access to another registered callback. Examples include an abandoned endpoint, a custom URI scheme claimed by another application, or a callback owned by a different component. Every submitted URI must already appear in the client’s registration.
The PoC repeats the exchange with two registered callbacks and verifies the token. XenForo 2.3.13 now checks the URI against both the client registration and the authorization request that produced the code.