
CVE-2026-15748: The Forminator File Upload Flaw and Who Is Actually at Risk
CVE-2026-15748 lets unauthenticated attackers upload PHP files through Forminator. Check whether your forms are exposed and which version really patches it.

Details of CVE-2026-15748 went public on August 17, 2026: an unauthenticated arbitrary file upload vulnerability in Forminator Forms, the WPMU DEV form builder running on more than 600,000 WordPress sites. Wordfence scores it 9.8 out of 10 and describes a path from an anonymous form submission to remote code execution and full site takeover. The advice you will see everywhere is "update now," and that advice is right.
The more useful question is whether your site was ever actually exploitable, because the answer changes what you do next. CVE-2026-15748 needs a specific combination of form fields to be present before anything can be uploaded at all, and it needs a second condition to be true before an uploaded file will execute. Sites that met both conditions have a compromise assessment to run. Sites that met neither have an update to install and nothing more. Working out which group you are in takes about ten minutes.
TL;DR
- CVE-2026-15748 affects Forminator Forms in all versions up to and including 1.56.1. It was fixed in 1.56.2, published to WordPress.org on July 30, 2026. The current release at the time of writing is 1.57.0 (August 12, 2026).
- Uploading anything requires a live form that contains both a File Upload field and a Select field. Forms without that pairing are not exploitable through this route.
- Getting the uploaded file to run requires the upload directory to permit PHP execution. Forminator's default location is meant to be protected by an
.htaccessfile, but that protection is Apache-family only and is written lazily, so it can be absent.- Three separate security releases shipped on July 30, 2026 (1.56.0.1, 1.56.1 and 1.56.2), each fixing a different flaw. Landing on 1.56.0.1 or 1.56.1 does not close this one.
- If you ran a vulnerable version alongside a matching form, search
wp-content/uploadsfor PHP files and audit administrator accounts before you call it done.
What CVE-2026-15748 actually is
Forminator's public form handler accepts file uploads from anonymous visitors, which is the entire point of a File Upload field on a contact or application form. The plugin is supposed to decide which file types are acceptable and reject everything else before writing anything to disk.
According to the Wordfence advisory, the flaw sits in the plugin's handle_file_upload() function and comes from two weaknesses that compound each other. The first is that the blocklist of dangerous extensions is matched by exact key, so MIME type keys written as pipe-separated alternatives slip past it without matching any blocked entry. The second is that the public submission handler trusts upload field configuration supplied in the request, which an attacker can inject by forging the value of a Select field in the same form.
Put together, an unauthenticated visitor can submit the form, tell the plugin what the upload rules should be, and have a PHP file written to the site. The vulnerability was reported by a researcher using the handle "daroo."
That description is worth reading carefully, because it explains the exposure conditions. The forged Select field value is the delivery mechanism for the malicious upload configuration. No Select field in the form, no injection point. That is not a coincidental detail, it is structural, and it is why the exposure conditions below are as narrow as they are.
Note: Reported severity comes from Wordfence's own scoring. NVD enrichment can arrive later and occasionally lands on a different vector string. Treat 9.8 as the working figure and check the NVD entry if you need a number for a formal risk register.
Are you affected? The two conditions that have to be true
Running a vulnerable version of the plugin is necessary but not sufficient. Two further things have to line up.
Condition one: a published form with both a File Upload field and a Select field
The exploit needs somewhere to submit to, and it needs a Select field in that form to carry the forged configuration. A form with a File Upload field but no Select field does not give the attacker the injection point. A form with a Select field but no File Upload field has nothing to upload into.
The combination is more common than it sounds. Job application forms, support request forms, warranty claims and quote requests all tend to pair "attach your file" with "choose a category" or "select a department." If you have ever built a form with a dropdown that routes the submission to a different email address, and that form also takes attachments, you are looking at exactly this shape.
Check every published form, not just the ones you remember. On sites managed by agencies or with several editors, forms accumulate. A form that is no longer linked from any menu is still reachable if its shortcode sits on a page that is still published.
Condition two: whether PHP can execute where the file lands
Writing a PHP file to disk is not the same as running it. Forminator stores uploads under wp-content/uploads by default, and that directory is meant to carry an .htaccess file that stops the web server from executing PHP there. Where that protection holds, the vulnerability is an arbitrary file write rather than code execution: still serious, still a data integrity problem, but not an immediate takeover.
Wordfence identified one specific way the protection fails. If an administrator has configured a custom upload storage root, the guard file for that directory is created only when it is first needed, during a front-end request where the WordPress helper responsible for writing it has not been loaded. The directory gets created, the guard does not, and requesting the uploaded file is then enough to have the web server run it.
There is a second failure mode the advisory does not need to spell out, and it deserves attention because it is much more widespread than custom storage roots: .htaccess is an Apache and LiteSpeed mechanism. On an Nginx server it is an inert text file. Nginx never reads it, and whether PHP executes inside wp-content/uploads depends entirely on the server's own location blocks. A well configured Nginx stack blocks PHP execution in the uploads tree explicitly. A default location ~ \.php$ { fastcgi_pass ... } block that matches anywhere under the document root does not.
This is the part that generic coverage of the CVE tends to skip. If your site runs on Nginx and nobody has written an explicit rule denying PHP under uploads, the .htaccess file Forminator ships is doing nothing for you and never was.
How to check whether PHP runs in your uploads directory
This is worth verifying once, independently of Forminator, because it protects you against the next upload vulnerability as well as this one. It needs SSH or SFTP access.
Create a harmless test file inside the uploads directory:
echo '<?php echo "php-executes-here";' > wp-content/uploads/exec-test.phpThen request it in a browser or with curl, substituting your own domain:
curl -s https://<example.com>/wp-content/uploads/exec-test.phpIf the response contains php-executes-here, PHP is executing in your uploads directory and any file written there is a potential webshell. If you get the raw source, a 403, or a 404, execution is blocked. Either way, delete the file immediately:
rm wp-content/uploads/exec-test.phpImportant: Run this on staging first if you have one, and remove the test file as soon as you have your answer. A forgotten test file is clutter at best and a fingerprint for scanners at worst.
If PHP does execute, that is a hosting-level problem worth fixing regardless of which plugins you run. On MagicWP managed hosting this sits at the platform layer rather than in a plugin's .htaccess file, and SSH and SFTP access are available per site if you want to run the check yourself.
Which version actually fixes it
Here is the trap. Look at the Forminator changelog for the end of July 2026:
| Version | Date | Fix |
|---|---|---|
| 1.56.0 | 2026-07-21 | Feature release (Stripe Connect, Checkout Sessions) |
| 1.56.0.1 | 2026-07-30 | Privilege escalation vulnerability |
| 1.56.1 | 2026-07-30 | Cross-Site Scripting (XSS) vulnerability |
| 1.56.2 | 2026-07-30 | Arbitrary file upload vulnerability |
| 1.57.0 | 2026-08-12 | Feature and maintenance release |
Three security releases, three different vulnerability classes, one calendar day. Only 1.56.2 addresses CVE-2026-15748.
This matters because of how update tooling behaves. A site that checked for updates partway through July 30 could have pulled 1.56.0.1 or 1.56.1, reported "up to date," and stayed vulnerable to the file upload flaw. A monitoring dashboard that recorded "Forminator security update applied, July 30" is not evidence that this specific issue is closed. Neither is a management tool that shows the plugin as patched without naming the version.
Check the actual version number:
wp plugin get forminator --field=versionAnything below 1.56.2 needs updating. If you are on 1.56.0.1 or 1.56.1, you are patched against two other flaws and exposed to this one.
What to do now, in order
1. Confirm the installed version on every site. If you manage a portfolio, do this with WP-CLI across the estate rather than clicking through dashboards. Do not trust a summary that says "updated."
2. Take a backup before you update. Not because the update is risky, but because if the site turns out to be compromised you want a pre-change snapshot to compare against. MagicWP takes daily off-site backups and supports on-demand snapshots with one-click restore; see the backup documentation for how restores work per site.
3. Update to 1.57.0, or at minimum 1.56.2.
wp plugin update forminator --version=1.57.01.57.0 is a substantial feature release including changes to Stripe payment flows, so if your forms take payments, run it on staging first and submit a live test payment before deploying. If you need to move today and cannot test that thoroughly, 1.56.2 closes the security hole with far less surface area for regressions, and you can schedule 1.57.0 properly afterwards.
4. Inventory your forms. Open each published form and note whether it contains both a File Upload field and a Select field. Record the answer; you will need it for the next step and for any incident report.
5. If any form matched, run the compromise checks below. If none did, you are finished. Patch, note the date, move on.
Checking whether a vulnerable site was actually hit
The patch shipped on July 30 and the details went public on August 17. That is roughly two and a half weeks in which the fix was available and the mechanism was not yet widely published. That gap is not safety. Patch diffing is routine, and a one-line changelog entry reading "Fix: Arbitrary file upload vulnerability" on a plugin with 600,000 installs is an invitation to go and look at what changed.
If you ran a version at or below 1.56.1 with a form containing both field types, assume nothing and check.
Search the uploads tree for PHP files. There should not be any.
find wp-content/uploads -type f \( -name "*.php" -o -name "*.phtml" -o -name "*.phar" \) -lsWiden it to catch double extensions and less obvious handlers:
find wp-content/uploads -type f -name "*.ph*" -lsLook for recently modified files across the whole install.
find wp-content -type f -mtime -30 -ls | sort -k8Compare what you find against your own deployment history. Files changed on days when nobody deployed anything are the ones to look at.
Audit administrator accounts. A successful webshell often ends with a new administrator rather than continued shell access, because an account survives a plugin update and a shell does not.
wp user list --role=administrator --fields=ID,user_login,user_email,user_registeredAnything you do not recognise, anything registered during the exposure window, or any account with an email address on a domain you do not control needs investigating rather than deleting. Delete it after you have recorded the details.
Check scheduled tasks. Persistence frequently hides in WP-Cron.
wp cron event listUnfamiliar hook names, particularly random-looking strings, warrant a closer look at what registers them.
Read your access logs for the exposure window. You are looking for POST requests to the plugin's public submission endpoint arriving in unusual volume from a small number of addresses, followed by GET requests to files under wp-content/uploads that ended in .php. That second pattern is the useful one: a legitimate visitor never requests a PHP file inside the uploads directory.
Absence of evidence here is weak evidence. Many hosts rotate access logs after seven to thirty days, which means the earliest part of the exposure window may already be gone. If your logs do not reach back to July 30 and your site met both exposure conditions, treat the result as inconclusive rather than clean.
If you find something, stop doing forensics on production. Restore from a backup taken before the exposure window, apply the update to the restored copy, rotate every credential including database passwords, salts, API keys and user passwords, and only then bring it back. MagicWP's security documentation covers malware scanning and the isolation model between sites, which limits how far a single compromised site can reach.
Why file upload fields keep producing this class of bug
Forminator is not uniquely careless here, and it is worth understanding the pattern rather than treating this as one plugin's mistake.
The plugin has had unauthenticated arbitrary file upload vulnerabilities before: CVE-2023-4596 in versions up to 1.24.6, and CVE-2024-28890 in versions before 1.29.0. Its recent changelogs are dotted with related fixes, including a validation bypass that permitted JSON uploads in 1.53.0 and an issue in 1.52.0 where users could proceed after uploading forbidden file types.
The common thread is the validation model. When a system decides what to accept by listing what to reject, every new edge case in how file types can be expressed becomes a potential bypass. Case variants, double extensions, alternative MIME spellings, null bytes, and in this instance pipe-separated MIME keys that never match an exact blocklist entry. The blocklist has to be right about every possible representation. The attacker has to find one it is wrong about.
An allowlist inverts that. It has to be right about the small set of things you actually want, and everything else fails closed by default. This is why the practical guidance for anyone building custom upload handling is to define the permitted types explicitly, verify the file's actual content rather than trusting the extension or the client-supplied MIME type, rename the file on write so the attacker never controls the final filename, and store uploads outside the web root or behind a handler that serves them with a forced content type.
That last point is where the architectural argument sits. Every mitigation in this CVE that failed was a mitigation applied after the file already existed inside a web-accessible directory. If uploads are not directly reachable over HTTP in the first place, the entire class of bug degrades from remote code execution to disk usage.
Hardening beyond this patch
Updating fixes CVE-2026-15748. It does not fix the next one. A few things reduce the blast radius of whatever comes after.
- Block PHP execution in the uploads directory at the server level, not in a plugin-generated
.htaccessfile. A rule your host controls survives plugin updates, directory recreation and lazy-write bugs. Configuration that a plugin creates on demand is configuration that can fail to be created. - Remove File Upload fields you do not need. A file upload on a form where nobody reads the attachments is pure attack surface. This sounds obvious and is skipped constantly.
- Keep automatic plugin updates on for security releases. The counter-argument is regression risk, and it is a real one, which is why the version to enable this on is a host that offers staging and one-click rollback rather than a bare install where a bad update means a manual restore.
- Run a web application firewall in front of the site. A WAF will not know about an undisclosed vulnerability, but generic malicious file upload rules catch a meaningful share of exploitation attempts against this class of bug before a specific signature exists. This is part of MagicWP's managed security layer rather than something you install per site.
- Keep an inventory of which forms exist and what fields they contain. When the next form plugin advisory lands with a conditional exposure clause, the difference between ten minutes and half a day is whether that inventory already exists.
Forminator was not the only one this month
If you are auditing plugins this week, CVE-2026-15826 in User Profile Builder is worth checking at the same time. It is an authentication bypass, also scored 9.8, affecting installations where the plugin's automatic login setting is enabled. It was patched on July 16, 2026 in version 3.16.5, and it allows an unauthenticated attacker to log in as user ID 1, which on most sites is the original administrator account.
The plugin has a much smaller install base than Forminator, but the impact is more direct: no upload directory conditions, no execution prerequisites, just administrative access. If you run it, check the version and check whether automatic login is enabled.
Frequently Asked Questions
Which Forminator version fixes CVE-2026-15748?
Version 1.56.2, published on July 30, 2026. Any version at or below 1.56.1 is affected. Note that 1.56.0.1 and 1.56.1 also shipped on July 30 as security releases, but they fix a privilege escalation issue and an XSS issue respectively, not this one. The current release as of mid-August 2026 is 1.57.0. Confirm the exact version number rather than relying on an "updated" status in a management dashboard.
My site uses Forminator but has no file upload fields. Am I at risk?
Not from this vulnerability. Exploitation requires a published form containing both a File Upload field and a Select field, because the Select field is what carries the forged upload configuration into the request. Without a File Upload field there is nothing to upload into. Update anyway, since the same version range carries other fixes, but you do not need to run a compromise assessment.
Does the .htaccess file in the uploads folder protect me?
Only partly, and only on some servers. .htaccess directives are read by Apache and LiteSpeed. Nginx ignores the file entirely, so on an Nginx stack the protection depends on your server configuration blocking PHP under wp-content/uploads. Wordfence also documented a case where the guard file is not written at all for custom upload storage roots, because it is created lazily during a front-end request where the WordPress function that writes it has not loaded.
Has CVE-2026-15748 been exploited in the wild?
There were no public reports of confirmed in-the-wild exploitation at the time of writing, but that status changes quickly for pre-authentication file upload flaws in widely installed plugins, and absence of reports is not evidence of absence. The patch became available on July 30 and the technical details became public on August 17, which gives attackers a patch diff to work from for the period in between. Treat any site that ran a vulnerable version with a matching form as needing verification.
How do I check whether my site was compromised?
Search wp-content/uploads for files with PHP extensions, since there should be none. Review administrator accounts for entries you do not recognise or that were registered during the exposure window. List scheduled cron events and look for unfamiliar hooks. Check access logs for GET requests to .php files inside the uploads directory, which legitimate visitors never make. If your logs do not reach back to late July, treat the result as inconclusive rather than clean.
Should I update to 1.57.0 or stop at 1.56.2?
1.57.0 is the better long-term target, but it is a feature release that changes Stripe payment handling, including a migration to Stripe Checkout Sessions. If your forms process payments, test it on staging and complete a real test transaction before deploying. If you need to close the security hole immediately and cannot test properly today, 1.56.2 is the smaller, safer step, and you can schedule 1.57.0 once you have staging time.
Does a web application firewall make updating optional?
No. A WAF reduces the window of exposure and can block generic malicious upload patterns before a vendor-specific rule exists, which is genuinely useful during the hours or days between disclosure and your maintenance window. It is not a substitute for the patch. Rule sets are written against known request shapes, and a determined attacker working from a patch diff has room to vary those shapes.
Conclusion
CVE-2026-15748 is a serious vulnerability with a narrower real-world footprint than its 9.8 score suggests, and the useful work is telling those two things apart on your own sites. Update Forminator to 1.56.2 or later, confirm the version number rather than trusting an update log, and then check whether any published form paired a File Upload field with a Select field. That answer decides whether you are finished or whether you have a compromise assessment ahead of you.
The durable lesson has less to do with this plugin than with where uploads live. Every mitigation that failed here was applied after an attacker-controlled file already sat inside a web-accessible directory. Blocking PHP execution under wp-content/uploads at the server level, where a plugin cannot fail to write it and a directory recreation cannot remove it, is the single change that would have downgraded this from remote code execution to a stray file. That belongs in your hosting configuration, not in a plugin's runtime behaviour, which is one reason managed WordPress hosting with server-level hardening, staging and one-click rollback changes what a critical plugin advisory costs you on a Monday morning.
One final warning: do not treat a clean log search as proof of safety if your host rotates access logs weekly. On a vulnerability disclosed eighteen days after its patch, the most interesting part of the timeline may already have aged out.
Get the best of MagicWP in your inbox.
Monthly engineering notes, product updates, and WordPress performance tips. No spam, unsubscribe anytime.

