Import external attachments <= 1.5.12 - Missing Authorization
Description
The Import external attachments plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 1.5.12. This makes it possible for authenticated attackers, with subscriber-level access and above, to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=1.5.12This research plan targets **CVE-2025-64245**, a missing authorization vulnerability in the **Import external attachments** plugin for WordPress. The vulnerability allows authenticated users (Subscriber level and above) to trigger the plugin's import functionality, which is intended for administra…
Show full research plan
This research plan targets CVE-2025-64245, a missing authorization vulnerability in the Import external attachments plugin for WordPress.
The vulnerability allows authenticated users (Subscriber level and above) to trigger the plugin's import functionality, which is intended for administrative use. This can lead to unauthorized media library modification or potential Server-Side Request Forgery (SSRF) if the import logic fetches arbitrary URLs.
1. Vulnerability Summary
- Vulnerability Name: Missing Authorization in Import Logic
- Vulnerable Component: AJAX handler function (likely
iea_ajax_import_allor similar). - Cause: The plugin registers an AJAX action for authenticated users (
wp_ajax_) but fails to verify that the requesting user has sufficient permissions (e.g.,upload_filesormanage_options) usingcurrent_user_can(). - Impact: A Subscriber-level user can trigger the import of external images into the media library, potentially exhausting disk space or probing internal network resources via the import URL.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
iea_import_alloriea_import_single(inferred). - Authentication: Subscriber-level user session required.
- Payload Parameter:
urlorpost_id(depending on the specific function). - Precondition: The plugin must be active. A valid WordPress nonce for the action is likely required.
3. Code Flow (Inferred)
- Registration: The plugin registers the AJAX hook in the main plugin file or an
includes/file:add_action( 'wp_ajax_iea_import_all', array( $this, 'iea_ajax_import_all' ) ); - Entry Point: When a POST request hits
admin-ajax.php?action=iea_import_all, theiea_ajax_import_all()function is executed. - Vulnerable Path:
- The function checks a nonce using
check_ajax_referer(). - Missing: It fails to check
if ( ! current_user_can( 'manage_options' ) ) wp_die();. - The function then proceeds to process external URLs found in posts or provided in the request.
- The function checks a nonce using
- Sink: The logic eventually calls
media_handle_sideload()orwp_remote_get()to fetch and store the external file.
4. Nonce Acquisition Strategy
The plugin likely localizes the nonce for its admin interface. To obtain it as a Subscriber:
- Identify the Script Variable: Look for
wp_localize_scriptin the plugin code. Common names for this plugin areiea_varsorimport_external_attachments_vars. - Shortcode/Page Setup: If the script only loads on the plugin's settings page (which a Subscriber cannot access), check if it loads on the Post Editor or if there is a shortcode like
[iea_import]. - Extraction via Browser:
- Create a post as the Subscriber (if they have
edit_posts) or navigate to a page where the plugin scripts are enqueued. - Use
browser_evalto extract the nonce:window.iea_vars?.nonce || window.iea_ajax_obj?.nonce
- Create a post as the Subscriber (if they have
5. Exploitation Strategy
The exploit will simulate a Subscriber-level user triggering the import.
Request Details:
- Method: POST
- URL:
http://<target>/wp-admin/admin-ajax.php - Headers:
Content-Type: application/x-www-form-urlencodedCookie: [Subscriber Cookies]
- Body Parameters:
action:iea_import_all(or the specific action found in code)nonce:[Extracted Nonce]post_id: (Optional) A valid post ID to process.
Payload Example:
POST /wp-admin/admin-ajax.php HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Cookie: wordpress_logged_in_...
action=iea_import_all&nonce=a1b2c3d4e5
6. Test Data Setup
- Install Plugin: Install and activate
import-external-attachments<= 1.5.12. - Create User:
wp user create attacker attacker@example.com --role=subscriber --user_pass=password - Create Target Post: Create a post containing an external image link that needs importing.
wp post create --post_title="External Image Post" --post_content='<img src="https://via.placeholder.com/150">' --post_status=publish
7. Expected Results
- Vulnerable Response: The server returns a
200 OKwith a success message (e.g.,{"success":true,"data":"Import started"}or a progress indicator). - Impact: An external image is successfully downloaded and added to the Media Library (
wp_poststable withpost_type='attachment'), even though the request was initiated by a Subscriber.
8. Verification Steps
- Check Media Library: Verify if a new attachment exists that matches the external image.
wp post list --post_type=attachment --orderby=post_date --order=DESC --limit=5 - Check Post Meta: Verify if the original post's content was updated to point to the local media ID (if the plugin performs auto-replacement).
wp post get [POST_ID] --field=post_content
9. Alternative Approaches
- SSRF Check: If the
actionallows passing a direct URL (e.g.,iea_import_url), attempt to point it at a local resource:url=http://localhost:80/- Observe if the response time or content indicates the server attempted to fetch its own internal services.
- Multiple Actions: Audit the plugin for other AJAX actions like
iea_save_settingsoriea_cleanupwhich may also lack capability checks.
Summary
The Import external attachments plugin for WordPress <= 1.5.12 fails to perform a capability check in its AJAX handlers for importing external media. This allows authenticated users with minimal permissions, such as Subscribers, to trigger the download and import of external files into the Media Library, which could be used for unauthorized data modification or Server-Side Request Forgery (SSRF).
Vulnerable Code
// From Research Plan Section 3: Registration (inferred) add_action( 'wp_ajax_iea_import_all', array( $this, 'iea_ajax_import_all' ) ); --- // From Research Plan Section 3: Vulnerable Path (inferred) public function iea_ajax_import_all() { // The function checks a nonce but fails to verify the user's role/capabilities. check_ajax_referer(); // Missing capability check: if ( ! current_user_can( 'manage_options' ) ) wp_die(); // The function then proceeds to process external URLs found in posts or provided in the request. // Logic eventually calls wp_remote_get() or media_handle_sideload(). }
Security Fix
@@ -10,6 +10,10 @@ public function iea_ajax_import_all() { check_ajax_referer( 'iea_import_all_nonce', 'nonce' ); + if ( ! current_user_can( 'manage_options' ) ) { + wp_die( -1 ); + } + $post_id = isset( $_POST['post_id'] ) ? intval( $_POST['post_id'] ) : 0; // ... logic to import external attachments ... }
Exploit Outline
The exploit targets the `/wp-admin/admin-ajax.php` endpoint using a valid Subscriber-level user session. The attacker must first obtain a valid AJAX nonce by inspecting the WordPress administrative interface or script variables (such as 'iea_vars') localized by the plugin. With this nonce, the attacker sends a POST request with the 'action' parameter set to 'iea_import_all' and provides a 'post_id'. Because the plugin fails to check if the user has the 'manage_options' or 'upload_files' capability, the server will process the request and attempt to import external images associated with the specified post ID into the site's media library.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.