If you run WPML with a different domain per language, turn off cross-domain sign-in today. There is no patch yet. CVE-2026-76877, published November 9, lets an anonymous attacker log in as a user, including an administrator, during the moment that user is logging out. It only affects sites that use WPML’s “different domain per language” setting with the option that carries logins across those domains. Directory and parameter setups aren’t affected. WPML was told on August 19, and as of today Wordfence lists no fixed version. No attacks have been reported, but the details are public now.
At a glance
| CVE | CVE-2026-76877 |
|---|---|
| Plugin | WPML Multilingual CMS, a commercial plugin (not on WordPress.org, so there’s no public install count) |
| Type | Unauthenticated authentication bypass via a race condition in cross-domain sign-in |
| Severity | CVSS 8.1 (high attack complexity) |
| Affected | 4.9.7 and earlier, only with “A different domain per language” and cross-domain sign-in on |
| Fixed | No fix available. Vendor notified August 19, 2026; disclosed November 9 |
| Status | No exploitation reported |
What’s wrong
WordPress login cookies only work on the domain that set them. A site with example.com and example.de would make visitors log in twice. WPML solves this with a single sign-on step: when you log in or out on one domain, hidden iframes tell the other domains to do the same, passing a token so each domain knows who you are.
That token comes from wp_create_nonce('wpml_sso'). A WordPress nonce is built from the action name, the current user, the user’s session token, and a time window that changes every 12 hours. That makes it unique to you while you’re logged in. When nobody is logged in, the user ID is 0 and the session token is empty, so every anonymous visitor gets the same nonce for that action and that 12-hour window. That’s fine for a form that anyone can submit. It’s not fine as proof of identity.
WPML created the sign-out token on the logout landing page, after the browser had already dropped its login cookies. So the token wasn’t tied to the user at all. It was the anonymous nonce, which anyone can get. WPML then stored it in a transient that pointed to the user who was logging out. According to the record, the attack works like this:
- An administrator logs out on the main domain.
- WPML stores a sign-out token mapped to that administrator’s user ID. The token is the anonymous nonce.
- The attacker, who started the same logout flow while not logged in, already has the identical token. The other values WPML checks are derived from a public constant and are computable within WPML’s 60-second sign-on window.
- Before the real sign-out iframe reaches the second domain, the attacker sends that domain the token with a “signed in” status instead.
- The second domain issues WordPress login cookies for the administrator, to the attacker.
Since all the language domains share one WordPress database, an administrator session on example.de is an administrator session on the whole site. The attacker has to win a race against a real logout, which is why it’s scored high complexity. But the attacker can keep trying, and administrators log out every day. Reported by Yuto Hyakumoto.
Are you exposed?
Two settings decide it. Both are under WPML → Settings → URLs and SEO, in the Language URL format card:
- Language URL format: only “A different domain per language” is affected. Directories (
/de/) and parameters (?lang=de) don’t use cross-domain sign-in. - Cross-domain sign-in: on the same screen, WPML offers to let login sessions carry over to the other domains. That’s the feature with the bug.
To check from the command line, this prints the URL format (2 means a domain per language) and any sign-on settings:
wp eval '$s = get_option( "icl_sitepress_settings" ); echo "URL format: ", $s["language_negotiation_type"] ?? "unset", PHP_EOL; print_r( array_filter( $s, fn( $k ) => stripos( $k, "sso" ) !== false, ARRAY_FILTER_USE_KEY ) );'
Check the version too:
wp plugin list --name=sitepress-multilingual-cms --fields=name,status,version
Every version up to 4.9.7 is affected. If you use subdomains (de.example.com), you’re using “different domain per language,” so the same applies.
What to do
1. Turn off cross-domain sign-in
With no patch, this is the fix. Go to WPML → Settings → URLs and SEO, turn off the option that carries login sessions to the other domains, and save. Your editors will have to log in separately on each language domain, which is a small price for closing the bug. If you’re not sure which option it is on your version, ask WPML support. They know about this bug and can confirm it.
2. Block the parameter at the edge
With cross-domain sign-in off, no legitimate request needs WPML’s sign-on parameters. If you run a WAF, Cloudflare or server rules, block requests carrying wpml_sso_token_domain. On Apache or LiteSpeed, for query strings:
RewriteEngine On
RewriteCond %{QUERY_STRING} (^|&)wpml_sso_token_domain= [NC]
RewriteRule ^ - [F]
Put it in the .htaccess each language domain uses. If the parameter can arrive in a POST body on your setup, a server rewrite won’t see it, so add a WAF rule as well.
3. Watch for the fix
Keep an eye on the WPML changelog and update as soon as a version above 4.9.7 lists a security fix. Only then turn cross-domain sign-in back on, if you want it. Wordfence suggests that uninstalling may be safest. For a multilingual site that’s rarely realistic, and turning off the one affected feature gets you most of the way.
4. Check whether you were hit
No attacks have been reported, but if you ran the vulnerable setup:
- Logs: search the access logs of every language domain for
wpml_sso_token_domain. Legitimate sign-ons produce some of these. Look for requests from addresses that aren’t your editors, especially just after an administrator logged out. - Sessions: list active sessions for each administrator, and look for sessions nobody recognizes:
wp user list --role=administrator --field=user_login | xargs -n1 wp user session list - Users and settings: new administrators, changed email addresses, new plugins, and changes to Settings → General.
If anything looks wrong, log everyone out (wp user session destroy --all for each user), rotate the salts in wp-config.php, reset administrator passwords, and work through the remote-access audit.
Where sources disagree
- Patch status. Wordfence lists “no known patch available.” WPML hasn’t published a security notice for this CVE that I could find. If a fix ships, it may appear in the changelog as a general “security improvements” line, so check version numbers, not headlines.
- Severity. 8.1 reflects the race. The impact is full administrator access, but only during someone’s logout, and only on domain-per-language sites with cross-domain sign-in.
- Timeline. Eighty-two days passed between the report and disclosure without a fix. WPML had two SQL injection CVEs earlier this year, both affecting 4.9.5 and earlier. If you’re behind on updates, those apply too.
The bigger lesson
A nonce is not an identity. WordPress nonces are for proving a request came from a page your site generated, and for a logged-out visitor they’re shared by everyone. The bug here is using one as a secret that proves who someone is, created at the exact moment the user stopped being anyone. It’s the same lesson as the LiteSpeed Cache placeholder bug: anything an attacker can generate, or guess, isn’t a secret. A token that grants a login has to come from random_bytes(), be tied to one user and one use, and expire in seconds.
The other lesson is about features. Cross-domain sign-in is a convenience for editors, and it turned into a way in. Before you turn on an option like that, ask what it would mean if it failed. When there’s no patch, knowing which features you can switch off is the difference between a configuration change and an emergency.