| @@ -262,8 +262,9 @@ | ||
| 262 | 262 | public static function where( $meta_key, $meta_value ) { |
| 263 | 263 | $args = array( |
| 264 | 264 | 'post_type' => ( new static() )->get_post_type(), |
| 265 | 265 | 'post_status' => static::$accepted_statuses, |
| 266 | + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Meta query is necessary for filtering posts by meta fields | |
| 266 | 267 | 'meta_query' => array( |
| 267 | 268 | array( |
| 268 | 269 | 'key' => $meta_key, |
| 269 | 270 | 'value' => $meta_value, |
| @@ -513,17 +514,17 @@ | ||
| 513 | 514 | } |
| 514 | 515 | |
| 515 | 516 | $value = $this->$key; |
| 516 | 517 | |
| 517 | - // Unserialize if necessary | |
| 518 | + // Unserialize if necessary (object instantiation disallowed — see helper). | |
| 518 | 519 | if ( is_string( $value ) && $this->is_serialized( $value ) ) { |
| 519 | - $value = maybe_unserialize( $value ); | |
| 520 | + $value = \booktics_safe_maybe_unserialize( $value ); | |
| 520 | 521 | } |
| 521 | 522 | |
| 522 | 523 | // Normalize value to default type |
| 523 | 524 | if ( gettype( $value ) !== gettype( $default ) ) { |
| 524 | 525 | if ( gettype( $default ) === 'array' && is_string( $value ) && $this->is_serialized( $value ) ) { |
| 525 | - $value = maybe_unserialize( $value ); | |
| 526 | + $value = \booktics_safe_maybe_unserialize( $value ); | |
| 526 | 527 | } elseif ( gettype( $default ) === 'array' ) { |
| 527 | 528 | $value = $default; // Set to default empty array if the value doesn't match |
| 528 | 529 | } |
| 529 | 530 | } |
| @@ -577,21 +578,10 @@ | ||
| 577 | 578 | * |
| 578 | 579 | * @return bool True if the data is serialized, false otherwise. |
| 579 | 580 | */ |
| 580 | 581 | protected function is_serialized( $data ) { |
| 581 | - // If it isn't a string, return false | |
| 582 | - if ( ! is_string( $data ) ) { | |
| 583 | - return false; | |
| 584 | - } | |
| 585 | - | |
| 586 | - // Check if it's a serialized string (Array or Object) | |
| 587 | - $data = trim( $data ); | |
| 588 | - | |
| 589 | - if ( 'N;' === $data || ! preg_match( '/^([adObis]):/', $data ) ) { | |
| 590 | - return false; | |
| 591 | - } | |
| 592 | - | |
| 593 | - $result = @unserialize( $data ); | |
| 594 | - | |
| 595 | - return $result !== false || $data === 'b:0;'; // Return false for failed unserialization and true for successful | |
| 582 | + // Use WordPress core's purely structural check. Unlike the previous | |
| 583 | + // implementation, \is_serialized() never calls unserialize(), so testing | |
| 584 | + // attacker-controlled meta can no longer trigger PHP Object Injection. | |
| 585 | + return is_string( $data ) && \is_serialized( $data ); | |
| 596 | 586 | } |
| 597 | 587 | } |