Skip to content

Our sixth CVE came back a 3.7

A sign-in finished by someone else

A callback built to redeem the sign-in code an advertising platform hands back to a merchant who just approved a connection instead ran on every single request to the site, matched its parameter by a loose guess rather than an exact name, and accepted whichever code the request happened to carry. Any anonymous visitor could make the site trade its own stored app credentials for a code of their choosing, replacing the merchant’s real connection with one the visitor supplied. It is public as CVE-2026-92965, scored 3.7 of 10 by WPScan, and credited to RIA Labs.

Patched

Read this part first

If your site runs a plugin that connects your store to an advertising platform by OAuth, read the advisory. It names the plugin and the affected versions. As of 18 September 2026 a fix had shipped in version 1.4.2 — update to that version or later and the path this post describes is closed.

The rest of this is about the pattern rather than the plugin. There is no exploit code below.

The feature that looked fine

The plugin’s job is connecting a store to TikTok’s advertising platform: an admin clicks connect, approves the request on TikTok’s own site, and TikTok redirects their browser back with a short-lived code the plugin trades for a lasting access token. An OAuth callback that accepts a code and exchanges it is not the bug — every integration that speaks OAuth has one, and it has to run for a browser that has not logged into WordPress yet, because the whole point is connecting an account, not proving one already exists.

What decides whether that callback is safe is what it checks before it trusts the code in front of it. Two separate checks are supposed to do that work here, and neither one showed up.

Two small mistakes, chained

First: the callback is wired to run on every single request to the site, not only when an admin is mid-connection. There is no capability check, no nonce, and — the check that actually belongs to OAuth — no state value tying the callback to a flow the site itself started. That parameter exists in the OAuth specification for exactly this reason: without it, a callback has no way to tell its own admin’s return trip from anyone else’s request carrying the right-looking parameter.

Second: the code is not read from a named parameter. It is found by searching the raw request URL for any segment that merely contains the text “auth_code” — so a URL does not need to match what TikTok would actually send back, only resemble it. And when that matched segment has no = in it at all, a quirk of the search function used still produces a value rather than nothing, so even a near-miss can trigger the exchange.

Chained: any URL, on any page of the site, carrying anything that merely looks like the parameter TikTok would send, submitted by anyone, causes the site to immediately take its own stored app credentials and redeem the visitor’s code against TikTok’s real API — overwriting whatever connection the merchant actually had with one built from a code the merchant never saw.

How we know

A description is not a finding. The engine built an isolated WordPress instance, installed the plugin’s official 1.4.1 release untouched, set up the preconditions a real connected store would have — its own app credentials, its own stored access token — and sent one anonymous request carrying nothing but a code of its own choosing. The stored token changed to that code’s exchanged value, a diff taken against the database rather than a response body, and a negative control — the identical request with the parameter removed — left the token untouched. Nobody else’s site was involved at any point, and no person confirmed it by hand — RIA Labs performs no manual step, by design.

What the lab could not show, because it never contacted the real platform, is whether a code obtained this way would be one TikTok’s own server will actually redeem for a specific victim’s app — that requires a real developer account and a live exchange, which is outside what this campaign will do. Our own submission argued the escalation anyway in an early draft, on an inference rather than a measurement, and withdrew that half of the claim before WPScan had to reject it, once the gap between what the lab proved and what the report argued was pointed out.

What survived is the part that needed no mock: the callback is reachable by anyone, checks nothing about who is asking, and matches its own parameter loosely enough that a near-miss still fires it. WPScan’s own reviewers independently reverified the source against that narrower claim, and the 3.7 is theirs, not ours — arrived at after they considered scoring the forced outbound request on its own, decided that was not something worth an advisory by itself, and settled on pricing the difficulty of obtaining a code the endpoint will actually redeem as high attack complexity. That is visible directly in the vector below: AC:H, the same complexity rating our own report chose for the part we declined to claim as measured.

Three questions for your own stack

None of this is WordPress-specific, and none of it is really about TikTok. If your product implements the receiving end of any OAuth flow — connecting to an ad platform, a payment provider, a CRM — these are worth answering on whatever you are built on.

  1. Does your callback check who is asking, or only that a code arrived? A callback that runs for every visitor and trusts whatever it receives has no way to tell its own admin’s return trip from a stranger’s request.
  2. Does a state value tie the callback to a flow your site actually started? This is the one check OAuth’s own spec built for exactly this problem. Skipping it does not just weaken the flow — it removes the one thing that would have stopped this.
  3. Is the parameter matched by its exact name, or by whether the request merely resembles one? A substring search widens what counts as a valid callback to anything that looks close enough, which is a larger attack surface than the one anyone reviewed.

None of that needs exotic tooling. It needs someone to ask what an OAuth callback actually verifies, not just whether it has one.

What it proves, and what it doesn’t

It proves the pipeline finds a bug in an OAuth flow, a shape none of the first five findings carried, and it proves the correction discipline behaves the way it is supposed to under real pushback: the part of our own claim that outran what the lab measured did not survive contact with a reviewer, and we took it back ourselves rather than defending it.

It does not prove we would find every bug in your application, and six findings are not a track record. It also does not establish that a code obtained the way this report describes would redeem against a real target’s TikTok app — that step was never measured, is not claimed, and is the reason the published score carries AC:H rather than a higher, unmeasured complexity.

The engine is still reading plugins. Nominate a target and the first scan costs nothing.

Published 18 September 2026. CVE-2026-92965 · CVSS 3.1 base score 3.7 · CWE-862 (Missing Authorization) · credited to RIA Labs, scored and published by WPScan. Status as of 18 September 2026. Corrections, or a plugin you maintain and want looked at: info@ria-labs.com.

See what a scan turns up

Nominate a target. The first scan costs nothing, and we’ll walk you through it.