CVE-2026-9227 Overview
CVE-2026-9227 is an arbitrary file upload vulnerability in the GutenBee – Gutenberg Blocks plugin for WordPress, affecting all versions up to and including 2.20.1. The flaw resides in the gutenbee_file_and_ext_json function, which uses a faulty strpos() substring check to validate .json filenames. Attackers with author-level access or higher can bypass the check using double-extension filenames such as shell.json.php, leading to remote code execution on the WordPress host. The issue is classified under [CWE-434] (Unrestricted Upload of File with Dangerous Type).
Critical Impact
Authenticated authors can upload executable PHP files disguised with .json in the filename, achieving remote code execution on the underlying web server.
Affected Products
- GutenBee – Gutenberg Blocks plugin for WordPress (all versions ≤ 2.20.1)
- WordPress sites running the vulnerable plugin with author-level or higher accounts
- Hosting environments where PHP files in upload directories are server-executable
Discovery Timeline
- 2026-05-28 - CVE-2026-9227 published to NVD
- 2026-05-28 - Last updated in NVD database
Technical Details for CVE-2026-9227
Vulnerability Analysis
The GutenBee plugin registers a filter hook on wp_check_filetype_and_ext that intentionally permits JSON file uploads, a leftover from experimental Lottie animation support. The gutenbee_file_and_ext_json function evaluates the filename with strpos( $filename, '.json' ) to decide whether to override WordPress filetype validation. This substring match does not anchor .json to the end of the filename. A filename like shell.json.php satisfies the check, causing the function to assign application/json as the MIME type and bypass WordPress' default executable extension blocking.
WordPress then writes the file to the uploads directory using the original filename, preserving the trailing .php extension. Most Apache and PHP-FPM configurations will execute any file ending in .php regardless of leading extensions. An authenticated attacker with author privileges can therefore obtain remote code execution under the web server account.
Root Cause
The root cause is improper input validation in the filename extension check. The code uses substring matching rather than verifying the actual final extension. The plugin also registers gutenbee_mime_types to whitelist JSON in upload_mimes, compounding the trust placed in the malformed check. Together these filters override WordPress' built-in defense against uploading executable content.
Attack Vector
Exploitation requires an authenticated session with the Author role or higher. The attacker uploads a payload such as shell.json.php through the standard WordPress media upload endpoint. The plugin's filter allows the file through validation, after which the attacker requests the uploaded file URL directly to trigger PHP execution.
return false;
}
-// TODO think what to do here enabling JSON uploads
-add_filter( 'wp_check_filetype_and_ext', 'gutenbee_file_and_ext_json', 10, 4 );
-function gutenbee_file_and_ext_json( $types, $file, $filename, $mimes ) {
- if ( false !== strpos( $filename, '.json' ) ) {
- $types['ext'] = 'json';
- $types['type'] = 'application/json';
- }
- return $types;
-}
-
-add_filter( 'upload_mimes', 'gutenbee_mime_types' );
-function gutenbee_mime_types( $mimes ) {
- $mimes['json'] = 'application/json';
- return $mimes;
-}
-
add_filter( 'plugin_action_links_gutenbee/gutenbee.php', 'gutenbee_settings_link' );
Source: GitHub Commit bde934c - The patch removes the gutenbee_file_and_ext_json and gutenbee_mime_types filters entirely, eliminating the JSON upload whitelist that enabled the bypass.
Detection Methods for CVE-2026-9227
Indicators of Compromise
- Files in wp-content/uploads/ with double extensions such as *.json.php, *.json.phtml, or *.json.phar.
- New PHP files in upload subdirectories created shortly after an author-level user session.
- Outbound network connections initiated by the PHP-FPM or Apache worker process to attacker infrastructure.
- Webshell-style HTTP requests to /wp-content/uploads/ paths containing query parameters like cmd=, exec=, or base64-encoded payloads.
Detection Strategies
- Audit the WordPress media library and filesystem for any uploaded files whose final extension is executable (.php, .phtml, .phar, .php7).
- Review web server access logs for POST requests to /wp-admin/async-upload.php or /wp-json/wp/v2/media followed by GET requests to the resulting upload URL.
- Correlate plugin version gutenbee ≤ 2.20.1 with author or contributor account activity in the audit log.
Monitoring Recommendations
- Enable file integrity monitoring on wp-content/uploads/ to alert on creation of files with PHP extensions.
- Forward WordPress audit logs and web server logs to a centralized analytics platform for correlation with authentication events.
- Monitor child processes spawned by the web server user for shell invocations, network utilities, or package managers.
How to Mitigate CVE-2026-9227
Immediate Actions Required
- Update the GutenBee plugin to the patched release that removes the gutenbee_file_and_ext_json filter (post-2.20.1 commit bde934c).
- Audit all author, editor, and administrator accounts for unauthorized creation or privilege changes, and reset credentials.
- Scan wp-content/uploads/ for files with double extensions and remove any that are not legitimate.
- Inspect the site for webshells, cron jobs, or modified core files indicating prior exploitation.
Patch Information
The vendor patch removes the JSON upload whitelisting code entirely. See the GitHub commit, the WordPress plugin changeset, and the Wordfence Vulnerability Report for full details.
Workarounds
- Restrict the Author role from uploading files until the plugin is updated, using a capability management plugin or by removing upload_files from the role.
- Configure the web server to refuse PHP execution within wp-content/uploads/ until remediation is complete.
- Temporarily deactivate the GutenBee plugin if an immediate upgrade is not feasible.
# Apache: block PHP execution in the WordPress uploads directory
# Place in wp-content/uploads/.htaccess
<FilesMatch "\.(php|phtml|phar|php7)$">
Require all denied
</FilesMatch>
# Nginx equivalent (server block):
location ~* /wp-content/uploads/.*\.(php|phtml|phar|php7)$ {
deny all;
return 403;
}
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.


