Vulnerability analysis

Unauthenticated RCE in File Uploader for WooCommerce

Vulnerability details

Software

File Uploader for WooCommerce

file-uploader-for-woocommerce

Vulnerability type

Unauthenticated RCE

Threat level

High

File Uploader for WooCommerce is a small plugin that lets shop customers attach files to products and orders via the Uploadcare CDN. Versions up to and including 1.0.3 ship an unauthenticated REST endpoint that will happily write an attacker-controlled file, with an attacker-controlled extension, straight into the uploads directory. That is a remote code execution vulnerability (CVE-2025-13329, CVSS 9.8), and it is about as bad as it gets on a live shop.

What the vulnerability does

The plugin registers POST /wp-json/v1/add-image-data during rest_api_init. The permission callback on that route, in src/JsonApi/class-imagejsonapi.php looks like this:

public function check_user_permissions(): bool {
	return true; // Allow logged-out users.
}

No nonce, no capability check and no rate limit. Anyone on the web can call it.

The handler takes three parameters from the request, runs them through sanitize_text_field, and passes them into an upload helper:

$uuid               = sanitize_text_field( wp_unslash( $request->get_param( 'uuid' ) ) );
$original_file_name = sanitize_text_field( wp_unslash( $request->get_param( 'fileName' ) ) );
$modifications      = sanitize_text_field( wp_unslash( $request->get_param( 'cdnUrlModifiers' ) ) );

$url = UploaderHelper::upload_image( $uuid, $original_file_name, $modifications );

The sanitize_text_field filter strips tags and whitespace but it does nothing to stop “shell.php”, “evil.phtml”, “.phar” or any other executable extension.

Inside UploaderHelper::upload_image the plugin uses pathinfo() to pull the extension straight off the supplied filename, builds a path under wp-content/uploads/file-uploader/, then uses Guzzle to stream whatever lives at https://ucarecdn.com/{uuid}/ into that path:

$file_name = sanitize_text_field( $uuid . '.' . $filename_from_url['extension'] );
$file_path = $upload_dir['basedir'] . '/file-uploader/' . $file_name;

$client->request(
	'GET', // ...
	esc_url_raw( 'https://ucarecdn.com/' . $uuid . '/' . $modifications ),
	array( 'sink' => $file_path )
);

There’s no MIME sniff, no call to wp_check_filetype_and_ext(), no wp_handle_sideload(), no allow-list. Uploadcare is a public CDN with a free tier. The attacker can upload their PHP web shell to Uploadcare, grab the UUID, then ask the plugin to pull that payload into the WordPress uploads directory with a “.php” extension. The response even hands back a thumbnail_url pointing at the file, so the attacker knows exactly where to hit it.

That is full unauthenticated RCE on any site running the plugin.

How to check

Run the usual version check:

# Check the version you're running, using WP CLI
wp plugin list --name=file-uploader-for-woocommerce --field=version

# If it's <= 1.0.3, check your site's access logs.
# NOTE: Change the location to match your site's actual access log file(s).
grep 'add-image-data' /var/log/access.log

Any 200 responses from an unauthenticated IP should be treated as a probable compromise. If you see hits to add-image-data in your logs from before you patched, assume the site is compromised and treat it accordingly. Rotate secrets, audit users, restore from a backup – whatever your process is.

Finally, look for nasty PHP files in the uploads/ directory:

# Report unusual file extensions in the upload folder (likely shells).
find wp-content/uploads/file-uploader -type f \( -name '*.php*' -o -name '*.phtml' -o -name '*.phar' \)

Anything with an executable extension in that folder is a live web shell. It’s not something the plugin places there legitimately.

What to do

Update to >= 1.0.4 now. The patch makes the endpoint require a logged-in user and a valid nonce, which closes the unauthenticated path.

important: Version 1.0.4 carries its own separate vulnerability (CVE-2026-25397 – path traversal). At the time of writing (April 2026), no patched version is available.

Also Important: The underlying problem has only been side-stepped because any logged-in user can still exploit it. Even a user who is only a “subscriber” or a “customer”. If your WooCommerce site has open registration enabled, updating to version “1.0.4” won’t fully protect you.

A more robust solution (apart from replacing the plugin) is to deny access to all PHP files in wp-content/uploads/ . This is a standard security configuration deployed by lots of managed WordPress Hosting providers, and it works well. Just add this to your site’s main “.htaccess”:

# Block PHP execution in the WordPress uploads directory.
# Add this near the top of your site's .htaccess file,
# before the standard WordPress section.
<IfModule mod_rewrite.c>
	RewriteEngine On
	RewriteRule ^wp-content/uploads/.*\.(?:php|phtml|phar)$ - [R=403,L,NC]
</IfModule>

The take-away advice here is to be very careful with file-upload plugins. Make sure you’re using a robust managed WordPress hosting provider who understands defence-in-depth, proper server configuration and routine updates.

Stop checking plugin versions manually.

Vulnz subscribers were notified about this vulnerability automatically. Drop the 50KB agent onto your client sites and get a weekly "Zero-Click" security digest straight to your inbox.

Automate your vulnerability reporting