| @@ -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, |