From b2b4e41fcb67b757d6c01c8053c206b636d6863b Mon Sep 17 00:00:00 2001 From: audrasjb Date: Thu, 12 Oct 2023 13:26:24 +0000 Subject: [PATCH] Application Passwords: Prevent the use of some pseudo protocols in application passwords. Props tykoted, xknown, peterwilsoncc, jorbin, timothyblynjacobs, martinkrcho, paulkevan, dd32, ehtis. Merges [56837] to the 6.3 branch. Built from https://develop.svn.wordpress.org/branches/6.3@56844 git-svn-id: http://core.svn.wordpress.org/branches/6.3@56356 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-admin/includes/user.php | 82 +++++++++++++++++++++++++++++++------- wp-includes/version.php | 2 +- 2 files changed, 69 insertions(+), 15 deletions(-) diff --git a/wp-admin/includes/user.php b/wp-admin/includes/user.php index 1d2d919348..1903ec1c59 100644 --- a/wp-admin/includes/user.php +++ b/wp-admin/includes/user.php @@ -636,6 +636,7 @@ Please click the following link to activate your user account: * * @since 5.6.0 * @since 6.2.0 Allow insecure HTTP connections for the local environment. + * @since 6.3.2 Validates the success and reject URLs to prevent javascript pseudo protocol being executed. * * @param array $request { * The array of request data. All arguments are optional and may be empty. @@ -649,27 +650,24 @@ Please click the following link to activate your user account: * @return true|WP_Error True if the request is valid, a WP_Error object contains errors if not. */ function wp_is_authorize_application_password_request_valid( $request, $user ) { - $error = new WP_Error(); - $is_local = 'local' === wp_get_environment_type(); + $error = new WP_Error(); - if ( ! empty( $request['success_url'] ) ) { - $scheme = wp_parse_url( $request['success_url'], PHP_URL_SCHEME ); - - if ( 'http' === $scheme && ! $is_local ) { + if ( isset( $request['success_url'] ) ) { + $validated_success_url = wp_is_authorize_application_redirect_url_valid( $request['success_url'] ); + if ( is_wp_error( $validated_success_url ) ) { $error->add( - 'invalid_redirect_scheme', - __( 'The success URL must be served over a secure connection.' ) + $validated_success_url->get_error_code(), + $validated_success_url->get_error_message() ); } } - if ( ! empty( $request['reject_url'] ) ) { - $scheme = wp_parse_url( $request['reject_url'], PHP_URL_SCHEME ); - - if ( 'http' === $scheme && ! $is_local ) { + if ( isset( $request['reject_url'] ) ) { + $validated_reject_url = wp_is_authorize_application_redirect_url_valid( $request['reject_url'] ); + if ( is_wp_error( $validated_reject_url ) ) { $error->add( - 'invalid_redirect_scheme', - __( 'The rejection URL must be served over a secure connection.' ) + $validated_reject_url->get_error_code(), + $validated_reject_url->get_error_message() ); } } @@ -698,3 +696,59 @@ function wp_is_authorize_application_password_request_valid( $request, $user ) { return true; } + +/** + * Validates the redirect URL protocol scheme. The protocol can be anything except http and javascript. + * + * @since 6.3.2 + * + * @param string $url - The redirect URL to be validated. + * + * @return true|WP_Error True if the redirect URL is valid, a WP_Error object otherwise. + */ +function wp_is_authorize_application_redirect_url_valid( $url ) { + $bad_protocols = array( 'javascript', 'data' ); + if ( empty( $url ) ) { + return true; + } + + // Based on https://www.rfc-editor.org/rfc/rfc2396#section-3.1 + $valid_scheme_regex = '/^[a-zA-Z][a-zA-Z0-9+.-]*:/'; + if ( ! preg_match( $valid_scheme_regex, $url ) ) { + return new WP_Error( + 'invalid_redirect_url_format', + __( 'Invalid URL format.' ) + ); + } + + /** + * Filters the list of invalid protocols used in applications redirect URLs. + * + * @since 6.3.2 + * + * @param string[] $bad_protocols Array of invalid protocols. + * @param string $url The redirect URL to be validated. + */ + $invalid_protocols = array_map( 'strtolower', apply_filters( 'wp_authorize_application_redirect_url_invalid_protocols', $bad_protocols, $url ) ); + + $scheme = wp_parse_url( $url, PHP_URL_SCHEME ); + $host = wp_parse_url( $url, PHP_URL_HOST ); + $is_local = 'local' === wp_get_environment_type(); + + // validates if the proper URI format is applied to the $url + if ( empty( $host ) || empty( $scheme ) || in_array( strtolower( $scheme ), $invalid_protocols, true ) ) { + return new WP_Error( + 'invalid_redirect_url_format', + __( 'Invalid URL format.' ) + ); + } + + if ( 'http' === $scheme && ! $is_local ) { + return new WP_Error( + 'invalid_redirect_scheme', + __( 'The URL must be served over a secure connection.' ) + ); + } + + return true; +} diff --git a/wp-includes/version.php b/wp-includes/version.php index 9d0bd1da46..fcfabeaf57 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -16,7 +16,7 @@ * * @global string $wp_version */ -$wp_version = '6.3.2-RC1-56843'; +$wp_version = '6.3.2-RC1-56844'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.