CVE-2026-32359

Icon List Block <= 1.2.3 - Authenticated (Contributor+) Stored Cross-Site Scripting

mediumImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
6.4
CVSS Score
6.4
CVSS Score
medium
Severity
1.2.4
Patched in
60d
Time to patch

Description

The Icon List Block plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 1.2.3 due to insufficient input sanitization and output escaping. 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.2.3
PublishedFebruary 15, 2026
Last updatedApril 15, 2026
Affected pluginicon-list-block

What Changed in the Fix

Changes introduced in v1.2.4

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-32359 (Icon List Block) ## 1. Vulnerability Summary The **Icon List Block** plugin (<= 1.2.3) is vulnerable to **Stored Cross-Site Scripting (XSS)**. The vulnerability exists because the plugin allows users with Contributor-level permissions or higher to creat…

Show full research plan

Exploitation Research Plan: CVE-2026-32359 (Icon List Block)

1. Vulnerability Summary

The Icon List Block plugin (<= 1.2.3) is vulnerable to Stored Cross-Site Scripting (XSS). The vulnerability exists because the plugin allows users with Contributor-level permissions or higher to create Gutenberg blocks where specific attributes are stored without sufficient sanitization.

When the block is rendered on the frontend, the build/render.php file outputs the block's attributes into a data-attributes attribute of a wrapper div. A corresponding frontend JavaScript file (implied by build/view.asset.php) then parses this JSON data and renders it into the DOM. The failure occurs in this frontend rendering phase, where the data is likely inserted using an unsafe method (like jQuery's .html() or native .innerHTML) without escaping.

2. Attack Vector Analysis

  • Endpoint: WordPress REST API for Posts (/wp-json/wp/v2/posts) or the standard Post Editor.
  • Vulnerable Block: icon-list-block/icon-list (inferred from plugin slug and render.php).
  • Vulnerable Parameter: Block attributes, specifically item text/labels within the list.
  • Authentication Level: Contributor or higher. Contributors can create posts and insert any registered block.
  • Preconditions: The plugin must be active, and a post containing the malicious block must be viewed by a user (e.g., an Admin reviewing a "Pending" post).

3. Code Flow

  1. Entry Point (Editor): A Contributor creates or edits a post. They add an "Icon List Block".
  2. Storage: The Gutenberg editor sends the block's attributes as JSON within the post_content (wrapped in HTML comments).
  3. Frontend Rendering (PHP): When a user views the post, WordPress executes build/render.php:
    • get_block_wrapper_attributes() generates classes/IDs.
    • wp_json_encode($attributes) serializes the user-controlled attributes.
    • esc_attr() escapes the JSON string for use in the HTML attribute.
    • Result: <div ... data-attributes='{"items":[{"text":"<img src=x onerror=alert(1)>"}]}'></div>
  4. Frontend Execution (JS): The script defined in build/view.js (referenced by build/view.asset.php) executes:
    • It selects the div by ID (e.g., ilbIconList-...).
    • It reads the data-attributes value.
    • It parses the JSON.
    • Sink: It iterates through the items and inserts the text or label value into the DOM using an unsafe sink (e.g., element.innerHTML = item.text), triggering the XSS.

4. Nonce Acquisition Strategy

While saving a post via the REST API requires a _wpnonce, the agent can simplify the exploit by using the browser to manipulate the block editor directly or by extracting the REST nonce from a loaded admin page.

  1. Identify Nonce: Navigate to /wp-admin/post-new.php.
  2. Extract: Use browser_eval to get the REST nonce:
    window.wpApiSettings.nonce
    
  3. Identify Block Name: Use browser_eval to confirm the block name:
    wp.blocks.getBlockTypes().map(b => b.name).filter(n => n.includes('icon-list'))
    
    Result likely: icon-list-block/icon-list or ilb/icon-list.

5. Exploitation Strategy

The goal is to create a post containing the malicious block attributes.

Step 1: Create the Malicious Post

The agent will send a REST API request to create a post.

  • Method: POST
  • URL: /wp-json/wp/v2/posts
  • Headers:
    • Content-Type: application/json
    • X-WP-Nonce: [EXTRACTED_NONCE]
  • Body:
{
  "title": "XSS Proof of Concept",
  "status": "pending",
  "content": "<!-- wp:icon-list-block/icon-list {\"items\":[{\"label\":\"<img src=x onerror=alert(window.origin)>\",\"icon\":\"fa-check\"}]} /-->"
}

(Note: The attribute name label is inferred from typical Icon List structures. If label fails, text or content will be tried.)

Step 2: Trigger the XSS

The agent will navigate to the newly created post's frontend URL.

6. Test Data Setup

  1. User: Create a user with the contributor role.
  2. Login: Log in as the contributor.
  3. Verification Page: No special shortcode is needed as the block itself provides the rendering logic via render.php.

7. Expected Results

  • The HTTP response from the REST API should be 201 Created.
  • When navigating to the post URL, the browser should execute alert(window.origin).
  • The HTML source will show the payload inside the data-attributes attribute, and the JavaScript will have rendered it as a live DOM element.

8. Verification Steps

  1. Check DB: Use WP-CLI to verify the payload is stored:
    wp post list --post_type=post --format=csv | grep "XSS Proof of Concept"
    wp post get [POST_ID] --field=content
    
  2. Verify Execution: Use browser_eval to check if a specific global variable or side effect was created by the XSS payload (if alert is not capturable).

9. Alternative Approaches

  • Attribute Breakout: If the JS doesn't use innerHTML but instead sets other attributes, try breaking out of those: icon="fas fa-search' onmouseover='alert(1)".
  • Editor-Side XSS: Check if the XSS triggers inside the Gutenberg editor itself by navigating the contributor to the post edit screen after saving. This would be "Authenticated Stored XSS in Admin".
  • Shortcode Discovery: If the block name is different, use:
    grep -r "registerBlockType" wp-content/plugins/icon-list-block/
    
    to find the exact string.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Icon List Block plugin for WordPress is vulnerable to Stored Cross-Site Scripting via block attributes in versions up to 1.2.3. Authenticated attackers with contributor-level access can inject arbitrary web scripts into pages that execute when users access the affected content because the plugin fails to sanitize user-supplied attributes before they are rendered on the frontend.

Vulnerable Code

<?php
// build/render.php lines 1-7
$id = wp_unique_id('ilbIconList-');
?>
<div <?php echo wp_kses_post(get_block_wrapper_attributes()); ?> id='<?php echo esc_attr($id); ?>'
  data-attributes='<?php echo esc_attr(wp_json_encode($attributes)); ?>'>
</div>

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/icon-list-block/1.2.3/build/dashboard.asset.php /home/deploy/wp-safety.org/data/plugin-versions/icon-list-block/1.2.4/build/dashboard.asset.php
--- /home/deploy/wp-safety.org/data/plugin-versions/icon-list-block/1.2.3/build/dashboard.asset.php	2025-11-13 06:42:34.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/icon-list-block/1.2.4/build/dashboard.asset.php	2026-02-23 09:46:22.000000000 +0000
@@ -1 +1 @@
-<?php return array('dependencies' => array('react', 'react-dom', 'wp-blob', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-data', 'wp-i18n'), 'version' => '7eb3c45e9131037a27b2');
+<?php return array('dependencies' => array('react', 'react-dom', 'wp-blob', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-data', 'wp-i18n'), 'version' => 'da82bc6e38d00dd06749');

Exploit Outline

1. Authenticate as a user with Contributor-level access or higher. 2. Create a new post and insert an 'Icon List' block. 3. Using the block editor or the WordPress REST API (/wp-json/wp/v2/posts), set the block's attributes (such as 'label' or 'text' within the 'items' array) to include an XSS payload like `<img src=x onerror=alert(document.domain)>`. 4. Save the post as a draft or submit it for review. 5. When an administrator or any site visitor views the post, the frontend JavaScript parses the JSON data from the 'data-attributes' wrapper and injects the malicious content into the DOM using an unsafe sink (likely innerHTML), triggering the execution of the script.

Check if your site is affected.

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