Super Forms wp_ajax_nopriv Upload Flaw Is Being Exploited
By WP Vanguard Team
Wordfence confirmed on September 3, 2026 that attackers are actively exploiting CVE-2026-14894, and its firewall has already blocked more than 250,000 exploit attempts against it. The bug lives in a wp_ajax_nopriv handler in the Super Forms - Drag & Drop Form Builder plugin, and it never needed a stolen password, a phished admin, or a chained exploit to work. Exploitation started July 14, 2026, five days after public disclosure, and Wordfence logged its heaviest wave between August 18 and August 25.
CVE-2026-14894 carries a CVSS score of 9.8. Every site running Super Forms at version 6.3.313 or earlier, an estimated 13,000 active installs per Wordfence, let an unauthenticated visitor upload a file straight through the plugin's AJAX handler. WebRehab shipped a fix in 6.3.314 on July 8, 2026, and Wordfence disclosed the flaw the next day. What makes this one worth a closer look isn't the file upload itself; we've covered a near-identical class of bug in the Ninja Forms File Upload vulnerability before. What's instructive is why the check that was supposed to stop it didn't, and now, why attackers found it within days.
How the wp_ajax_nopriv flaw works
Super Forms handles form submissions, including file uploads, through a submit_form() function in its SUPER_Ajax class, wired up to run for logged-out visitors via wp_ajax_nopriv_super_submit_form. That's correct on its own; public-facing forms need to accept submissions from people who've never logged in. The handler processes a data parameter that can carry a datauristring value, a base64-encoded file embedded in the request. That's the arbitrary file upload vector, and it stacks two separate failures. The bug is tracked under CWE-434, "Unrestricted Upload of File with Dangerous Type," a classification that shows up constantly in WordPress plugins because file uploads are one of the few places a plugin has to write attacker-controlled bytes to disk.
First, there was no file type validation against the uploaded content. The declared content type in the datauristring (commonly data:image/gif;base64,...) was never checked against what the decoded bytes actually contained, and extensions weren't restricted to a safe allowlist. Second, and more interesting, there was no capability check at all on who was permitted to call this handler. The destination filename came straight from attacker-controlled request data and was concatenated onto the upload path before the file was written, which also opens the door to path traversal.
The plugin's only gate was a session nonce, sf_nonce. That would matter if the nonce were hard to get. It wasn't. A separate nopriv AJAX action, super_create_nonce, existed specifically to mint a fresh nonce for any visitor who asked for one, no login, no prior session state, nothing. An attacker's script sent one request to grab a valid nonce, then a second request to super_submit_form carrying that nonce and a malicious file payload. Two HTTP calls, no authentication, arbitrary file write. Given that WordPress uploads directories are frequently web-accessible and PHP is often still executable there depending on server config, "arbitrary file" quickly becomes "arbitrary code."
Notice what didn't have to happen for this to work. No password guessing, no session hijacking, no social engineering a site owner into clicking a link. The two requests an attacker needs are the same two requests a legitimate form submission would make, just aimed at a different target. That's what separates a flaw like this from most of the vulnerability classes in our rundown of how WordPress sites actually get hacked: there's no human in the loop to fool, only a missing server-side check to walk past.
Active exploitation: what the real attack looks like
Wordfence's September 3 report includes the actual request shape its firewall has caught more than 250,000 times. It's a single POST to admin-ajax.php carrying the nonce and a JSON data payload whose file field declares an image content type but contains a PHP webshell:
POST /wp-admin/admin-ajax.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded
action=super_submit_form&form_id=2&sf_nonce=04c3aa2046&data={"sf_upload_field":
{"type":"files","files":[{"datauristring":"data:image/gif;base64,PD9waHAg...[truncated]",
"value":"Mushr00w_upl.php","name":"Mushr00w_upl.php","label":"attachment"}]}}
The datauristring decodes to a compact PHP file uploader, branded "Mushr00w Uploader" in the observed samples, that gives the attacker a browser-based form to drop further files once the first-stage webshell lands. Wordfence notes the branding matches a group that recently defaced a government health ministry site through an unrelated Joomla vulnerability, though attribution based on branding alone isn't reliable; the tooling gets reused and swapped between groups. Once a shell like this is running, it's typically used to plant more shells, spam pages, or phishing kits, not to stop at one file.
Wordfence's top offending IP addresses are listed below for anyone checking access logs. The two busiest account for most of the blocked traffic, one of them over 100,000 requests on its own:
| IP address | Blocked requests |
|---|---|
| 103.168.147.235 | 106,000+ |
| 103.168.146.131 | 82,000+ |
| 103.154.152.178 | 5,000+ |
| 103.170.97.7 | 3,400+ |
| 182.10.130.51 | 3,000+ |
| 189.4.122.140 | 2,700+ |
| 129.227.46.143 | 2,100+ |
| 64.176.209.104 | 1,900+ |
| 103.164.182.122 | 1,700+ |
| 37.9.33.62 | 1,700+ |
Who is affected
Every site running Super Forms - Drag & Drop Form Builder at version 6.3.313 or earlier is affected, regardless of configuration. The nopriv AJAX handler exists by design, since the plugin's whole purpose is accepting form submissions from site visitors, so there's no setting that turns this exposure off. Update to 6.3.314 or later closes the hole; there's no partial mitigation or config workaround.
There's no privilege prerequisite here worth listing, which is what pushes the CVSS score to 9.8 in the first place. No subscriber account, no contributor role, no admin session to steal first. A scanner that already knows the super_submit_form action name and the shape of the super_create_nonce request can walk the two-step sequence against any site running the plugin, and the exploitation data confirms that's exactly what's been happening since July 14.
A nonce is not a lock
This is the part worth sitting with, because it's the single most common misconception we see in plugin security reviews, and it's not unique to Super Forms.
A nonce answers one question: did this request originate from a page my server rendered, for this specific action, recently? That's it. It proves intent and origin, which is exactly what you need to stop cross-site request forgery, where a malicious site tricks a logged-in visitor's browser into firing a request they never meant to send. We've written a full explainer on what WordPress nonces protect and what they don't, and the Super Forms bug is close to a textbook illustration of the pattern described there.
What a nonce cannot tell you is whether the caller is allowed to do the thing they're asking for. Those are two different problems with two different fixes: authentication asks who you are, authorization asks what you're permitted to do, and CSRF protection asks whether this specific request was actually intended by that person, right now. A nonce only ever answers the third question. When a plugin treats a passing nonce check as proof the request is legitimate in every sense, it's collapsing three separate security properties into one, and the two it dropped are usually the ones that actually stop an attacker.
The design failure gets worse once you notice where the nonce came from. Nonces are meant to be unpredictable to anyone who didn't load the page that generated them. Super Forms handed its nonce out through a second public endpoint built for that exact purpose. At that point the token isn't proving anything about the request's origin; it's just a value both sides happen to know, no different from a hardcoded string. The lock was real, but the key was sitting in a bowl by the front door.
The difference between the two approaches is small in terms of lines of code and large in terms of consequences:
// Nonce-only: proves origin, proves nothing about permission or content
add_action( 'wp_ajax_nopriv_super_submit_form', function () {
check_ajax_referer( 'sf_nonce', 'nonce' );
submit_form( $_POST['data'] ); // no type check, no allowlist
} );
// Nonce plus actual validation of the request itself
add_action( 'wp_ajax_nopriv_super_submit_form', function () {
check_ajax_referer( 'sf_nonce', 'nonce' );
$type = wp_check_filetype( $_POST['filename'] )['type'];
if ( ! in_array( $type, ALLOWED_UPLOAD_TYPES, true ) ) {
wp_send_json_error( 'Unsupported file type', 400 );
}
submit_form( $_POST['data'] );
} );
The nonce line is identical in both. What separates a safe nopriv handler from a critical CVE is everything after it.
The underlying lesson generalizes past this one plugin. Registering a wp_ajax_nopriv_ handler is an explicit decision to serve logged-out traffic, and WordPress's own developer documentation frames it exactly that way: the nopriv variant exists specifically for endpoints that must work without a session. That decision doesn't relax your validation requirements, it multiplies them. Every input needs the scrutiny you'd give a form submitted by a stranger from an unknown machine, because that's precisely what it is. File type validation against actual content, not just a nonce, is the bar for any handler that accepts uploads from the public internet, logged in or not.
What to do now
Check your Super Forms version. Anything at 6.3.313 or below needs to move to 6.3.314 or later immediately. Given that exploitation has been running since July 14 and Wordfence's heaviest wave hit August 18 to 25, treat a vulnerable install with public forms live as a probable compromise, not just a patch-and-move-on situation.
Search your uploads directory for PHP files and the specific webshell name Wordfence has observed in the wild:
# Any PHP file in uploads shouldn't be there at all
find wp-content/uploads -name '*.php' -type f
# The specific webshell name seen in this campaign
find . -iname 'Mushr00w_upl.php'
# Files with double extensions, a common upload-filter bypass
find wp-content/uploads -type f -regex '.*\.\(php\|php[0-9]\|phtml\)\..*'
Then check your access logs for the exact request pattern attackers are sending, and for hits from the IP addresses Wordfence has flagged as most active:
# Adjust the log path for your server (Apache often uses /var/log/apache2/access.log)
# Requests hitting the vulnerable action
grep 'action=super_submit_form' /var/log/nginx/access.log
# Requests from the top offending IPs
grep -E '103\.168\.147\.235|103\.168\.146\.131|103\.154\.152\.178|103\.170\.97\.7|182\.10\.130\.51' /var/log/nginx/access.log
An empty grep result doesn't clear the site; it just means you haven't found evidence yet, and log retention windows are frequently shorter than the exploitation window here. If you find Mushr00w_upl.php or any other unrecognized .php file in uploads, don't just delete it: a webshell dropped through this path is exactly the kind of persistence mechanism we cover in our guide to PHP backdoors in WordPress, and attackers who got in once often leave more than one way back in, including unfamiliar administrator accounts.
Review your server's PHP execution settings for the uploads directory while you're in there. Disabling PHP execution in wp-content/uploads/ doesn't fix this vulnerability class, but it does mean a successful arbitrary upload can't be immediately weaponized into remote code execution, which is a reasonable defense-in-depth step regardless of which plugin triggered the concern. It's a five-minute change, and it stays useful against the next unpatched upload handler too, whichever plugin ships it.
WP Vanguard's plugin scan checks every detected plugin version against our vulnerability database, so a Super Forms install still on 6.3.313 or earlier surfaces as a known vulnerability once the scan reads the version string. A deep scan (SSH-based) goes further and checks your uploads directory for PHP files, dangerous file types, and double-extension files, the same place a dropped webshell like Mushr00w_upl.php would land. Run a scan of your site to check both in a few minutes.
References
- Wordfence: Attackers Actively Exploiting Critical Vulnerability in Super Forms Plugin
- Wordfence: Super Forms <= 6.3.313 - Unauthenticated Arbitrary File Upload via data Parameter (datauristring) Value
- NVD: CVE-2026-14894 Detail
- Patchstack: Super Forms - Drag & Drop Form Builder <= 6.3.313 - Unauthenticated Arbitrary File Upload
- WordPress Developer Reference: wp_ajax_nopriv_(action) hook
Related reading
Check Your WordPress Site Security
Free scan, no login required. Find vulnerabilities before attackers do.
Scan Your Site FreeGet weekly WordPress security tips
Vulnerability alerts, plugin updates, and security guides. No spam. Unsubscribe any time.