| @@ -394,8 +394,9 @@ | ||
| 394 | 394 | |
| 395 | 395 | /** |
| 396 | 396 | * Retrieves a single donor from the database |
| 397 | 397 | * |
| 398 | + * @since 4.16.8.1 Reject an email lookup value that sanitize_text_field() would rewrite, instead of matching against the rewritten form. | |
| 398 | 399 | * @since 1.0 |
| 399 | 400 | * @access public |
| 400 | 401 | * |
| 401 | 402 | * @param string $field ID or email. Default is 'id'. |
| @@ -403,9 +404,10 @@ | ||
| 403 | 404 | * |
| 404 | 405 | * @return mixed Upon success, an object of the donor. Upon failure, NULL |
| 405 | 406 | */ |
| 406 | 407 | public function get_donor_by( $field = 'id', $value = 0 ) { |
| 407 | - $value = sanitize_text_field( $value ); | |
| 408 | + $submitted_value = is_string( $value ) ? trim( $value ) : $value; | |
| 409 | + $value = sanitize_text_field( $value ); | |
| 408 | 410 | |
| 409 | 411 | // Bailout. |
| 410 | 412 | if ( empty( $field ) || empty( $value ) ) { |
| 411 | 413 | return null; |
| @@ -429,8 +431,17 @@ | ||
| 429 | 431 | if ( ! is_email( $value ) ) { |
| 430 | 432 | return false; |
| 431 | 433 | } |
| 432 | 434 | |
| 435 | + // The column this looks up is unique on its raw, stored bytes. Matching | |
| 436 | + // against a form that sanitize_text_field() rewrote (e.g. by removing | |
| 437 | + // percent-hex sequences) would compare a different string than what is | |
| 438 | + // actually stored, letting one row's raw value resolve to another row's | |
| 439 | + // plain value. Require the two to already agree. | |
| 440 | + if ( $value !== $submitted_value ) { | |
| 441 | + return false; | |
| 442 | + } | |
| 443 | + | |
| 433 | 444 | $value = trim( $value ); |
| 434 | 445 | } |
| 435 | 446 | |
| 436 | 447 | // Bailout |
| @@ -487,14 +498,20 @@ | ||
| 487 | 498 | * |
| 488 | 499 | * Note: This function is for internal purposes only. Don't use this function as it will be deprecated soon. |
| 489 | 500 | * |
| 490 | 501 | * @param int $id Email Access Token ID. |
| 491 | - * | |
| 502 | + * @since 4.16.6 Require a non-empty, scalar string token before querying. | |
| 492 | 503 | * @since 2.3.1 |
| 493 | 504 | * |
| 494 | 505 | * @return object |
| 495 | 506 | */ |
| 496 | 507 | public function get_donor_by_token( $id ) { |
| 508 | + // Require a non-empty, scalar string token: every donor row defaults to | |
| 509 | + // verify_key = '' until they request their own access link. | |
| 510 | + if ( ! is_string( $id ) || '' === $id ) { | |
| 511 | + return null; | |
| 512 | + } | |
| 513 | + | |
| 497 | 514 | global $wpdb; |
| 498 | 515 | $row = $wpdb->get_row( |
| 499 | 516 | $wpdb->prepare( "SELECT * FROM {$wpdb->donors} WHERE verify_key = %s LIMIT 1", $id ) |
| 500 | 517 | ); |