PluginProbe
wpForo Forum / 3.1.6
wpForo Forum v3.1.6
3.1.6 3.1.5 3.1.4 3.1.2 3.1.1 3.1.0 3.0.9 3.0.8 3.0.7 trunk 1.0.0 1.0.1 1.0.2 1.1.0 1.1.1 1.1.2 1.2.0 1.3.0 1.3.1 1.4.0 1.4.1 1.4.10 1.4.11 1.4.12 1.4.13 All 138 releases
← All changes | classes/AIClient.php +40 -6 3.1.13.1.6 View file →
@@ -3596,8 +3596,11 @@
3596 3596
3597 3597 $wp_post = get_post( (int) $wp_post_id );
3598 3598 if ( ! $wp_post || $wp_post->post_status !== 'publish' ) continue;
3599 3599
3600 + // Skip password-protected posts unless user has entered the password
3601 + if ( post_password_required( $wp_post ) ) continue;
3602 +
3600 3603 // Use real WP post_type (post, page, product, etc.)
3601 3604 $post_type_obj = get_post_type_object( $wp_post->post_type );
3602 3605 $post_type_label = $post_type_obj ? $post_type_obj->labels->singular_name : ucfirst( $wp_post->post_type );
3603 3606
@@ -3872,8 +3875,21 @@
3872 3875
3873 3876 // Update total to reflect filtered results count
3874 3877 $filtered_total = count( $enriched_results );
3875 3878
3879 + // Sanitize AI enhancement output to prevent XSS
3880 + if ( $ai_enhancement ) {
3881 + if ( isset( $ai_enhancement['summary'] ) ) {
3882 + $ai_enhancement['summary'] = wpforo_kses( (string) $ai_enhancement['summary'] );
3883 + }
3884 + if ( isset( $ai_enhancement['quick_answer'] ) ) {
3885 + $ai_enhancement['quick_answer'] = wpforo_kses( (string) $ai_enhancement['quick_answer'] );
3886 + }
3887 + if ( isset( $ai_enhancement['recommendations_html'] ) ) {
3888 + $ai_enhancement['recommendations_html'] = wpforo_kses( (string) $ai_enhancement['recommendations_html'] );
3889 + }
3890 + }
3891 +
3876 3892 // Return enriched results with AI enhancement
3877 3893 wp_send_json_success( [
3878 3894 'results' => $enriched_results,
3879 3895 'total' => $filtered_total,
@@ -7083,8 +7099,15 @@
7083 7099 'message' => wpforo_phrase( 'Post not found', false )
7084 7100 ], 404 );
7085 7101 }
7086 7102
7103 + // SECURITY: Check if user can view this post before allowing translation
7104 + if ( ! WPF()->post->view_access( $post ) ) {
7105 + wp_send_json_error( [
7106 + 'message' => wpforo_phrase( 'You do not have permission to view this content', false )
7107 + ], 403 );
7108 + }
7109 +
7087 7110 // Get the rendered HTML content using output buffering
7088 7111 // (wpforo_content echoes instead of returning)
7089 7112 ob_start();
7090 7113 wpforo_content( $post );
@@ -7114,10 +7137,11 @@
7114 7137 'duration_ms' => (int) ( ( microtime( true ) - $_log_start_time ) * 1000 ),
7115 7138 ] );
7116 7139 }
7117 7140 // Return cached translation (no credits used)
7141 + // Sanitize AI output to prevent XSS - wpforo_kses allows all post-safe HTML tags
7118 7142 wp_send_json_success( [
7119 - 'translated_content' => wpfval( $cached_result, 'translated_content' ) ?: '',
7143 + 'translated_content' => wpforo_kses( (string) wpfval( $cached_result, 'translated_content' ) ),
7120 7144 'source_language' => wpfval( $cached_result, 'source_language' ) ?: 'auto',
7121 7145 'target_language' => $target_language,
7122 7146 'credits_used' => 0,
7123 7147 'cached' => true,
@@ -7173,10 +7197,11 @@
7173 7197 ];
7174 7198 $this->set_ai_cache( self::CACHE_TYPE_TRANSLATE, $cache_key, $cache_data, 0, $post_id );
7175 7199
7176 7200 // Return translated content
7201 + // Sanitize AI output to prevent XSS - wpforo_kses allows all post-safe HTML tags
7177 7202 wp_send_json_success( [
7178 - 'translated_content' => wpfval( $result, 'translated_content' ) ?: '',
7203 + 'translated_content' => wpforo_kses( (string) wpfval( $result, 'translated_content' ) ),
7179 7204 'source_language' => wpfval( $result, 'source_language' ) ?: 'auto',
7180 7205 'target_language' => $target_language,
7181 7206 'credits_used' => $credits_used,
7182 7207 'cached' => false,
@@ -7336,8 +7361,15 @@
7336 7361 'message' => wpforo_phrase( 'Topic not found', false )
7337 7362 ], 404 );
7338 7363 }
7339 7364
7365 + // SECURITY: Check if user can view this topic before allowing summarization
7366 + if ( ! WPF()->topic->view_access( $topic ) ) {
7367 + wp_send_json_error( [
7368 + 'message' => wpforo_phrase( 'You do not have permission to view this content', false )
7369 + ], 403 );
7370 + }
7371 +
7340 7372 // Get summary style from settings or request
7341 7373 $style = sanitize_text_field( wpfval( $_POST, 'style' ) );
7342 7374 if ( empty( $style ) ) {
7343 7375 $style = wpfval( WPF()->settings->ai, 'topic_summary_style' ) ?: 'detailed';
@@ -7446,13 +7478,14 @@
7446 7478 }
7447 7479
7448 7480 // Return cached summary (no credits used)
7449 7481 // Process link markers to convert [[#POST_ID]] to clickable links
7450 - $cached_summary = wpfval( $cached_result, 'summary' ) ?: '';
7482 + $cached_summary = (string) wpfval( $cached_result, 'summary' );
7451 7483 $cached_summary = $this->replace_summary_link_markers( $cached_summary, $topicid );
7452 7484
7485 + // Sanitize AI output to prevent XSS - wpforo_kses allows all post-safe HTML tags
7453 7486 wp_send_json_success( [
7454 - 'summary' => $cached_summary,
7487 + 'summary' => wpforo_kses( $cached_summary ),
7455 7488 'style' => wpfval( $cached_result, 'style' ) ?: $style,
7456 7489 'topic_id' => $topicid,
7457 7490 'reply_count' => $reply_count,
7458 7491 'total_posts_count' => $total_posts_count,
@@ -7491,9 +7524,9 @@
7491 7524 ], 500 );
7492 7525 }
7493 7526
7494 7527 // Get raw summary and store in cache (keep raw with link markers for re-processing)
7495 - $raw_summary = wpfval( $result, 'summary' ) ?: '';
7528 + $raw_summary = (string) wpfval( $result, 'summary' );
7496 7529 // Strip markdown code fence wrappers (```html ... ```) that LLMs sometimes add around HTML output
7497 7530 $raw_summary = preg_replace( '/^\s*```\w*\s*\n([\s\S]*?)\n\s*```\s*$/s', '$1', $raw_summary );
7498 7531 $credits_used = wpfval( $result, 'credits_used' ) ?: 1;
7499 7532
@@ -7524,10 +7557,11 @@
7524 7557 // Process link markers to convert [[#POST_ID]] to clickable links
7525 7558 $processed_summary = $this->replace_summary_link_markers( $raw_summary, $topicid );
7526 7559
7527 7560 // Return summary with clickable links
7561 + // Sanitize AI output to prevent XSS - wpforo_kses allows all post-safe HTML tags
7528 7562 wp_send_json_success( [
7529 - 'summary' => $processed_summary,
7563 + 'summary' => wpforo_kses( $processed_summary ),
7530 7564 'style' => wpfval( $result, 'style' ) ?: $style,
7531 7565 'topic_id' => $topicid,
7532 7566 'reply_count' => $reply_count,
7533 7567 'total_posts_count' => $total_posts_count,