Critical Vulnerability Patched in Ad Inserter Plugin

Description: Authenticated Remote Code Execution
Affected Plugin: Ad Inserter
Affected Versions: <= 2.4.21
CVSS Score: 9.9 (Critical)

On Friday, July 12th, our Threat Intelligence team discovered a vulnerability present in Ad Inserter, a WordPress plugin installed on over 200,000 websites. The weakness allowed authenticated users (Subscribers and above) to execute arbitrary PHP code on websites using the plugin. We privately disclosed the issue to the plugin’s developer, who released a patch the very next day.

This is considered a critical security issue, and websites running Ad Inserter 2.4.21 or below should be updated to version 2.4.22 right away. On the same day we discovered the vulnerability, Wordfence Premium customers received a new firewall rule to protect against exploits; free users will receive the rule after thirty days.

Ad Preview Prelude

Ad Inserter is an ad management plugin that supports all different kinds of ads and includes advanced options for inserting opt-in forms, header scripts, Javascript, CSS, HTML, PHP, analytics, tracking or advert code anywhere on the page. The plugin also has an ad preview feature which administrators can use to verify ad blocks are configured correctly before publishing them for site visitors to see.

Ad Inserter’s preview feature showing a test image

The preview feature is accessed via the ajax action ai_ajax_backend.

if (is_admin () === true) {
  add_action ('wp_ajax_ai_ajax_backend', 'ai_ajax_backend');
  add_action ('wp_ajax_ai_ajax',         'ai_ajax');
  add_action ('wp_ajax_nopriv_ai_ajax',  'ai_ajax');

Because the action is registered without the wp_ajax_nopriv prefix it is only accessible by authenticated users. By default, ajax actions registered in this way can be accessed by any logged-in user—Subscribers and above. If we take a closer look at the way this action was implemented, we can see that there is an additional security control in place: check_admin_referer().

function ai_ajax_backend () {
  global $preview_name, $preview_alignment, $preview_css;

//  check_ajax_referer ("adinserter_data", "ai_check");
  check_admin_referer ("adinserter_data", "ai_check");

  if (isset ($_POST ["preview"])) {
    $block = urldecode ($_POST ["preview"]);
    if (is_numeric ($block) && $block >= 1 && $block <= 96) {
      require_once AD_INSERTER_PLUGIN_DIR.'includes/preview.php';

The function check_admin_referer() is intended to protect against cross-site request forgery (CSRF) attacks by ensuring that a nonce (a one-time token used to prevent unwanted repeated, expired, or malicious requests from being processed) is present in the request. That’s great! However, we often see developers stop there, thinking that checking for a nonce is a sufficient form of access control. In practice, that can sometimes be true, assuming that the nonce is only made available to users with the appropriate privileges. The WordPress documentation makes it clear, though, that check_admin_referer() is not intended for access control, and this vulnerability is a good example of why misusing nonces for authorization is a bad idea.

Nonces can be Compromised

Another useful feature Ad Inserter provides is a debug mode for troubleshooting ad issues. Normally, these debugging features are only available to administrators, and when certain options are enabled a block of Javascript is included on nearly every page. That Javascript contains a valid nonce for the ai_ajax_backend action.

Javascript code revealing a valid nonce

Unfortunately, that debugging feature can be triggered by any user who has this special cookie!


Clearly, nonces are no substitute for proper access control using current_user_can().

Previewing Malicious Payloads

With a nonce in hand—and a Subscriber or above user account—an attacker can now exploit the ad preview feature by sending a malicious payload containing arbitrary PHP code such as <?php echo file_get_contents('/etc/passwd'); ?>.

Ad Inserter’s preview feature showing the results of a malicious payload

Disclosure Timeline

July 12 – Vulnerability discovered by Wordfence Threat Intelligence Team
July 12 – Firewall rule released to Wordfence Premium users
July 12 – Plugin developer notified of the security issue
July 13 – Patch released
August 11 – Firewall rule becomes available to free users


In today’s post, we detailed an authenticated remote code execution flaw present in the Ad Inserter plugin. This flaw has been patched in version 2.4.22 and we recommend users update to the latest version available. Sites running Wordfence Premium have been protected from attacks against this vulnerability since July 12th. Sites running the free version of Wordfence will receive the firewall rule update on August 11th.

Thanks to the plugin’s developer, Igor Funa, for his extremely prompt response on a Saturday, and to James Yokobosky of the Wordfence Threat Intelligence team for his assistance in researching this vulnerability.

Did you enjoy this post? Share it!


  • Great catch. Hopefully this helped prevent many people's hard work get destroyed.

  • This is a nice article for everyone, I like your plugin is doing awesome work to keep it secure and your team is quite sending us regular valuable information to update with new trends.


  • Wordfence has been to me an indisputable security plugin beyond which i don't look further...and i really appreciate your sacrificial support in making available a free version of such an extremely intelligent plugin...thank you.