Swiss Toolkit For WP <= 1.4.6 - Authenticated (Author+) Arbitrary File Upload via upload_extension_files()
Description
The Swiss Toolkit For WP plugin for WordPress is vulnerable to arbitrary file upload due to a flawed file type validation bypass in the `upload_extension_files()` function in all versions up to, and including, 1.4.6. The `upload_extension_files()` function hooks into WordPress's `wp_check_filetype_and_ext` filter and uses `strpos()` to check if a filename contains a configured extension string, rather than verifying the actual file extension. This makes it possible for authenticated attackers, with Author-level access and above, to upload arbitrary files (including PHP) on the affected site's server which may make remote code execution possible, granted the "Enhanced Multi-Format Image Support" feature is enabled with at least one extension (e.g., avif) in the allowed formats.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:HTechnical Details
<=1.4.6# Exploitation Research Plan: CVE-2026-2354 - Swiss Toolkit For WP Arbitrary File Upload ## 1. Vulnerability Summary The **Swiss Toolkit For WP** plugin (versions <= 1.4.6) contains an arbitrary file upload vulnerability. The flaw exists in the `upload_extension_files()` function, which is hooked i…
Show full research plan
Exploitation Research Plan: CVE-2026-2354 - Swiss Toolkit For WP Arbitrary File Upload
1. Vulnerability Summary
The Swiss Toolkit For WP plugin (versions <= 1.4.6) contains an arbitrary file upload vulnerability. The flaw exists in the upload_extension_files() function, which is hooked into the WordPress wp_check_filetype_and_ext filter.
The function attempts to allow additional image formats (like .avif) by checking if the filename contains an allowed extension string. However, it uses strpos() for this check instead of verifying that the file actually ends with the allowed extension or validating the MIME type correctly. This allows an authenticated user with Author-level permissions or higher to upload PHP files by including an allowed extension string anywhere in the filename (e.g., malicious.avif.php).
2. Attack Vector Analysis
- Endpoint:
wp-admin/async-upload.php(Standard WordPress media upload handler). - Action:
upload-attachment. - Authentication: Authenticated, Author level or higher (requires
upload_filescapability). - Precondition: The feature "Enhanced Multi-Format Image Support" must be enabled in the Swiss Toolkit settings, and at least one extension (e.g.,
avif) must be added to the allowed formats list. - Payload Parameter:
async-upload(the file blob) and_wpnonce.
3. Code Flow (Inferred)
- Entry Point: An Author user uploads a file via the Media Library or a post editor.
- WordPress Core:
wp_handle_upload()callswp_check_filetype_and_ext(). - Plugin Hook: The plugin's
upload_extension_files()function intercepts the check via thewp_check_filetype_and_extfilter. - Vulnerable Logic:
- The function retrieves the list of "Enhanced Multi-Format" extensions from the database (e.g.,
['avif']). - It iterates through these extensions and checks the filename:
if (strpos($filename, $extension) !== false). - If found, it modifies the return array to set
type(MIME) andextto match the allowed extension, effectively "blessing" the file.
- The function retrieves the list of "Enhanced Multi-Format" extensions from the database (e.g.,
- Sink: WordPress core accepts the file as a valid image but preserves the original
.phpextension during the final move to theuploadsdirectory because the sanitization was bypassed by the filter's return value.
4. Nonce Acquisition Strategy
This exploit requires a valid _wpnonce associated with the media-form action (used by async-upload.php).
- Authentication: Log in as an Author-level user.
- Navigation: Use
browser_navigateto go towp-admin/media-new.php. - Extraction:
- The nonce is typically found in the
_wpnoncefield of the upload form or within thepluploadconfiguration object. - Action:
browser_eval("wp.Uploader.defaults.multipart_params._wpnonce")orbrowser_eval("document.querySelector('#_wpnonce').value"). - (Inferred) The localization key for media nonces in WordPress is often under the
_wpnoncekey in the globalpluploadL10norwpUploaderInitobjects.
- The nonce is typically found in the
5. Exploitation Strategy
Step 1: Configuration
Ensure the plugin is configured to be vulnerable. This requires modifying plugin options to enable the specific feature.
Step 2: Payload Construction
Create a PHP file named shell.avif.php.
Content: <?php phpinfo(); ?>
Step 3: Upload Request
Send a multipart/form-data request to async-upload.php.
Request Details:
- Method: POST
- URL:
http://TARGET/wp-admin/async-upload.php - Headers:
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
- Body Parameters:
name:shell.avif.phpaction:upload-attachment_wpnonce:[EXTRACTED_NONCE]async-upload:[FILE_CONTENT]
Step 4: Execution
Access the uploaded file. WordPress stores uploads in wp-content/uploads/YYYY/MM/.
URL: http://TARGET/wp-content/uploads/[YEAR]/[MONTH]/shell.avif.php
6. Test Data Setup
- User: Create an Author user:
wp user create attacker attacker@example.com --role=author --user_pass=password123
- Plugin Settings (Crucial):
- Identify the option name for Swiss Toolkit (likely
swiss_toolkit_settingsor similar - (inferred)). - Enable the "Enhanced Multi-Format Image Support".
- Add
avifto the list of allowed extensions. - Note: If the UI is complex, use
wp option getto find the correct structure andwp option updateto set it.
- Identify the option name for Swiss Toolkit (likely
7. Expected Results
- HTTP Response: The
async-upload.phpendpoint should return a200 OKwith a JSON object containing the attachment ID and the success status. - File System: A file named
shell.avif.phpshould exist in thewp-content/uploads/directory. - Remote Code Execution: Navigating to the file URL should execute the PHP code and display the
phpinfo()output.
8. Verification Steps
- Check for file existence via CLI:
find /var/www/html/wp-content/uploads/ -name "shell.avif.php"
- Verify via HTTP:
http_request('GET', 'http://localhost:8080/wp-content/uploads/[YYYY]/[MM]/shell.avif.php')- Check if response body contains "PHP Version".
9. Alternative Approaches
- If
strposis used differently: If the plugin checks the start of the string instead of just the presence, try naming the fileavif.php. - Alternative Extension: If
avifis not enabled by default, try common alternatives likewebp,svg, orheicif they appear in the plugin's settings. - Bypass
wp_check_filetype_and_extvia Null Byte (Old PHP): If the environment is running an ancient PHP version (unlikely),shell.php%00.avifmight be attempted, though this vulnerability is described as a logic flaw in the string check.
Summary
The Swiss Toolkit For WP plugin for WordPress is vulnerable to arbitrary file upload in versions up to 1.4.6 because it uses the strpos() function to validate file extensions. This logic flaw allows authenticated attackers with Author-level permissions to bypass security filters and upload executable PHP files by including a permitted extension string anywhere in the filename.
Vulnerable Code
/* File: swiss-toolkit-for-wp/includes/class-swiss-toolkit-for-wp.php (inferred) */ // Hooked into wp_check_filetype_and_ext public function upload_extension_files($data, $file, $filename, $mimes) { $settings = get_option('swiss_toolkit_settings'); $allowed_extensions = $settings['allowed_formats'] ?? []; foreach ($allowed_extensions as $extension) { // Vulnerable check: looks for existence anywhere in the string if (strpos($filename, $extension) !== false) { $data['ext'] = $extension; $data['type'] = 'image/' . $extension; break; } } return $data; }
Security Fix
@@ -10,7 +10,8 @@ $allowed_extensions = $settings['allowed_formats'] ?? []; foreach ($allowed_extensions as $extension) { - if (strpos($filename, $extension) !== false) { + $file_ext = pathinfo($filename, PATHINFO_EXTENSION); + if (strtolower($file_ext) === strtolower($extension)) { $data['ext'] = $extension; $data['type'] = 'image/' . $extension; break;
Exploit Outline
An authenticated user with Author-level access or higher can exploit this vulnerability if the 'Enhanced Multi-Format Image Support' feature is enabled. The attacker identifies an allowed extension (e.g., 'avif') and uploads a PHP file with a double extension, such as 'shell.avif.php', through the WordPress media uploader (/wp-admin/async-upload.php). Because the plugin's validation logic only checks for the presence of the 'avif' string anywhere in the filename using strpos(), it marks the file as valid. WordPress then saves the file to the uploads directory with its original .php extension, allowing the attacker to execute arbitrary code by navigating to the file's URL.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.