CVE-2026-2917

Happy Addons for Elementor <= 3.21.0 - Insecure Direct Object Reference to Authenticated (Contributor+) Post Duplication via 'post_id' Parameter

mediumAuthorization Bypass Through User-Controlled Key
5.4
CVSS Score
5.4
CVSS Score
medium
Severity
3.21.1
Patched in
1d
Time to patch

Description

The Happy Addons for Elementor plugin for WordPress is vulnerable to Insecure Direct Object Reference in all versions up to, and including, 3.21.0 via the `ha_duplicate_thing` admin action handler. This is due to the `can_clone()` method only checking `current_user_can('edit_posts')` (a general capability) without performing object-level authorization such as `current_user_can('edit_post', $post_id)`, and the nonce being tied to the generic action name `ha_duplicate_thing` rather than to a specific post ID. This makes it possible for authenticated attackers, with Contributor-level access and above, to clone any published post, page, or custom post type by obtaining a valid clone nonce from their own posts and changing the `post_id` parameter to target other users' content. The clone operation copies the full post content, all post metadata (including potentially sensitive widget configurations and API tokens), and taxonomies into a new draft owned by the attacker.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=3.21.0
PublishedMarch 10, 2026
Last updatedMarch 11, 2026
Affected pluginhappy-elementor-addons

What Changed in the Fix

Changes introduced in v3.21.1

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-2917 ## 1. Vulnerability Summary The **Happy Addons for Elementor** plugin (up to 3.21.0) contains an **Insecure Direct Object Reference (IDOR)** vulnerability in its post duplication feature. The vulnerability exists within the `Happy_Addons\Elementor\Classes…

Show full research plan

Exploitation Research Plan: CVE-2026-2917

1. Vulnerability Summary

The Happy Addons for Elementor plugin (up to 3.21.0) contains an Insecure Direct Object Reference (IDOR) vulnerability in its post duplication feature. The vulnerability exists within the Happy_Addons\Elementor\Classes\Clone_Handler::duplicate_thing method.

While the plugin checks if the user has the general edit_posts capability (possessed by Contributors), it fails to perform object-level authorization (i.e., checking if the user is allowed to edit the specific post_id being cloned). Furthermore, the WordPress nonce used to protect the action is tied only to the static action string ha_duplicate_thing rather than being unique per post. This allows a Contributor-level user to obtain a valid nonce from one of their own posts and use it to clone any published post or page on the site, effectively gaining access to its full content and metadata.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin.php (Admin Action)
  • Action: ha_duplicate_thing
  • Parameters:
    • action: ha_duplicate_thing
    • post_id: The ID of the target post to clone (IDOR target).
    • _wpnonce: A valid nonce for the ha_duplicate_thing action.
  • Authentication: Authenticated (Contributor or higher). Contributors have the edit_posts capability required by the can_clone() check.
  • Preconditions: The target post must have a status other than 'private' or 'draft' (unless the attacker is the author), as per the check in duplicate_thing(). Published posts are the primary targets.

3. Code Flow

  1. Entry Point: A request is sent to admin.php?action=ha_duplicate_thing.
  2. Hook Registration: The plugin registers the action handler (likely via admin_action_ha_duplicate_thing).
  3. Authorization Check (classes/clone-handler.php:24):
    public static function can_clone() {
        return current_user_can( 'edit_posts' ); // Contributor+ passes this
    }
    
  4. Parameter Extraction (classes/clone-handler.php:73-75):
    $nonce = isset( $_GET['_wpnonce'] ) ? $_GET['_wpnonce'] : '';
    $post_id = isset( $_GET['post_id'] ) ? absint( $_GET['post_id'] ) : 0;
    
  5. Nonce Verification (classes/clone-handler.php:78):
    if ( ! wp_verify_nonce( $nonce, self::ACTION ) ) { // self::ACTION = 'ha_duplicate_thing'
        return;
    }
    
  6. Weak Ownership Check (classes/clone-handler.php:84-90):
    if ( ('private' == $post_status || 'draft' == $post_status) && ! $same_author ) {
        wp_die( __( 'Sorry, you are not allowed to clone this item.' ) );
    }
    
    Crucially, this check is skipped for 'published' posts.
  7. Sink (classes/clone-handler.php:97):
    $duplicated_post_id = self::duplicate_post( $post );
    
    The duplicate_post method creates a new draft where post_author is set to the current user (the attacker).

4. Nonce Acquisition Strategy

The nonce is for the action ha_duplicate_thing. Since it is not post-specific, an attacker can extract it from the WordPress admin interface where they have permission to see the "Happy Clone" link.

  1. Requirement: The attacker must have at least one post they are allowed to edit (e.g., a post they created).
  2. Steps:
    • Log in as a Contributor.
    • Create a post: wp post create --post_type=post --post_status=publish --post_title="Attacker Post" --post_author=[CONTRIBUTOR_ID].
    • Navigate to the "Posts" list: /wp-admin/edit.php.
    • The "Happy Clone" link is added via Clone_Handler::add_row_actions (Line 46).
    • Use browser_navigate to /wp-admin/edit.php.
    • Use browser_eval to find the "Happy Clone" link associated with the attacker's post and extract the _wpnonce parameter from its URL.

5. Exploitation Strategy

  1. Setup:
    • Create an Administrator user.
    • Create a Contributor user.
    • As Administrator, create a "Sensitive Post" (ID X) with content and perhaps some custom metadata (simulating sensitive widget data).
  2. Nonce Extraction:
    • As Contributor, create a dummy post (ID Y).
    • Navigate to /wp-admin/edit.php.
    • Extract the _wpnonce from the "Happy Clone" link for post Y.
  3. Trigger IDOR:
    • Construct the exploit URL: /wp-admin/admin.php?action=ha_duplicate_thing&post_id=[X]&_wpnonce=[EXTRACTED_NONCE].
    • Send the request using http_request.
  4. Validation:
    • The response should be a redirect (302) to edit.php?post_type=post.
    • Check the post list for a new post titled "Sensitive Post - [Cloned #[X]]".
    • Verify the author of the new post is the Contributor.

6. Test Data Setup

  • Target Post (Admin):
    • Title: Secret Admin Blueprint
    • Content: This is restricted content with internal API keys: {key: "12345"}
    • Status: publish
  • Attacker Post (Contributor):
    • Title: My Trash Post
    • Status: publish

7. Expected Results

  • The HTTP request to clone the Admin post (ID X) returns a 302 redirect.
  • A new post is created in the database.
  • The new post's post_content is identical to the Admin post.
  • The new post's post_author is the ID of the Contributor.
  • The new post's post_status is draft.

8. Verification Steps

  1. List Posts via CLI:
    wp post list --post_author=[CONTRIBUTOR_ID] --post_status=draft --fields=ID,post_title,post_content
  2. Check for Cloned Content:
    Compare the post_content of the new draft with the original Admin post content.
  3. Verify Metadata:
    wp post meta list [NEW_DRAFT_ID]
    Check if metadata from the Admin post was successfully copied.

9. Alternative Approaches

  • Custom Post Types: If the site uses Elementor Templates (CPT elementor_library), try cloning a Template ID. These often contain complex JSON in _elementor_data metadata which is copied by duplicate_meta_entries (Line 183).
  • Ref Parameter: Test the ref=editor parameter to see if the plugin redirects the Contributor directly into the Elementor editor for the stolen content:
    /wp-admin/admin.php?action=ha_duplicate_thing&post_id=[X]&_wpnonce=[NONCE]&ref=editor
Research Findings
Static analysis — not yet PoC-verified

Summary

The Happy Addons for Elementor plugin is vulnerable to an Insecure Direct Object Reference (IDOR) that allows Contributor-level users and above to clone any published post, page, or custom post type. This vulnerability exists because the plugin checks for general 'edit_posts' capabilities rather than object-specific permissions, and utilizes a generic nonce that is not tied to a specific post ID.

Vulnerable Code

// classes/clone-handler.php:18
public static function can_clone() {
	return current_user_can( 'edit_posts' );
}

---

// classes/clone-handler.php:73
$nonce = isset( $_GET['_wpnonce'] ) ? $_GET['_wpnonce'] : '';
$post_id = isset( $_GET['post_id'] ) ? absint( $_GET['post_id'] ) : 0;
$ref = isset( $_GET['ref'] ) ? sanitize_text_field($_GET['ref']) : '';

if ( ! wp_verify_nonce( $nonce, self::ACTION ) ) {
	return;
}

$post_status = get_post_status ( $post_id );
$same_author = self::is_the_same_author( $post_id );

if ( ('private' == $post_status || 'draft' == $post_status) && ! $same_author ) {
	wp_die( __( 'Sorry, you are not allowed to clone this item.' ) );
}

Security Fix

--- a/classes/clone-handler.php
+++ b/classes/clone-handler.php
@@ -81,6 +81,10 @@
 			return;
 		}
 
+		if ( ! current_user_can( 'edit_post', $post_id ) ) {
+			wp_die( __( 'Sorry, you are not allowed to clone this item.' ) );
+		}
+
 		$post_status = get_post_status ( $post_id );
 		$same_author = self::is_the_same_author( $post_id );

Exploit Outline

1. Authenticate to the WordPress site as a user with at least Contributor-level privileges. 2. Create or navigate to a post owned by the attacker to view the 'Happy Clone' link in the admin dashboard. 3. Extract the `_wpnonce` value from the 'Happy Clone' link; this nonce is valid for the `ha_duplicate_thing` action across all posts because it is not post-specific. 4. Identify the `post_id` of the target content (e.g., a published post or page authored by an Administrator). 5. Construct an exploit URL by targeting the `admin_action_ha_duplicate_thing` endpoint: `/wp-admin/admin.php?action=ha_duplicate_thing&post_id=[TARGET_ID]&_wpnonce=[EXTRACTED_NONCE]`. 6. Submit the request. The plugin will create a new draft containing the full content and metadata of the target post, with the attacker as the new owner.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.