From 4de91b58942e6194e9b2747e56d5902682c9c630 Mon Sep 17 00:00:00 2001 From: audrasjb Date: Thu, 12 Oct 2023 13:30:23 +0000 Subject: [PATCH] Shortcodes: Restrict ajax handler for media shortcode. Props tykoted, xknown, peterwilsoncc, antpb, jorbin. Merges [56838] to the 6.3 branch. Built from https://develop.svn.wordpress.org/branches/6.3@56846 git-svn-id: http://core.svn.wordpress.org/branches/6.3@56358 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-admin/includes/ajax-actions.php | 18 +++++++++++++- wp-includes/media.php | 22 +++++++++++++++++ wp-includes/shortcodes.php | 38 ++++++++++++++++++++++++++++++ wp-includes/version.php | 2 +- 4 files changed, 78 insertions(+), 2 deletions(-) diff --git a/wp-admin/includes/ajax-actions.php b/wp-admin/includes/ajax-actions.php index 3c5dab31b5..29eeb7dd97 100644 --- a/wp-admin/includes/ajax-actions.php +++ b/wp-admin/includes/ajax-actions.php @@ -3882,13 +3882,29 @@ function wp_ajax_parse_media_shortcode() { $shortcode = wp_unslash( $_POST['shortcode'] ); + // Only process previews for media related shortcodes: + $found_shortcodes = get_shortcode_tags_in_content( $shortcode ); + $media_shortcodes = array( + 'audio', + 'embed', + 'playlist', + 'video', + 'gallery', + ); + + $other_shortcodes = array_diff( $found_shortcodes, $media_shortcodes ); + + if ( ! empty( $other_shortcodes ) ) { + wp_send_json_error(); + } + if ( ! empty( $_POST['post_ID'] ) ) { $post = get_post( (int) $_POST['post_ID'] ); } // The embed shortcode requires a post. if ( ! $post || ! current_user_can( 'edit_post', $post->ID ) ) { - if ( 'embed' === $shortcode ) { + if ( in_array( 'embed', $found_shortcodes, true ) ) { wp_send_json_error(); } } else { diff --git a/wp-includes/media.php b/wp-includes/media.php index 56f2a25c78..bb27476fde 100644 --- a/wp-includes/media.php +++ b/wp-includes/media.php @@ -2605,6 +2605,7 @@ function gallery_shortcode( $attr ) { $attachments[ $val->ID ] = $_attachments[ $key ]; } } elseif ( ! empty( $atts['exclude'] ) ) { + $post_parent_id = $id; $attachments = get_children( array( 'post_parent' => $id, @@ -2617,6 +2618,7 @@ function gallery_shortcode( $attr ) { ) ); } else { + $post_parent_id = $id; $attachments = get_children( array( 'post_parent' => $id, @@ -2629,6 +2631,17 @@ function gallery_shortcode( $attr ) { ); } + if ( ! empty( $post_parent_id ) ) { + $post_parent = get_post( $post_parent_id ); + + // terminate the shortcode execution if user cannot read the post or password-protected + if ( + ( ! is_post_publicly_viewable( $post_parent->ID ) && ! current_user_can( 'read_post', $post_parent->ID ) ) + || post_password_required( $post_parent ) ) { + return ''; + } + } + if ( empty( $attachments ) ) { return ''; } @@ -2961,6 +2974,15 @@ function wp_playlist_shortcode( $attr ) { $attachments = get_children( $args ); } + if ( ! empty( $args['post_parent'] ) ) { + $post_parent = get_post( $id ); + + // terminate the shortcode execution if user cannot read the post or password-protected + if ( ! current_user_can( 'read_post', $post_parent->ID ) || post_password_required( $post_parent ) ) { + return ''; + } + } + if ( empty( $attachments ) ) { return ''; } diff --git a/wp-includes/shortcodes.php b/wp-includes/shortcodes.php index 4d23521f44..9d8fb84767 100644 --- a/wp-includes/shortcodes.php +++ b/wp-includes/shortcodes.php @@ -168,6 +168,44 @@ function has_shortcode( $content, $tag ) { return false; } +/** + * Returns a list of registered shortcode names found in the given content. + * + * Example usage: + * + * get_shortcode_tags_in_content( '[audio src="file.mp3"][/audio] [foo] [gallery ids="1,2,3"]' ); + * // array( 'audio', 'gallery' ) + * + * @since 6.3.2 + * + * @param string $content The content to check. + * @return string[] An array of registered shortcode names found in the content. + */ +function get_shortcode_tags_in_content( $content ) { + if ( false === strpos( $content, '[' ) ) { + return array(); + } + + preg_match_all( '/' . get_shortcode_regex() . '/', $content, $matches, PREG_SET_ORDER ); + if ( empty( $matches ) ) { + return array(); + } + + $tags = array(); + foreach ( $matches as $shortcode ) { + $tags[] = $shortcode[2]; + + if ( ! empty( $shortcode[5] ) ) { + $deep_tags = get_shortcode_tags_in_content( $shortcode[5] ); + if ( ! empty( $deep_tags ) ) { + $tags = array_merge( $tags, $deep_tags ); + } + } + } + + return $tags; +} + /** * Searches content for shortcodes and filter shortcodes through their hooks. * diff --git a/wp-includes/version.php b/wp-includes/version.php index fcfabeaf57..73828211bd 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-56844'; +$wp_version = '6.3.2-RC1-56846'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.