| @@ -374,9 +374,11 @@ | ||
| 374 | 374 | if( in_array( $field['type'], [ 'text', 'textarea', 'email', 'search', 'tel' ] ) ) { |
| 375 | 375 | foreach( $value as $v ) $wheres[] = "`metavalue` LIKE '%" . esc_sql( wp_unslash( $v ) ) . "%'"; |
| 376 | 376 | } elseif( $field['type'] === 'checkbox' || ( $field['type'] === 'select' && wpfval( $field, 'isMultiChoice' ) ) || ( $field['type'] === 'autocomplete' && wpfval( $field, 'isMultiChoice' ) ) ) { |
| 377 | 377 | foreach( $value as $v ) { |
| 378 | - $v = preg_quote( preg_quote( wp_unslash( $v ) ) ); | |
| 378 | + // esc_sql() neutralizes SQL quotes/backslashes; preg_quote keeps the value a regex literal. | |
| 379 | + // Without esc_sql an apostrophe breaks out of the REGEXP string literal (unauthenticated SQLi). | |
| 380 | + $v = esc_sql( preg_quote( preg_quote( wp_unslash( $v ) ) ) ); | |
| 379 | 381 | $wheres[] = "`metavalue` REGEXP '[\\\[,]\"" . $v . "\"[,\\\]]'"; |
| 380 | 382 | } |
| 381 | 383 | } else { |
| 382 | 384 | foreach( $value as $v ) $wheres[] = "`metavalue` LIKE '" . esc_sql( wp_unslash( $v ) ) . "'"; |
| @@ -533,11 +535,12 @@ | ||
| 533 | 535 | if( ! empty( $topic['postmetas'] ) ) { |
| 534 | 536 | $fields_list = WPF()->post->get_topic_fields_list( false, $forum, ! WPF()->current_userid ); |
| 535 | 537 | foreach( $topic['postmetas'] as $metakey => $metavalue ) { |
| 536 | 538 | if( in_array( $metakey, $fields_list ) ) { |
| 537 | - // Security: Only accept array values for file-type fields to prevent file path injection | |
| 539 | + // Security: drop array values from single-value field types. | |
| 540 | + $multi_value_types = apply_filters( 'wpforo_postmeta_array_field_types', [ 'file', 'checkbox', 'multiselect', 'tags', 'secondary_groups' ] ); | |
| 538 | 541 | $field = WPF()->post->get_field( $metakey, 'topic', $forum ); |
| 539 | - if( is_array( $metavalue ) && wpfval( $field, 'type' ) !== 'file' ) continue; | |
| 542 | + if( is_array( $metavalue ) && ! in_array( (string) wpfval( $field, 'type' ), $multi_value_types, true ) ) continue; | |
| 540 | 543 | $postmeta = [ |
| 541 | 544 | 'postid' => $topic['first_postid'], |
| 542 | 545 | 'metakey' => $metakey, |
| 543 | 546 | 'metavalue' => $metavalue, |
| @@ -559,11 +562,12 @@ | ||
| 559 | 562 | if( ! empty( $args['postmetas'] ) ) { |
| 560 | 563 | $fields_list = WPF()->post->get_topic_fields_list( false, $forum, ! WPF()->current_userid ); |
| 561 | 564 | foreach( $args['postmetas'] as $metakey => $metavalue ) { |
| 562 | 565 | if( in_array( $metakey, $fields_list ) ) { |
| 563 | - // Security: Only accept array values for file-type fields to prevent file path injection | |
| 566 | + // Security: drop array values from single-value field types. | |
| 567 | + $multi_value_types = apply_filters( 'wpforo_postmeta_array_field_types', [ 'file', 'checkbox', 'multiselect', 'tags', 'secondary_groups' ] ); | |
| 564 | 568 | $field = WPF()->post->get_field( $metakey, 'topic', $forum ); |
| 565 | - if( is_array( $metavalue ) && wpfval( $field, 'type' ) !== 'file' ) continue; | |
| 569 | + if( is_array( $metavalue ) && ! in_array( (string) wpfval( $field, 'type' ), $multi_value_types, true ) ) continue; | |
| 566 | 570 | $postmeta = [ |
| 567 | 571 | 'metavalue' => $metavalue, |
| 568 | 572 | 'forumid' => $topic['forumid'], |
| 569 | 573 | 'topicid' => $topic['topicid'], |
| @@ -592,11 +596,12 @@ | ||
| 592 | 596 | if( ! empty( $post['postmetas'] ) ) { |
| 593 | 597 | $fields_list = WPF()->post->get_post_fields_list( false, $forum, ! WPF()->current_userid ); |
| 594 | 598 | foreach( $post['postmetas'] as $metakey => $metavalue ) { |
| 595 | 599 | if( in_array( $metakey, $fields_list ) ) { |
| 596 | - // Security: Only accept array values for file-type fields to prevent file path injection | |
| 600 | + // Security: drop array values from single-value field types. | |
| 601 | + $multi_value_types = apply_filters( 'wpforo_postmeta_array_field_types', [ 'file', 'checkbox', 'multiselect', 'tags', 'secondary_groups' ] ); | |
| 597 | 602 | $field = WPF()->post->get_field( $metakey, 'post', $forum ); |
| 598 | - if( is_array( $metavalue ) && wpfval( $field, 'type' ) !== 'file' ) continue; | |
| 603 | + if( is_array( $metavalue ) && ! in_array( (string) wpfval( $field, 'type' ), $multi_value_types, true ) ) continue; | |
| 599 | 604 | $postmeta = [ |
| 600 | 605 | 'postid' => $post['postid'], |
| 601 | 606 | 'metakey' => $metakey, |
| 602 | 607 | 'metavalue' => $metavalue, |
| @@ -618,11 +623,12 @@ | ||
| 618 | 623 | if( ! empty( $args['postmetas'] ) ) { |
| 619 | 624 | $fields_list = WPF()->post->get_post_fields_list( false, $forum, ! WPF()->current_userid ); |
| 620 | 625 | foreach( $args['postmetas'] as $metakey => $metavalue ) { |
| 621 | 626 | if( in_array( $metakey, $fields_list ) ) { |
| 622 | - // Security: Only accept array values for file-type fields to prevent file path injection | |
| 627 | + // Security: drop array values from single-value field types. | |
| 628 | + $multi_value_types = apply_filters( 'wpforo_postmeta_array_field_types', [ 'file', 'checkbox', 'multiselect', 'tags', 'secondary_groups' ] ); | |
| 623 | 629 | $field = WPF()->post->get_field( $metakey, 'post', $forum ); |
| 624 | - if( is_array( $metavalue ) && wpfval( $field, 'type' ) !== 'file' ) continue; | |
| 630 | + if( is_array( $metavalue ) && ! in_array( (string) wpfval( $field, 'type' ), $multi_value_types, true ) ) continue; | |
| 625 | 631 | $postmeta = [ |
| 626 | 632 | 'metavalue' => $metavalue, |
| 627 | 633 | 'forumid' => $post['forumid'], |
| 628 | 634 | 'topicid' => $post['topicid'], |