Security Advisory ยท Last verified 2026-05-19
Piotnet Addons for Elementor CVE-2026-4885: File Upload RCE Self-Check
Piotnet's file upload handler uses a blacklist to block dangerous extensions.
The blacklist blocks .php. It doesn't block .phar
or .phtml. Apache executes both by default on most shared hosts.
That's CVSS 9.8, no authentication required. Check the plugin version, upload
directory, logs, and server execution rules before calling the site clean.
TL;DR
- CVE: CVE-2026-4885, CVSS 9.8 (Critical). CWE-434.
- Affected: Piotnet Addons for Elementor Pro <= 7.1.70. Condition: at least one form with a file upload field.
- Impact: unauthenticated remote code execution. Attacker uploads a PHP shell disguised as
.pharor.phtml. - Fix: update to 7.1.71+. Then hunt for shells.
- Detection time: 5 minutes for version check. 10 minutes for shell hunt.
Why the blacklist approach fails here
Piotnet's upload handler in pafe_ajax_form_builder checks
incoming file extensions against a deny list: php,
phpt, php5, php7, exe.
Anything not on that list goes through.
The problem is Apache's default config treats .phar and
.phtml as PHP too. So does LiteSpeed on most cPanel boxes.
Nginx won't execute them by default (the location ~ \.php$
block doesn't match), but if your nginx config uses a broader regex or
passes all requests to php-fpm, you're still exposed.
Some hosting setups execute .phtml as PHP out of the box. Shared
hosting on cPanel is a common place to check because Apache's
application/x-httpd-php handler may cover .phar and
.phtml unless the account is explicitly hardened.
Step 1: Is the plugin installed?
WordPress admin - Plugins - Installed Plugins - search "Piotnet". Look for Piotnet Addons For Elementor Pro or the free variant Piotnet Addons For Elementor.
Not installed? You're done. Close this tab.
Step 2: Version check
Version number is right below the plugin name. 7.1.71+ means patched. 7.1.70 or lower means vulnerable. Even if you've already updated, finish the remaining steps. The window between disclosure and your update is when shells get dropped.
Step 3: Do any of your forms accept file uploads?
Open the Elementor editor on pages that use Piotnet form widgets. Look for a File Upload field type. If you've got one on a public page (contact form, application form, job listing), that's your attack surface. An attacker doesn't need to be logged in to submit the form.
Step 4: Hunt for uploaded shells
SSH into your server (or use File Manager in cPanel) and run:
# Find suspicious extensions in uploads
find /home/*/public_html/wp-content/uploads/ \
\( -name "*.phar" -o -name "*.phtml" -o -name "*.php8" -o -name "*.shtml" \) \
-ls 2>/dev/null
# Also check Piotnet's own upload directory if it exists
find /home/*/public_html/wp-content/uploads/piotnet* -type f -ls 2>/dev/null
# Check for recently modified PHP-like files anywhere in uploads
find /home/*/public_html/wp-content/uploads/ -newer /tmp/marker -name "*.p*" -ls 2>/dev/null
If you find .phar or .phtml files you didn't
upload yourself, treat them as hostile. Don't open them in a browser.
Download one copy for forensics, then delete the rest.
Step 5: Check your access logs
Look for POST requests to admin-ajax.php with the action
pafe_ajax_form_builder that came from IPs you don't recognize:
grep "pafe_ajax_form_builder" /var/log/apache2/access.log | tail -50
# or on cPanel:
grep "pafe_ajax_form_builder" ~/access-logs/yourdomain.com | tail -50
Then check if those same IPs later requested a .phar or
.phtml URL. That's the confirmation: upload followed by
execution.
Step 6: Update the plugin
WordPress admin - Plugins - Update Now. Confirm version 7.1.71 or higher. If your license expired and automatic updates are blocked, download the latest zip from pafe.piotnet.com and upload manually through Plugins - Add New - Upload Plugin.
Step 7: Harden (optional but smart)
Even after patching, add a belt-and-suspenders block for PHP execution in
your uploads directory. Drop this in wp-content/uploads/.htaccess:
# Block PHP execution in uploads (Apache)
<FilesMatch "\.(php|phar|phtml|php8|php5|php7|phps|shtml)$">
Require all denied
</FilesMatch> For nginx, add this inside your server block:
location ~* /wp-content/uploads/.*\.(php|phar|phtml|php8|shtml)$ {
deny all;
} This blocks the execution path even if another upload bypass appears later. Apply it broadly on WordPress uploads, whether or not the site runs Piotnet.
When to call for help
If you found shells, assume the attacker had code execution for whatever window your site was vulnerable. That means they could've:
- Read
wp-config.php(database credentials, auth salts) - Dumped your entire database (user emails, passwords, orders)
- Installed a backdoor somewhere other than uploads
- Pivoted to other sites on the same hosting account
If any of those apply, don't try to clean this yourself. You need someone who'll check every file modification since the vulnerability window opened, rotate all credentials, and verify no persistence mechanisms survive.
Ping7 can review the incident. Or use Wordfence's incident response team, or Sucuri. Just don't keep running the site thinking you caught everything by deleting one shell.
References
- NVD - CVE-2026-4885
- Wordfence Intelligence - full advisory
- Piotnet official site (plugin download)
- Ping7 CVE Watch page for CVE-2026-4885
Ping7 is not affiliated with Piotnet, Elementor, or Automattic. All trademarks belong to their owners. No proof-of-concept code is provided.