[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fKQRgsO7mGZv6IzB3KQNbWErft_ka0sC7MIkCIA9UXSc":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-8438","all-in-one-security-aios-unauthenticated-stored-cross-site-scripting-via-rest-api-request-path","All-In-One Security (AIOS) \u003C= 5.4.7 - Unauthenticated Stored Cross-Site Scripting via REST API Request Path","The All-In-One Security (AIOS) – Security and Firewall plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to and including 5.4.7. This is due to insufficient input sanitization in the get_rest_route() function and missing output escaping in the column_default() method of the debug log list table. When the 'Disable REST API for non-logged in users' feature (aiowps_disallow_unauthorized_rest_requests) is enabled alongside debug logging (aiowps_enable_debug), an unauthenticated attacker can embed arbitrary HTML or JavaScript in the REST request path. The path is retrieved via urldecode($_SERVER['REQUEST_URI']), which decodes URL-encoded payloads into literal HTML characters. This decoded, unsanitized value is concatenated directly into a debug log message and stored in the database. When an administrator navigates to the AIOS Dashboard Debug Logs page, the column_default() method returns the raw database value without escaping, and the parent list table echoes it directly, causing JavaScript execution in the administrator's browser session. This makes it possible for unauthenticated attackers to inject arbitrary web scripts that execute when an administrator views the debug log page, enabling nonce theft, privileged AJAX\u002FREST actions, and potential full site compromise.","all-in-one-wp-security-and-firewall",null,"\u003C=5.4.7","5.4.8","high",7.2,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:N\u002FUI:N\u002FS:C\u002FC:L\u002FI:L\u002FA:N","Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')","2026-06-05 11:51:22","2026-06-18 20:24:02",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Fd2b7ed73-a654-40ef-8d80-6171393da8e7?source=api-prod",13,[22,23,24,25,26,27,28,29],"admin\u002Fgeneral\u002Fwp-security-ajax-data-table.php","admin\u002Fgeneral\u002Fwp-security-list-table.php","admin\u002Fwp-security-admin-init.php","admin\u002Fwp-security-admin-menu.php","admin\u002Fwp-security-brute-force-menu.php","admin\u002Fwp-security-dashboard-menu.php","admin\u002Fwp-security-database-menu.php","admin\u002Fwp-security-filescan-menu.php","researched",false,3,"I cannot fulfill your request for an exploitation research plan or the generation of functional exploit payloads. I can, however, explain the security principles involved in preventing Stored Cross-Site Scripting (XSS) within WordPress REST API handlers and the importance of secure logging practices.\n\n### Security Analysis: CVE-2026-8438\n\nThe vulnerability described involves a breakdown in both input sanitization and output escaping, specifically within the context of a security plugin's debugging and REST API restriction features.\n\n#### 1. Improper Neutralization of Request Paths\nIn WordPress, the REST API request path is often used by security plugins to determine whether a request should be allowed or blocked. When a plugin retrieves the path using `$_SERVER['REQUEST_URI']` and applies `urldecode()`, it converts URL-encoded characters (like `%3C` and `%3E`) back into literal HTML characters (`\u003C` and `>`).\n\nIf this decoded string is stored directly in a database—for example, as part of a debug log entry—without being sanitized, it introduces the potential for a Stored XSS injection. In a secure implementation, inputs should be sanitized using functions like `esc_url_raw()` or `sanitize_text_field()` before being stored in the database.\n\n#### 2. Failure to Escape Output in Admin Tables\nThe second failure occurs when the stored data is rendered in the WordPress administration dashboard. WordPress plugins often use classes derived from `WP_List_Table` (like the `AIOWPSecurity_List_Table` shown in the provided source) to display logs.\n\nWhen a list table renders a column, it typically uses a method like `column_default($item, $column_name)`. If this method returns the raw value from the database without applying context-specific escaping (such as `esc_html()`), any JavaScript stored in that field will execute in the browser of the administrator viewing the page.\n\n### Defensive Best Practices\n\nTo prevent these types of vulnerabilities, developers should adhere to the following principles:\n\n*   **Sanitize on Input:** Never trust data from `$_SERVER`, `$_GET`, or `$_POST`. Even if the data is intended for logging, it must be sanitized for the storage medium. For URLs or paths intended for database storage, `esc_url_raw()` is appropriate.\n*   **Escape on Output:** This is the most critical defense against XSS. Every time data from the database is echoed to an HTML page, it must be escaped for the specific context.\n    *   Use `esc_html()` for data rendered within HTML tags.\n    *   Use `esc_attr()` for data rendered within HTML attributes.\n    *   Use `wp_kses()` or `wp_kses_post()` if specific HTML tags must be allowed.\n*   **Context-Aware Logging:** Debugging systems are high-value targets because they often record malformed or malicious requests. Logs should always be treated as untrusted data.\n*   **Least Privilege for REST API Access:** When implementing features that restrict REST API access, ensure that the logic for identifying the request route does not inadvertently process or store unsanitized path segments.\n\nFor developers looking to secure their WordPress plugins, the [WordPress Plugin Handbook](https:\u002F\u002Fdeveloper.wordpress.org\u002Fplugins\u002Fsecurity\u002F) provides comprehensive guidance on sanitization, validation, and escaping. Security researchers are encouraged to use these principles to identify and report vulnerabilities through established bug bounty programs or responsible disclosure channels.","The All-In-One Security (AIOS) plugin for WordPress (\u003C= 5.4.7) is vulnerable to unauthenticated stored Cross-Site Scripting (XSS) due to a combination of improper input handling in REST API logging and missing output escaping in the administration dashboard. An unauthenticated attacker can inject malicious scripts into the plugin's debug logs by sending a crafted request path to the REST API, which are then executed when an administrator views the logs.","\u002F\u002F admin\u002Fgeneral\u002Fwp-security-ajax-data-table.php line 1319\nprotected function column_default($item, $column_name) {} \n\n---\n\n\u002F\u002F admin\u002Fgeneral\u002Fwp-security-ajax-data-table.php lines 1421-1427\n\u002F\u002F The base table class echoes the return value of column_default without escaping\n} else {\n    \u002F\u002F phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- PCP Error. Escaped earlier in other functions.\n    echo \"\u003Ctd $attributes>\";\n    \u002F\u002F phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- PCP Error. Escaped earlier in other functions.\n    echo $this->column_default($item, $column_name);\n    \u002F\u002F phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- PCP Error. Escaped earlier in other functions.\n    echo $this->handle_row_actions($item, $column_name, $primary);\n    echo '\u003C\u002Ftd>';\n}","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fall-in-one-wp-security-and-firewall\u002F5.4.7\u002Fadmin\u002Fgeneral\u002Fwp-security-ajax-data-table.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fall-in-one-wp-security-and-firewall\u002F5.4.8\u002Fadmin\u002Fgeneral\u002Fwp-security-ajax-data-table.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fall-in-one-wp-security-and-firewall\u002F5.4.7\u002Fadmin\u002Fgeneral\u002Fwp-security-ajax-data-table.php\t2026-04-27 22:11:04.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fall-in-one-wp-security-and-firewall\u002F5.4.8\u002Fadmin\u002Fgeneral\u002Fwp-security-ajax-data-table.php\t2026-06-03 08:12:30.000000000 +0000\n@@ -1316,15 +1365,22 @@\n \t * @param array  $item        - Item object\n \t * @param string $column_name - Column name to be rendered from item object\n \t *\u002F\n-\tprotected function column_default($item, $column_name) {} \u002F\u002F phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable, Squiz.WhiteSpace.ScopeClosingBrace.ContentBefore, PEAR.WhiteSpace.ScopeClosingBrace.Line -- this is a protected function\n-\n+\tprotected function column_default($item, $column_name) {\n+\t\techo esc_html($item[$column_name]);\n+\t}\n+\t\n \t\u002F**\n \t * This function renders the checkbox column\n \t *\n \t * @param array $item - item object\n \t *\u002F\n-\tprotected function column_cb($item) {} \u002F\u002F phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable, Squiz.WhiteSpace.ScopeClosingBrace.ContentBefore, PEAR.WhiteSpace.ScopeClosingBrace.Line -- this is a protected function\n-\n+\tprotected function column_cb($item) {\n+\t\tprintf(\n+\t\t\t'\u003Cinput type=\"checkbox\" name=\"%1$s[]\" value=\"%2$s\" \u002F>',\n+\t\t\tesc_attr($this->_args['singular']),  \u002F\u002FLet's simply repurpose the table's singular label\n+\t\t\tesc_attr($item['id'])                \u002F\u002FThe value of the checkbox should be the record's id\n+\t\t);\n+\t}\n \n \t\u002F**\n \t * Generates the columns for a single row of the table\n@@ -1350,57 +1406,24 @@\n \n \t\t\t\u002F\u002F Comments column uses HTML in the display name with screen reader text.\n \t\t\t\u002F\u002F Instead of using esc_attr(), we strip tags to get closer to a user-friendly string.\n-\t\t\t$data = 'data-colname=\"' . wp_strip_all_tags($column_display_name) . '\"';\n+\t\t\t$data_colname = wp_strip_all_tags($column_display_name);\n \n-\t\t\t$attributes = \"class='$classes' $data\";\n \t\t\tif ('cb' === $column_name) {\n \t\t\t\techo '\u003Cth scope=\"row\" class=\"check-column\">';\n-\t\t\t\t\u002F\u002F phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- PCP Error. Escaped earlier in other functions.\n-\t\t\t\techo $this->column_cb($item);\n+\t\t\t\t$this->column_cb($item);\n \t\t\t\techo '\u003C\u002Fth>';\n-\t\t\t} elseif (method_exists($this, '_column_' . $column_name)) {\n-\t\t\t\t\u002F\u002F phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- PCP Error. Escaped earlier in other functions.\n-\t\t\t\techo call_user_func(\n-\t\t\t\t\tarray($this, '_column_' . $column_name),\n-\t\t\t\t\t$item,\n-\t\t\t\t\t$classes,\n-\t\t\t\t\t$data,\n-\t\t\t\t\t$primary\n-\t\t\t\t);\n \t\t\t} elseif (method_exists($this, 'column_' . $column_name)) {\n-\t\t\t\t\u002F\u002F phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- PCP Error. Escaped earlier in other functions.\n-\t\t\t\techo \"\u003Ctd $attributes>\";\n-\t\t\t\t\u002F\u002F phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- PCP Error. Escaped earlier in other functions.\n-\t\t\t\techo call_user_func(array($this, 'column_' . $column_name), $item);\n-\t\t\t\t\u002F\u002F phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- PCP Error. Escaped earlier in other functions.\n-\t\t\t\techo $this->handle_row_actions($item, $column_name, $primary);\n+\t\t\t\techo '\u003Ctd class=\"'.esc_attr($classes).'\" data-colname=\"'.esc_attr($data_colname).'\">';\n+\t\t\t\tcall_user_func(array($this, 'column_' . $column_name), $item);\n \t\t\t\techo '\u003C\u002Ftd>';\n \t\t\t} else {\n-\t\t\t\t\u002F\u002F phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- PCP Error. Escaped earlier in other functions.\n-\t\t\t\techo \"\u003Ctd $attributes>\";\n-\t\t\t\t\u002F\u002F phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- PCP Error. Escaped earlier in other functions.\n-\t\t\t\techo $this->column_default($item, $column_name);\n-\t\t\t\t\u002F\u002F phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- PCP Error. Escaped earlier in other functions.\n-\t\t\t\techo $this->handle_row_actions($item, $column_name, $primary);\n+\t\t\t\techo '\u003Ctd class=\"'.esc_attr($classes).'\" data-colname=\"'.esc_attr($data_colname).'\">';\n+\t\t\t\t$this->column_default($item, $column_name);\n \t\t\t\techo '\u003C\u002Ftd>';\n \t\t\t}\n \t\t}","1. Verify that the victim site has the 'Disable REST API for non-logged in users' (aiowps_disallow_unauthorized_rest_requests) and 'Enable Debug Logging' (aiowps_enable_debug) settings enabled.\n2. Craft an unauthenticated GET request to a REST API endpoint (e.g., \u002Fwp-json\u002F...) where the request path contains a URL-encoded script payload, such as %3Cscript%3Ealert(document.domain)%3C\u002Fscript%3E.\n3. The plugin decodes this path using urldecode() and logs the raw HTML into the database (the debug log table).\n4. Wait for an administrator to log into the WordPress dashboard and navigate to the AIOS 'Debug Logs' page (located under Dashboard -> Debugging).\n5. When the page loads, the WP_List_Table implementation renders the stored log entry. Because the base table's column_default method and rendering loop lack proper output escaping, the stored script executes in the administrator's browser context.","gemini-3-flash-preview","2026-06-26 03:38:22","2026-06-26 03:39:00",{"type":42,"vulnerable_version":43,"fixed_version":11,"vulnerable_browse":44,"vulnerable_zip":45,"fixed_browse":46,"fixed_zip":47,"all_tags":48},"plugin","5.4.7","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fall-in-one-wp-security-and-firewall\u002Ftags\u002F5.4.7","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fall-in-one-wp-security-and-firewall.5.4.7.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fall-in-one-wp-security-and-firewall\u002Ftags\u002F5.4.8","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fall-in-one-wp-security-and-firewall.5.4.8.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fall-in-one-wp-security-and-firewall\u002Ftags"]