Back to Blog
WordPressApplication SecurityCybersecurityVulnerability Management

Simple CAPTCHA with Cloudflare Turnstile CVE-2026-93900: Who Is Exposed and How to Fix It

A WordPress CAPTCHA plugin on 200,000+ sites let contributors plant script that runs when an editor previews the post. Who is exposed, how to check and fix it.

P
Rafael Melo
November 5, 202611 min read

On 4 November 2026, a stored cross-site scripting flaw was published in Simple CAPTCHA with Cloudflare Turnstile, a WordPress plugin that adds a CAPTCHA to login, registration, comment and contact forms on more than 200,000 sites. CVE-2026-93900 is rated 6.4 out of 10. In versions up to and including 1.44.3, anyone who can write posts, starting at the contributor role, can plant script in a post through the plugin's Gravity Forms shortcode. The script runs in the browser of whoever opens that post, including the editor or administrator who previews it before approving it.

It is the second time this exact shortcode has had this exact flaw. The first, CVE-2023-5135, was fixed in 2023; a feature change in February 2025 brought it back.

The fix shipped in version 1.44.4 on 30 October, five days before the CVE. The same day the CVE came out, a second one was published for the plugin, CVE-2026-57775: a broken-authentication flaw in versions up to 1.44.1 that needs no account at all. The version to run is 1.44.5, released on 31 October with two more security fixes to the plugin's login checks. As of 5 November there are no reports of either flaw being exploited, and neither is on the official list of vulnerabilities known to be exploited.

A medium score is no reason to panic, and no reason to skip the update. Below: the three conditions that make a site exposed, why a flaw that needs a contributor account can end with an attacker holding an administrator account, how to check and fix it with WP-CLI, and how to look for anything already planted.

Who Is Exposed?

The vulnerable code only runs on a site where all three of these are true:

  • The plugin is on a version from 1.30.0 to 1.44.3. The CVE lists every version up to 1.44.3; the unquoted number that makes it work arrived in 1.30.0, in February 2025, and versions up to 1.23.1 have the 2023 flaw instead. Anything older than 1.44.5 is past due anyway: this plugin has had eight CVEs in 2026 alone.
  • Gravity Forms is active. The plugin loads its Gravity Forms integration only when Gravity Forms is installed and active.
  • The Gravity Forms integration is switched on. It is the "Enable on all Gravity Forms" checkbox under Settings → Cloudflare Turnstile, and it is off by default. A site that uses the plugin only on its login or comment forms never registers the vulnerable shortcode.

The attack also needs an account that can write posts: contributor, author, editor or administrator. Plenty of sites have those accounts in hands the owner does not fully control:

  • Multi-author blogs and newsrooms with guest writers and freelancers.
  • Agency-built sites where the client's marketing team, an SEO contractor and the agency all have logins.
  • Forgotten accounts of people who left, and accounts whose password was reused on a site that leaked.
  • Open registration. If "Anyone can register" is on and the default role for new users is contributor or higher, the attacker does not need an existing account at all.

If you run Gravity Forms with this integration switched on, and someone with a writing account is not a person you would give your administrator password to, update today.

What the Flaw Does

The plugin adds its CAPTCHA to Gravity Forms through a shortcode, [gravity-simple-turnstile], which it inserts next to each form's submit button when the page renders. The shortcode takes the form's ID and prints it into an inline script, as a bare number in a JavaScript comparison.

In 1.44.3, the ID went through WordPress's HTML escaping and its JavaScript string escaping before it was printed. Both protect a value that sits inside quotes. This one had no quotes around it, so the characters JavaScript needs to run code, such as parentheses, semicolons, braces and the pipe, passed through untouched. Whatever was written in the id attribute became JavaScript on the page.

WordPress shortcodes work anywhere content is rendered, so the shortcode the plugin meant for its own forms also works when someone types it into a post. Contributors can type it into a post.

Why the 2023 Fix Stopped Working

In September 2023, CVE-2023-5135 reported the same thing: stored cross-site scripting through the id attribute of [gravity-simple-turnstile], by contributors and above, in versions up to 1.23.1. Back then the ID was printed inside quoted strings in the script. Version 1.23.2 added HTML escaping, which turns quotes into entities, so the ID could no longer close its string. For that code, the fix held.

In version 1.30.0, released in February 2025, the script was rewritten so the CAPTCHA renders again after a form fails validation. The new script compares the form ID as a number, outside any quotes. The escaping from 2023 stayed in place and looked like protection, but it no longer covered where the value landed. For twenty months, every site with the integration on carried the 2023 flaw again.

Version 1.44.4 changed one line. The ID is now converted to a whole number before it is used anywhere:

php
$form_id = isset($atts['id']) ? absint($atts['id']) : 0;

If you write WordPress code, there are two lessons. Escape for the exact place a value lands: esc_html() is for text inside HTML, esc_js() for a value inside a quoted JavaScript string, and wp_json_encode() for data placed in a script. A value that must be a number should be converted to one, with absint() or (int). And a security fix is only as durable as the test that pins it: escaping is tied to its context, so when a later change moves the value, the fix stops working without anything looking different. A regression test that renders the shortcode with a hostile id would have caught the change in 1.30.0.

Why a 6.4 Can End With an Administrator Account

Contributors cannot publish. Their posts wait for review, which makes "contributor-level" sound like low risk. The review is the problem: to check a pending post, an editor or administrator opens its preview, and the preview renders shortcodes exactly as the published page would.

We reproduced this on a test site running 1.44.3 with Gravity Forms active and the integration on. A contributor submitted a post for review with the shortcode in it, and the script ran in the administrator's browser as soon as the preview loaded. No form had to be on the page. After updating to 1.44.4, the same post printed the ID as a plain number and nothing ran.

Script in an administrator's browser can do anything that administrator can do in the dashboard: create another administrator account, change settings, or install a plugin, which means running code on the server. If the post gets published anyway, the script runs for every visitor who opens it. The 6.4 rates the direct impact as low; what the script can actually do depends on whose browser runs it, and on a site where administrators review contributor posts, that is an administrator's.

How to Check Your Site

With WP-CLI on the server, three commands answer the three conditions:

bash
wp plugin list --name=simple-cloudflare-turnstile --fields=name,status,version,update_version
wp plugin is-active gravityforms && echo "Gravity Forms is active"
wp option get cfturnstile_gravity

The first shows the installed version and, if one is waiting, the update. The last prints on when the Gravity Forms integration is switched on; an empty value or a "Could not get" error means it is off.

Then look at who can write, and whether anyone can sign up:

bash
wp user list --role__in=contributor,author,editor --fields=ID,user_login,roles,user_registered
wp option get users_can_register
wp option get default_role

users_can_register returns 1 when registration is open. Without WP-CLI, the Plugins screen shows the version, and Settings → Cloudflare Turnstile shows the checkbox.

If you look after many sites, the plugin's readme is public, so you can check versions from outside without logging in anywhere:

bash
curl -s https://example.com/wp-content/plugins/simple-cloudflare-turnstile/readme.txt | grep -i "stable tag"

Scanners read the same file, which is why a public disclosure turns into mass scanning so quickly.

How to Fix It

Update the plugin and confirm the version:

bash
wp plugin update simple-cloudflare-turnstile
wp plugin get simple-cloudflare-turnstile --field=version

The second command should print 1.44.5. In the dashboard, it is the usual "update now" link on the Plugins screen.

Updating also defuses anything already planted: from 1.44.4 on, a malicious ID in a post is printed as a number and does nothing. You still want to find it, because it tells you which account was used (see below).

The 1.44.x releases also changed how the plugin checks login and registration forms built with WooCommerce, Easy Digital Downloads and Ultimate Member. After updating, log in, register a test account if registration is open, and submit one of your forms. Do it on staging first if you have one.

A plugin that sits on your login form, with eight CVEs this year and four security releases in four days, is a good candidate for automatic updates:

bash
wp plugin auto-updates enable simple-cloudflare-turnstile

If checking and updating this across every site you run is more than an afternoon's work, our free WordPress security assessment does it for all of them at once.

If You Cannot Update Today

Switch the Gravity Forms integration off, by unticking the checkbox or with:

bash
wp option update cfturnstile_gravity ''

With the integration off, the plugin no longer registers the shortcode. We tested it: a planted shortcode then shows up as plain text in the post, and nothing runs. That has two costs. Your Gravity forms lose their CAPTCHA until you switch it back on, so expect more spam. And planted shortcodes on published pages become visible to visitors, which is also how you spot them. Update as soon as you can, then tick the box again.

Until you have updated, do not preview pending posts from accounts you do not recognize.

Look for Anything Already Planted

The plugin adds its shortcode itself when a page renders. Nothing legitimate stores [gravity-simple-turnstile in a post, so any stored copy is worth a look, and a copy whose id is anything other than a number is a red flag.

Search the revisions too. A contributor who removes the shortcode after an administrator has previewed the post leaves a copy in the revision history, and wp post list --post_type=any skips revisions. We checked: on our test site it missed a revision that a direct query found. Query the posts table, which holds both:

bash
PREFIX=$(wp db prefix)
wp db query "SELECT ID, post_type, post_status, post_author, post_parent, post_modified FROM ${PREFIX}posts WHERE post_content LIKE '%gravity-simple-turnstile%'"

post_author is the account that wrote that version, and post_parent points from a revision to its post. If you find something:

  • Suspend the account that wrote it and reset its password.
  • List the administrators and check each one, especially any created after the planted post's date:
bash
wp user list --role=administrator --fields=ID,user_login,user_email,user_registered
  • Compare the plugin list with what you expect to be installed, and look for plugins nobody on your team added.
  • Log everyone out by changing the security keys in wp-config.php, so any session the script used stops working:
bash
wp config shuffle-salts

Then delete the planted content, revisions included, and update the plugin if you have not yet.

Eight CVEs This Year, Four Security Releases in Four Days

CVE-2026-93900 is the plugin's eighth CVE of 2026:

  • June: a broken-authentication flaw in versions up to 1.38.0.
  • August: before 1.42.0, one solved challenge could be replayed on Forminator forms for a short window.
  • September: three. A CAPTCHA bypass and a content injection, both in versions up to 1.42.1, and, from 1.2.2 to before 1.42.3, a flaw that let visitors without an account run any shortcode registered on the site through the values they typed into a Contact Form 7 form.
  • 29 October: a broken-access-control flaw in versions up to 1.44.0.
  • 4 November: two. The broken-authentication flaw in versions up to 1.44.1, and this stored XSS.

Between 28 and 31 October, the plugin also shipped 1.44.1, 1.44.2, 1.44.4 and 1.44.5, each with security fixes. Besides this flaw, the changelog lists Contact Form 7 forms that could be submitted without solving the CAPTCHA, login and registration checks that could be skipped on sites running WooCommerce, Easy Digital Downloads or Sunshine Photo Cart, and a solved challenge on the Ultimate Member login form that could be reused for several login attempts.

This plugin hooks into the forms of about thirty other plugins, and each integration is one more place where the check can be skipped. A skipped check does not show: the widget still appears and the form still works, while bots get through to your login and registration forms. That is why these releases matter more than their medium scores suggest.

The number of CVEs does not by itself make this a bad plugin. Popular plugins draw researchers, which is how flaws get found, and this fix was out five days before the CVE was published. What it does mean is that the plugin protecting your login form needs updating within days of a release, and that integrations you do not use should be switched off: the Gravity Forms one was off by default, and only the sites that switched it on were exposed. It is the same pattern we described in why client WordPress sites keep getting hacked: the risk lives in the plugins, and in how long they wait for updates.

Free WordPress Security Assessment

The free assessment covers:

  • Plugin inventory: every plugin and version across your WordPress sites, and which of them have security fixes you have not applied
  • Account review: who can write, publish and administer each site, and which accounts nobody uses anymore
  • Compromise check: planted content and unexpected administrator accounts on the sites you are worried about

You get a written list of what is exposed and what to do about it, with no obligation attached.

Request your free WordPress security assessment, see how our WordPress maintenance service tests updates on staging before they reach production, or read about our cybersecurity practice.