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.

Need a clean-room check on your WordPress site?

Plugin version audit, upload directory webshell scan, hidden admin check, and file integrity verification - everything in this guide, done on a screenshare so you can see what we find in real time. If we find something, we walk you through the remediation on the same call.

Request CVE repair

References

Related guides