PluginProbe
WPBot – AI ChatBot for Live Support, Lead Generation, WordPress Automation, AI Services / 8.7.6
WPBot – AI ChatBot for Live Support, Lead Generation, WordPress Automation, AI Services v8.7.6
8.7.6 8.7.5 8.7.4 8.7.3 8.7.2 8.7.1 8.7.0 8.6.9 8.6.8 8.6.7 8.6.6 8.6.5 8.6.4 8.6.2 8.6.1 8.6.0 8.5.9 8.5.8 8.5.7 8.5.6 8.5.5 8.5.4 8.5.3 8.5.2 8.5.0 All 532 releases
← All changes | functions.php +57 -4 8.7.28.7.6 View file →
@@ -1935,14 +1935,67 @@
1935 1935 }
1936 1936
1937 1937 }
1938 1938
1939 +/**
1940 + * Safely sanitize chatbot conversation input.
1941 + *
1942 + * SECURITY FIX (CVE WPBot Stored XSS ≤ 8.6.9):
1943 + * The previous order was: wp_kses() → html_entity_decode() → htmlspecialchars().
1944 + * An attacker could submit entity-encoded payloads (<img onerror=...>) that
1945 + * bypassed wp_kses (which saw inert text), were then decoded back into live markup
1946 + * by html_entity_decode(), and survived into storage and the admin UI.
1947 + *
1948 + * Correct order: html_entity_decode() FIRST → wp_kses() → htmlspecialchars().
1949 + * wp_kses() now sees the real decoded markup and strips forbidden tags/attributes.
1950 + *
1951 + * @param string $data Raw conversation string (already wp_unslash'd by caller).
1952 + * @return string Sanitized, entity-encoded string safe for DB storage.
1953 + */
1939 1954 function qcld_wpbot_input_validation( $data ) {
1940 - $data = html_entity_decode($data);
1941 - $data = trim($data);
1942 - $data = stripslashes($data);
1943 - $data = htmlspecialchars($data);
1955 + // 1. Decode any entity-encoded HTML so wp_kses sees the real markup.
1956 + $data = html_entity_decode( $data, ENT_QUOTES | ENT_HTML5, 'UTF-8' );
1957 + $data = trim( $data );
1958 + $data = stripslashes( $data );
1959 + // 2. Sanitize with a strict allowlist — NOW operating on decoded markup.
1960 + $data = wp_kses( $data, wpbot_get_safe_conversation_tags() );
1961 + // 3. Re-encode for safe DB storage; admin.js decodes for rendering.
1962 + $data = htmlspecialchars( $data, ENT_QUOTES | ENT_HTML5, 'UTF-8' );
1944 1963 return $data;
1964 +}
1965 +
1966 +/**
1967 + * Returns the strict HTML allowlist for chatbot conversation content.
1968 + *
1969 + * Critically: no event-handler attributes (onerror, onclick, onload, etc.) are
1970 + * allowed — wp_kses strips any attribute not explicitly listed here.
1971 + * 'img' is intentionally omitted; bot responses that include images should use
1972 + * safe URLs only and can be re-added with only 'src', 'alt', 'class' if needed.
1973 + *
1974 + * @return array<string, array<string, bool>>
1975 + */
1976 +function wpbot_get_safe_conversation_tags() {
1977 + return array(
1978 + 'ul' => array( 'class' => true ),
1979 + 'ol' => array( 'class' => true ),
1980 + 'li' => array( 'class' => true, 'id' => true ),
1981 + 'div' => array( 'class' => true, 'id' => true ),
1982 + 'span' => array( 'class' => true, 'id' => true ),
1983 + 'p' => array( 'class' => true ),
1984 + 'br' => array(),
1985 + 'strong' => array(),
1986 + 'em' => array(),
1987 + 'b' => array(),
1988 + 'i' => array(),
1989 + 'a' => array(
1990 + 'href' => true,
1991 + 'target' => true,
1992 + 'rel' => true,
1993 + 'class' => true,
1994 + ),
1995 + // 'img' intentionally excluded — prevents onerror/onload injection.
1996 + // Add back with only 'src','alt','class' if bot image responses are needed.
1997 + );
1945 1998 }
1946 1999 add_action('wp_ajax_qcld_small_talk_import', 'qcld_small_talk_import');
1947 2000 function qcld_small_talk_import(){
1948 2001 if ( ! current_user_can( 'manage_options' ) ) {