diff --git a/wp-includes/default-filters.php b/wp-includes/default-filters.php index 5642829e56..531fd538e4 100644 --- a/wp-includes/default-filters.php +++ b/wp-includes/default-filters.php @@ -196,6 +196,8 @@ add_filter( 'nav_menu_meta_box_object', '_wp_nav_menu_meta_box_object' ); add_filter( 'pingback_ping_source_uri', 'pingback_ping_source_uri' ); add_filter( 'xmlrpc_pingback_error', 'xmlrpc_pingback_error' ); +add_filter( 'http_request_host_is_external', 'allowed_http_request_hosts', 10, 2 ); + // Actions add_action( 'wp_head', 'wp_enqueue_scripts', 1 ); add_action( 'wp_head', 'feed_links', 2 ); diff --git a/wp-includes/http.php b/wp-includes/http.php index 03edce8e88..59dfa55ce9 100644 --- a/wp-includes/http.php +++ b/wp-includes/http.php @@ -451,15 +451,16 @@ function wp_http_validate_url( $url ) { $ip = false; } if ( $ip ) { - if ( '127.0.0.1' === $ip ) - return false; $parts = array_map( 'intval', explode( '.', $ip ) ); - if ( 10 === $parts[0] ) - return false; - if ( 172 === $parts[0] && 16 <= $parts[1] && 31 >= $parts[1] ) - return false; - if ( 192 === $parts[0] && 168 === $parts[1] ) - return false; + if ( '127.0.0.1' === $ip + || ( 10 === $parts[0] ) + || ( 172 === $parts[0] && 16 <= $parts[1] && 31 >= $parts[1] ) + || ( 192 === $parts[0] && 168 === $parts[1] ) + ) { + // If host appears local, reject unless specifically allowed. + if ( ! apply_filters( 'http_request_host_is_external', false, $host, $url ) ) + return false; + } } } @@ -475,3 +476,44 @@ function wp_http_validate_url( $url ) { return false; } + +/** + * Whitelists allowed redirect hosts for safe HTTP requests as well. + * + * Attached to the http_request_host_is_external filter. + * + * @since 3.6.0 + * + * @param bool $is_external + * @param string $host + * @return bool + */ +function allowed_http_request_hosts( $is_external, $host ) { + if ( ! $is_external && wp_validate_redirect( 'http://' . $host ) ) + $is_external = true; + return $is_external; +} + +/** + * Whitelists any domain in a multisite installation for safe HTTP requests. + * + * Attached to the http_request_host_is_external filter. + * + * @since 3.6.0 + * + * @param bool $is_external + * @param string $host + * @return bool + */ +function ms_allowed_http_request_hosts( $is_external, $host ) { + global $wpdb, $current_site; + static $queried = array(); + if ( $is_external ) + return $is_external; + if ( $host === $current_site->domain ) + return true; + if ( isset( $queried[ $host ] ) ) + return $queried[ $host ]; + $queried[ $host ] = (bool) $wpdb->get_var( $wpdb->prepare( "SELECT domain FROM $wpdb->blogs WHERE domain = %s LIMIT 1", $host ) ); + return $queried[ $host ]; +} diff --git a/wp-includes/ms-default-filters.php b/wp-includes/ms-default-filters.php index 34dc151c44..c4c223a4f7 100644 --- a/wp-includes/ms-default-filters.php +++ b/wp-includes/ms-default-filters.php @@ -63,4 +63,7 @@ remove_filter( 'option_siteurl', '_config_wp_siteurl' ); remove_filter( 'option_home', '_config_wp_home' ); // If the network upgrade hasn't run yet, assume ms-files.php rewriting is used. -add_filter( 'default_site_option_ms_files_rewriting', '__return_true' ); \ No newline at end of file +add_filter( 'default_site_option_ms_files_rewriting', '__return_true' ); + +// Whitelist multisite domains for HTTP requests +add_filter( 'http_request_host_is_external', 'ms_allowed_http_request_hosts', 20, 2 );