| @@ -27,9 +27,18 @@ | ||
| 27 | 27 | * |
| 28 | 28 | * @return string Canonical URL rebuilt from the validated components, or an empty string when the URL is not allowed. |
| 29 | 29 | */ |
| 30 | 30 | function get_validated_script_url( $url ) { |
| 31 | - if ( ! is_string( $url ) || str_contains( $url, '\\' ) ) { | |
| 31 | + if ( ! is_string( $url ) ) { | |
| 32 | + return ''; | |
| 33 | + } | |
| 34 | + | |
| 35 | + // A link whose query separators are HTML-encoded parses as `amp;`-prefixed parameter | |
| 36 | + // names and fails the allowlist below. The decode table cannot produce a path or | |
| 37 | + // authority delimiter, so normalizing here does not widen what is accepted. | |
| 38 | + $url = wp_specialchars_decode( $url ); | |
| 39 | + | |
| 40 | + if ( str_contains( $url, '\\' ) ) { | |
| 32 | 41 | return ''; |
| 33 | 42 | } |
| 34 | 43 | |
| 35 | 44 | $parsed = wp_parse_url( esc_url_raw( $url, array( 'https' ) ) ); |