Forminator Forms runs on more than 600,000 WordPress sites. Until 31 July 2026, a form on any of them that combined a file-upload field with a dropdown could be talked into accepting a PHP file from a complete stranger.
CVE-2026-15748 is a CVSS 9.8 flaw requiring no login and offering a straight path to a web shell, affecting Forminator Forms up to version 1.56.1, a plugin running on more than 600,000 WordPress sites, and fixed in version 1.56.2 on 31 July 2026. Here is what actually goes wrong, and (the part most write-ups skip) why a large share of Forminator sites were never exploitable at all.
What it is
| Field | Value |
|---|---|
| CVE | CVE-2026-15748 |
| CVSS v3.1 | 9.8 Critical |
| Class | Arbitrary file upload leading to remote code execution |
| Authentication | None. Public form submission |
| Affected | Forminator Forms ≤ 1.56.1 |
| Fixed in | 1.56.2, released 31 July 2026 |
| Reported by | Researcher "daroo", via the Wordfence Bug Bounty Program |
| Record | NVD: CVE-2026-15748 |
Are you affected?
Read this section before you panic or relax, because the answer is not simply "are you running Forminator".
Exploitation requires a published form that contains both:
- a File Upload field, and
- a Select (dropdown) field
Both. A contact form with just name, email and message is not exploitable through this path. A job-application form with a CV upload and a "position applied for" dropdown is the textbook target.
That is an unusually specific precondition for a 9.8, and it is why the honest exposure number is far lower than 600,000. It is also why you cannot answer "are we affected?" from the plugin list alone. Somebody has to look at the forms.
How the bug works
Two separate weaknesses chain together. Neither is enough alone.
1. The blocklist that does not match its own entries
File handling lives in handle_file_upload(). Forminator keeps a blocklist of dangerous extensions and checks an uploaded file against it.
The check uses exact-key matching against a lookup table whose keys are not always single extensions: some entries group several variants into one key using pipe alternatives. A lookup for a single extension therefore fails to match a compound key that contains it. The dangerous extension is on the list, the list is consulted, and the file still passes.
This is a specific instance of a very general failure:
A blocklist is only as good as the assumption that its lookup and its contents use the same format. When the data is richer than the check, entries silently stop counting.
2. The upload configuration the visitor gets to write
The second weakness is what makes the first one reachable. Forminator's public submission handler trusts upload-field configuration supplied in the request: configuration that should come from the saved form definition on the server.
An attacker forges that configuration by injecting a crafted value through the Select field. The dropdown is the delivery mechanism; the payload is a fake upload-field config that tells the plugin what to accept and where to put it.
Public form submission
│
├── forged Select value ──► attacker-controlled upload field config
│
▼
handle_file_upload()
│
├── extension blocklist ──► exact-key match misses the compound key
│
▼
PHP file written to an uploads path
│
▼
Request the file directly ──► code execution as the web-server user
Once PHP executes, the site is gone in the ways that matter: wp-config.php and therefore the database credentials, an administrator account of the attacker's choosing, persistence that survives a plugin update, and a foothold on the hosting account.
The lesson worth taking
Neither half of this bug is exotic. A blocklist with a formatting mismatch is a bad afternoon. A handler that trusts client-supplied configuration is a bad design decision. Chained, they are a pre-auth RCE on six hundred thousand sites.
The design lesson is the second one. The server already knows what a form's upload field is supposed to accept: it stored it. Every byte of that configuration that arrives from the browser instead is an opportunity. This is the same class of mistake as trusting a hidden field for a price, and it is exactly what we look for in an application penetration test.
Is it being exploited?
As of disclosure, there was no confirmed in-the-wild exploitation and no public proof-of-concept. The vulnerability was found through a bug bounty programme, not in incident response.
Two cautions. First, "no public PoC" is a statement about today, and the technique is now described publicly in enough detail to reconstruct. Second, plugins with six-figure install bases are scanned continuously; the window between a well-understood WordPress bug and mass automated exploitation is historically short.
The disclosure timeline, as reported by The Hacker News and SecurityOnline, was to the credit of everyone involved fast:
| Date | Event |
|---|---|
| 11 July 2026 | Submitted to Wordfence |
| 14 July 2026 | Validated, proof-of-concept confirmed, vendor notified |
| 31 July 2026 | Forminator 1.56.2 released with the fix |
What to do today
- Update Forminator to 1.56.2 or later. If you are on 1.57.x, be aware a second critical flaw was disclosed in August. See our write-up of CVE-2026-66583, which requires 1.57.1.
- Inventory your forms. Find every published form containing both a File Upload and a Select field. Those were the exposed ones and they are where you should look hardest for signs of abuse.
- Search your uploads directory for PHP. Nothing in a forms plugin's upload path should ever be executable.
- Confirm your upload roots refuse to execute PHP. If you use a custom upload directory, verify it has its own protection. Do not assume it inherited one.
How to check whether someone got there first
Look for executable files anywhere under your uploads tree:
find wp-content/uploads -type f \( -name '*.php' -o -name '*.phtml' -o -name '*.phar' \) -printf '%TY-%Tm-%Td %p\n' | sort
Any result is worth investigating; a result dated before 31 July on a site running an affected version deserves an incident response, not a delete.
Then check your access logs for direct requests to files under the uploads path:
grep -E 'wp-content/uploads/.*\.(php|phtml|phar)' access.log
A successful upload is quiet. The retrieval is not: an attacker has to request the file to run it, and that request lands in your logs with a 200.
If you find either, treat the host as compromised: rotate the database password in wp-config.php, rotate all administrator passwords and application passwords, audit the user table for accounts you did not create, and check for scheduled tasks and mu-plugins that arrived without you. Continuous monitoring for exactly this pattern is what SOC as a service is for.
The broader point
This is the third WordPress plugin flaw in a month where the vulnerable path ran through trusting structure supplied by the client. Plugins are where most WordPress risk lives, and a plugin with a public submission endpoint is an internet-facing application with all the obligations that implies.
If your business depends on a WordPress site, the questions worth answering are: which plugins expose unauthenticated endpoints, who reviews them, and how quickly do you find out when one of them ships a 9.8. We help teams answer those in a secure web development engagement, or talk to us if you would rather have someone check the forms for you.



