Improper Access Controls in GDPR Cookie Consent Plugin

Description: Improper Access Controls
Affected Plugin: GDPR Cookie Consent
Affected Versions: <= 1.8.2
CVSS Score: 9.0 (Critical)
CVSS Vector:
Patched Version: 1.8.3

The following post describes how improper access controls lead to a stored cross-site scripting vulnerability in the GDPR Cookie Consent plugin that emerged after it was removed from the repository. The Wordfence team released a firewall rule to our Premium customers on February 10th.

To help create awareness of this issue, we are disclosing details of this vulnerability today, now that a fix has been released and users who do not use Wordfence Premium have a clear upgrade path. A technical description of the vulnerability in the “GDPR Cookie Consent” plugin follows.

GDPR Cookie Consent is a plugin providing site owners with the functionality to present an unintrusive modal to allow end users of the site to review and consent to receiving that site’s cookies. It’s useful for sites looking to be in compliance with EU GDPR/Cookie Law regulations. GDPR Cookie Consent currently has 700,000 active installs.

Earlier this week, the GDPR Cookie Consent plugin was closed “pending a full review” according to the plugin’s page in the directory. Normally when plugins are closed in the WordPress plugins directory without a clear reason, plugin users can be concerned or confused. Because plugins can often be closed due to security issues, we decided to investigate to see if this was the case. The development log showed the most recent revision with the log message “1.8.3 – PHP 7.4 compatibility – Security fix”, so we decided to dig further into the code changes to determine its severity to protect Wordfence users.

There were a number of code changes, but those relevant to security include a capabilities check added to an AJAX endpoint used in the plugin’s administration pages.

Because the AJAX endpoint was intended to only be accessible to administrators, the vulnerability allows subscriber-level users to perform a number of actions that can compromise the site’s security.

There are 3 actions that the vulnerability exposes to subscribers: get_policy_pageid, autosave_contant_data, and save_contentdata.

get_policy_pageid does not do much other than return the post ID of the plugin’s configured cookie policy page. There isn’t much risk with having this action available to subscribers.

autosave_contant_data is intended to define the default content that appears in the cookie policy preview page. The stored HTML content is unfiltered and can contain cross-site scripting (XSS) payloads. The cookie policy preview page is publicly accessible to all users, and these XSS payloads will be executed when visiting http://<wordpress-site>/cli-policy-preview/.

save_contentdata is designed to create or update update the corresponding post used as the GDPR Cookie Policy page that end users of the site would view to choose whether to accept cookies from the site. The action takes a page_id parameter along with a content_data parameter which contains the post content. The page_id parameter allows the attacker to update the post content of any post. Additionally, it will set the post status to draft, so attackers looking to use this vulnerability for defacement won’t be able to display the post content to normal end users of the site. It could potentially be used to remove posts and pages from the public-facing portion of the site though.

Since the post is in draft status, the post content will be visible to the post author, editors, and administrators. By default, when wp_insert_post is used for creating and updating posts, the post content is run through wp_filter_post_kses which is WordPress’s HTML whitelist. It’s designed to only allow specific HTML tags and attributes, and will strip out XSS payloads.

Because the post content can contain shortcodes, an attacker can however use GDPR Cookie Consent’s built-in shortcodes to bypass the KSES filter. These shortcodes are parsed when viewing the rendered post in the browser. Here’s an example shortcode that can included in the post content that will render a valid XSS payload in the browser when viewing the post:

[cookie_accept colour='" onmousemove=alert(/xss/);this.onmousemove=null; style="position:fixed;top:0;right:0;bottom:0;left:0;" test="']

Because the post itself will no longer be public on the site (since the post status has been changed to draft) the XSS payload can only be executed by authors, editors, and administrators who view the post.


  • February 8, 2020 – GDPR Cookie Consent plugin is removed from the plugin directory.
  • February 10, 2020 8:02 AM UTC – A patch fixing the vulnerability is pushed to
  • February 10, 2020 6:37 PM UTC – We deploy a firewall rule to provide protection against this vulnerability to our Threat Defense Feed.
  • February 11, 2020 10:00 PM UTC – GDPR Cookie Consent is re-opened in the plugin directory with the patched version available for download.
  • March 11, 2020 – Wordfence users still using the free version receive the firewall rule to protect their site.


In today’s post, we detailed how a missing capabilities check can lead to stored cross-site scripting in the GDPR Cookie Consent plugin. This vulnerability has been fixed in version 1.8.3. We recommend that users immediately update to the latest version available. Sites running Wordfence Premium have been protected from attacks against this vulnerability since February 10th. Sites running the free version of Wordfence receive the firewall rule update on March 11th, 2020.

Additionally, the generic XSS protection built into our WAF blocked the XSS payloads sent to all AJAX endpoints tested with this vulnerability. This XSS protection is provided out of the box with the Wordfence WAF, and has been available all along to both premium and free users.

Special thanks to Matt Rusnak and Ryan Britton for handling the initial investigation into this vulnerability.

Did you enjoy this post? Share it!


  • autosave_contant_data should probably say content

  • Just a suggestion that you don't release problems to the world until non premium members have had a chance to update their plugins.
    By disclosing a vulnerability at the same time a fix is released (but before there is a chance to apply it) I feel you are unnecessarily exposing website owners. Delaying the disclosure by a couple of days would provide the time for plugins to be updated. Still email Wordfence users that there is a problem of course.
    Thanks for the plugin.

    • Part of the reason we publish vulnerability reports and email our mailing list is to let our users know they should update as soon as possible. Free users were also covered by the XSS protection built into our WAF before the details were released.

  • Well, it's becoming clearer by the post that the most problematic issue - at least one I've seen the most often - is connected to administrative ability verification, or rather: the lack thereof. Personally, I still think it's connected to how the damn "is_admin" function is named - you think you have security dealt with, and you're wrong...

    • There's a number of common developer "gotchas" within WordPress that can lead to vulnerabilities, `is_admin` being one, and also registering AJAX actions such as this one. I like the way WordPress has developers add pages to the navigation within the admin panel. add_menu_page includes a capability as the third parameter to this function which requires the developer to consider who should be able to access the page when they initially begin building the page. AJAX actions could be handled similarly with something like add_ajax_action which could also include a required capability parameter (actions open to the public could be handled with its own function like add_nopriv_ajax_action). Maybe future versions of WordPress will include updated APIs like this while still maintaining backwards compatibility for existing plugins and themes.

  • That is why you should not trust the first plugins that come across. It is better to use open source cookie consent that use millions of sites, for example 2GDPR free cookie consent