CVE-2026-4019

Complianz – GDPR/CCPA Cookie Consent <= 7.4.5 - Missing Authorization to Unauthenticated Private Post Content Disclosure via Consent Area REST Endpoint

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
7.4.6
Patched in
1d
Time to patch

Description

The Complianz – GDPR/CCPA Cookie Consent plugin for WordPress is vulnerable to unauthorized data access in all versions up to, and including, 7.4.5 This is due to the REST API endpoint at /wp-json/complianz/v1/consent-area/{post_id}/{block_id} using __return_true as the permission_callback, allowing any unauthenticated user to access it. The cmplz_rest_consented_content() function retrieves a post by ID via get_post() and returns the consentedContent attribute of any complianz/consent-area block found in it, without checking if the post is published or if the user has permission to read it. This makes it possible for unauthenticated attackers to read the consent area block content from private, draft, or unpublished posts.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=7.4.5
PublishedApril 28, 2026
Last updatedApril 29, 2026
Affected plugincomplianz-gdpr

What Changed in the Fix

Changes introduced in v7.4.6

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-4019 (Complianz Private Post Disclosure) ## 1. Vulnerability Summary The **Complianz – GDPR/CCPA Cookie Consent** plugin (<= 7.4.5) contains a missing authorization vulnerability in its REST API implementation. Specifically, the endpoint `/wp-json/complianz/v1…

Show full research plan

Exploitation Research Plan: CVE-2026-4019 (Complianz Private Post Disclosure)

1. Vulnerability Summary

The Complianz – GDPR/CCPA Cookie Consent plugin (<= 7.4.5) contains a missing authorization vulnerability in its REST API implementation. Specifically, the endpoint /wp-json/complianz/v1/consent-area/{post_id}/{block_id} uses __return_true as its permission_callback, effectively allowing unauthenticated access.

The underlying function cmplz_rest_consented_content() retrieves a WordPress post using get_post($post_id) but fails to verify if the post is published, private, or draft, and does not check if the requesting user has the read_post capability for that specific post. If the post contains a complianz/consent-area block, the function extracts and returns the consentedContent attribute, leading to unauthorized disclosure of sensitive information hidden within unpublished or private posts.

2. Attack Vector Analysis

  • Endpoint: GET /wp-json/complianz/v1/consent-area/{post_id}/{block_id}
  • Authentication: None (Unauthenticated)
  • Parameters:
    • post_id (URL Path): The ID of the target post (Draft, Private, or Scheduled).
    • block_id (URL Path): The unique identifier assigned to the specific "Consent Area" block within that post.
  • Vulnerable Component: cmplz_rest_consented_content() (inferred location: includes/class-rest-api.php or similar logic file, though not provided in the source snippets).
  • Preconditions: A post must exist (regardless of status) that contains a Gutenberg block of type complianz/consent-area which has the consentedContent attribute populated.

3. Code Flow (Inferred from Description)

  1. Registration: The plugin registers a REST route using register_rest_route('complianz/v1', '/consent-area/(?P<post_id>\d+)/(?P<block_id>[a-zA-Z0-9\-]+)').
  2. Authorization: The permission_callback is set to __return_true, bypassing WordPress's default REST API authorization checks.
  3. Execution: When a request is made, cmplz_rest_consented_content(WP_REST_Request $request) is invoked.
  4. Retrieval:
    • $post_id = $request->get_param('post_id')
    • $post = get_post($post_id)
  5. Vulnerability Sink: The code proceeds to parse $post->post_content without checking $post->post_status. It looks for blocks matching complianz/consent-area.
  6. Data Extraction: If a block matches the provided block_id, the value of the consentedContent attribute is returned in the JSON response.

4. Nonce Acquisition Strategy

According to the vulnerability description, the permission_callback is __return_true. This indicates that no WordPress nonce is required for this endpoint when accessed via a direct GET request.

If for any reason the environment requires a REST nonce (e.g., due to global security headers), it can be obtained from the homepage:

  1. Navigate to the homepage using browser_navigate.
  2. Execute browser_eval("window.wpApiSettings?.nonce").
  3. Note: This is likely unnecessary given the __return_true callback.

5. Exploitation Strategy

The goal is to retrieve content from a private post that contains a complianz/consent-area block.

Step 1: Discover Post IDs (Brute Force)

Since post IDs are incremental, an attacker can iterate through IDs. For the PoC, we will create a known post ID.

Step 2: Request the Content

  1. Send a GET request to the target endpoint.
  2. Tool: http_request
  3. URL: http://localhost:8080/wp-json/complianz/v1/consent-area/{post_id}/{block_id}
  4. Headers: Accept: application/json

6. Test Data Setup

To verify the vulnerability, we must create a private post containing the specific Gutenberg block structure used by Complianz.

WP-CLI Command:

# Create a private post with a Consent Area block
# Note: The blockId and consentedContent attributes are key.
wp post create --post_type=post \
               --post_status=private \
               --post_title="Secret Disclosure Test" \
               --post_content='<!-- wp:complianz/consent-area {"blockId":"exploit-id-123","consentedContent":"CENSORED_PRIVATE_TOKEN_9999"} --> <div class="cmplz-consent-area">Visible placeholder</div> <!-- /wp:complianz/consent-area -->'

Note the resulting ID from the command output.

7. Expected Results

  • Success: The REST API returns a 200 OK response with a JSON body containing the consentedContent.
  • Payload Response Example:
{
    "consentedContent": "CENSORED_PRIVATE_TOKEN_9999"
}
  • Failure (Patched): The API returns a 403 Forbidden or 401 Unauthorized if the post is private and the user is unauthenticated.

8. Verification Steps

  1. Identify ID: Run wp post list --post_status=private to get the ID of the post created in Step 6.
  2. Execute Exploit: Use http_request to fetch the REST endpoint.
  3. Compare: Verify the string returned in the JSON matches the consentedContent string defined in the WP-CLI setup.
  4. Check Permissions: Verify that visiting the post URL directly (/?p=ID) as an unauthenticated user results in a 404 or a login prompt, proving the post is indeed private and otherwise inaccessible.

9. Alternative Approaches

If the block_id used in the URL is not the blockId attribute but rather a numeric index or a different hash:

  1. Brute Force/Inference: Use the browser_eval tool on the private post (while logged in as admin) to inspect the Gutenberg block attributes: wp.data.select('core/block-editor').getBlocks().
  2. Block ID discovery: Check if the plugin leaks block IDs in any other public endpoints or if they are predictable (e.g., based on post ID). However, for a PoC, the manually defined blockId in the Gutenberg comment is the standard target.

Check if your site is affected.

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