Security Advisory ยท Published 2026-05-27
WordPress CVE-2026-6960: Unauthenticated File Upload RCE - What You Need to Check Today
CVE-2026-6960 is a CVSS 9.8 unauthenticated arbitrary file upload vulnerability in a
WordPress plugin that leads directly to remote code execution. The attack is the
oldest trick in the PHP playbook: upload a .php file somewhere the web
server will execute it, then call that file. No login. No admin session. No CSRF token
dance. Just an HTTP POST and a shell.
Why unauthenticated file upload is the worst kind of WordPress vuln
I want to put this in perspective before we get to the commands. There's a spectrum of WordPress vulnerabilities, and most of them require something from the attacker - an account, a session, a logged-in user to click something. Unauthenticated file upload requires none of that. Your site doesn't need visitors. The attacker doesn't need to know anything about you. They scan for the endpoint, confirm it's accessible, upload the file, and they're in. The whole operation takes under a minute with a script.
The 9.8 CVSS score reflects this. The only reason it's not 10.0 is that the exploitation
result is constrained to the web server's user context - so if you're running PHP as
www-data with limited permissions, the blast radius is bounded. It's still
a full server compromise in most real hosting configurations.
Step 1: Identify whether you have the affected plugin
CVE-2026-6960 affects a specific WordPress plugin with a file upload handler that doesn't validate file types before writing to a web-accessible directory. Check your installed plugins:
# From the WordPress root, list all active plugins
wp plugin list --status=active --fields=name,version,status
# Or scan the plugins directory directly
ls wp-content/plugins/
# If you have WP-CLI, check for known vulnerable slugs from NVD
wp plugin get PLUGIN-SLUG --field=version 2>/dev/null Cross-reference your plugin list against the NVD CVE-2026-6960 entry for the specific plugin name and affected version range. The plugin details will be fully populated in NVD within 48-72 hours of the initial publication if CPE data isn't there yet.
Step 2: Check for signs of exploitation
If you were running a vulnerable version before you knew about this, run these checks before you do anything else. Patching a compromised site without cleaning it first just locks the attacker in with you.
Hunt for PHP files in upload directories
WordPress never writes PHP files to wp-content/uploads/ under normal
operation. If there's a .php file in there, it's a webshell.
find wp-content/uploads/ -name "*.php" -ls
find wp-content/uploads/ -name "*.phtml" -ls
find wp-content/uploads/ -name "*.phar" -ls
find wp-content/uploads/ -name "*.php5" -ls Empty output is what you want. Anything else is a problem.
Check recently created files
# Files modified in the last 7 days, excluding the uploads folder you just checked
find wp-content/ -name "*.php" -mtime -7 -not -path "*/uploads/*" -ls
# Specifically in the plugin directory of the affected plugin
find wp-content/plugins/PLUGIN-SLUG/ -name "*.php" -mtime -7 -ls Look for webshell signatures in PHP files
# Common webshell patterns
grep -r "eval(base64_decode\|system(\$_\|exec(\$_\|passthru(\$_\|shell_exec(\$_" wp-content/uploads/ 2>/dev/null
grep -r "FilesMan\|WSO\|r57shell\|c99shell\|b374k" wp-content/ 2>/dev/null | grep -v ".git" Check access logs for the upload endpoint
# Look for POST requests to the vulnerable plugin's upload handler
grep "POST.*PLUGIN-SLUG\|POST.*upload\|POST.*file" /var/log/apache2/access.log | grep "200\|201" | tail -50
# Nginx
grep "POST.*upload" /var/log/nginx/access.log | grep " 200 " | tail -50
A successful exploit will show a 200 response to a POST on the upload endpoint,
followed by a GET request to a .php file in an uploads directory
shortly after. That GET request is the attacker calling their shell.
Step 3: Patch
Update the affected plugin to the patched version. In wp-admin: Plugins - Updates - select the plugin - Update.
From the command line:
wp plugin update PLUGIN-SLUG
wp plugin verify-checksums PLUGIN-SLUG
The verify-checksums command compares your installed files against
the official WordPress.org copy. Any modified or extra files show up here.
Step 4: Immediate hardening regardless of compromise status
Whether or not you found anything in the checks above, do these. They're worth doing after any unauthenticated file upload CVE because the same attack vector gets reused across plugins constantly.
Block PHP execution in uploads via .htaccess (Apache)
Create or update wp-content/uploads/.htaccess:
# Deny PHP execution in uploads directory
<FilesMatch "\.php$">
Order Allow,Deny
Deny from all
</FilesMatch>
# Also block other executable extensions
<FilesMatch "\.(php|php5|phtml|phar|pl|py|cgi)$">
Order Allow,Deny
Deny from all
</FilesMatch> Block PHP execution in uploads via nginx config
location ~* /wp-content/uploads/.*\.php$ {'{'}
deny all;
return 403;
{'}'}
Add this inside your server {} block and reload nginx:
nginx -t && systemctl reload nginx.
Review which plugins handle file uploads
# Find plugins that accept file uploads (quick heuristic)
grep -rl "move_uploaded_file\|wp_handle_upload" wp-content/plugins/ 2>/dev/null | grep -v ".git"
Any plugin that calls move_uploaded_file() or
wp_handle_upload() is a candidate for similar vulnerabilities. This
isn't a hit list - both functions are legitimate - but it tells you which plugins
touch file uploads and should be on your priority update list.
If you found a webshell or compromise indicators
Don't just delete the PHP file and move on. That's not remediation, that's inconvenience. Here's the correct order:
First, take your site offline or into maintenance mode while you work. An attacker with an active shell will notice you cleaning and can plant persistence faster than you can find it while the site is live.
wp maintenance-mode activate
Second, snapshot the server. You need the forensic evidence before you start
deleting things. tar -czf /tmp/wp-snapshot-$(date +%Y%m%d).tar.gz wp-content/
at minimum.
Third, force-logout every user and rotate credentials.
wp user session destroy --all
# Then manually update the secret keys in wp-config.php
# Use: https://api.wordpress.org/secret-key/1.1/salt/ Fourth, follow the full recovery playbook. The WordPress hacked recovery guide covers the full sequence - database audit for rogue admins, malicious options, cron job backdoors, and how to get back to a confirmed-clean state without missing anything.
The pattern you'll keep seeing in WordPress plugins
This isn't the first WordPress plugin with an unauthenticated file upload RCE, and
it won't be the last. The same mistake gets made repeatedly: a plugin adds a file
upload handler, the developer either forgets to check current_user_can()
before processing the upload, or they check it but the nonce validation is broken,
or they validate the extension client-side but not server-side. Any of those paths
leads to this class of vulnerability.
The best structural defense against the next one: block PHP execution in
wp-content/uploads/ at the server level right now (Step 4 above), and
keep auto-updates on for all plugins. The window between disclosure and active
exploitation for high-severity WP plugin CVEs is sometimes measured in hours in 2026.
Auto-updates with that cadence actually matter.
FAQ
My site is on managed WordPress hosting (WP Engine, Kinsta, etc.). Do I need to do this?
Managed hosts typically have their own WAF rules and push plugin updates automatically for critical CVEs. Check with your host whether they've pushed the update. Even so, verify the plugin version yourself - "we handle security" from a host means different things at different companies.
The NVD page doesn't have product details yet. How do I know if I'm affected?
NVD's CPE data often lags a day or two behind. The Patchstack and Wordfence advisories for WordPress CVEs usually have the plugin slug and version range within hours of disclosure. Check patchstack.com/database and search for CVE-2026-6960.
Can I just delete the plugin entirely?
Yes, deactivating and deleting the plugin eliminates the vulnerability immediately. If you're not using the functionality it provides, that's the cleanest option. Fewer plugins means fewer attack surface. Delete it, and check whether anything on your site actually depended on it.
References
- NVD: CVE-2026-6960
- Patchstack WordPress vulnerability database
- Wordfence threat intelligence database