From f3ccbed586d036baee8e72e76964da2ee9703339 Mon Sep 17 00:00:00 2001 From: audrasjb Date: Thu, 12 Oct 2023 12:47:21 +0000 Subject: [PATCH] Shortcodes: Restrict ajax handler for media shortcode. Props tykoted, xknown, peterwilsoncc, antpb, jorbin. Built from https://develop.svn.wordpress.org/trunk@56838 git-svn-id: http://core.svn.wordpress.org/trunk@56350 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 8aada30959..69f5fd469c 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 c383a8c586..078e3a2daa 100644 --- a/wp-includes/media.php +++ b/wp-includes/media.php @@ -2607,6 +2607,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, @@ -2619,6 +2620,7 @@ function gallery_shortcode( $attr ) { ) ); } else { + $post_parent_id = $id; $attachments = get_children( array( 'post_parent' => $id, @@ -2631,6 +2633,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 ''; } @@ -2963,6 +2976,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 538b6e79da..24df21d4da 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 6a7cc15ac5..e17abee134 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -16,7 +16,7 @@ * * @global string $wp_version */ -$wp_version = '6.4-beta3-56837'; +$wp_version = '6.4-beta3-56838'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.