diff --git a/package-lock.json b/package-lock.json index 8178c539fdde6..378c2328048b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "WordPress", - "version": "5.1.15", + "version": "5.1.16", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 14e52e2fe541a..1bdc893b0ff1a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "WordPress", - "version": "5.1.15", + "version": "5.1.16", "description": "WordPress is open source software you can use to create a beautiful website, blog, or app.", "repository": { "type": "svn", diff --git a/src/js/_enqueues/wp/embed.js b/src/js/_enqueues/wp/embed.js index 887c7483fb0a5..63c59f2fb0b9a 100644 --- a/src/js/_enqueues/wp/embed.js +++ b/src/js/_enqueues/wp/embed.js @@ -44,6 +44,7 @@ var iframes = document.querySelectorAll( 'iframe[data-secret="' + data.secret + '"]' ), blockquotes = document.querySelectorAll( 'blockquote[data-secret="' + data.secret + '"]' ), + allowedProtocols = new RegExp( '^https?:$', 'i' ), i, source, height, sourceURL, targetURL; for ( i = 0; i < blockquotes.length; i++ ) { @@ -79,6 +80,11 @@ sourceURL.href = source.getAttribute( 'src' ); targetURL.href = data.value; + /* Only follow link if the protocol is in the allow list. */ + if ( ! allowedProtocols.test( targetURL.protocol ) ) { + continue; + } + /* Only continue if link hostname matches iframe's hostname. */ if ( targetURL.host === sourceURL.host ) { if ( document.activeElement === source ) { diff --git a/src/js/media/views/frame/video-details.js b/src/js/media/views/frame/video-details.js index 2dbb22f774a91..6a0d6042026e3 100644 --- a/src/js/media/views/frame/video-details.js +++ b/src/js/media/views/frame/video-details.js @@ -106,6 +106,7 @@ VideoDetails = MediaDetails.extend(/** @lends wp.media.view.MediaFrame.VideoDeta wp.ajax.send( 'set-attachment-thumbnail', { data : { + _ajax_nonce: wp.media.view.settings.nonce.setAttachmentThumbnail, urls: urls, thumbnail_id: attachment.get( 'id' ) } diff --git a/src/wp-admin/about.php b/src/wp-admin/about.php index 3d9736bc97715..9cd8b4e72cdea 100644 --- a/src/wp-admin/about.php +++ b/src/wp-admin/about.php @@ -36,6 +36,26 @@
+ Version %s addressed some security issues.' ), + '5.1.16' + ); + ?> + the release notes.' ), + sprintf( + /* translators: %s: WordPress version */ + esc_url( __( 'https://wordpress.org/support/wordpress-version/version-%s/' ) ), + sanitize_title( '5.1.16' ) + ) + ); + ?> +
' ) ) {
+ $text = preg_replace_callback( '%%', '_filter_block_content_callback', $text );
+ }
+
$blocks = parse_blocks( $text );
foreach ( $blocks as $block ) {
$block = filter_block_kses( $block, $allowed_html, $allowed_protocols );
@@ -280,6 +284,19 @@ function filter_block_content( $text, $allowed_html = 'post', $allowed_protocols
return $result;
}
+/**
+ * Callback used for regular expression replacement in filter_block_content().
+ *
+ * @private
+ * @since 6.2.1
+ *
+ * @param array $matches Array of preg_replace_callback matches.
+ * @return string Replacement string.
+ */
+function _filter_block_content_callback( $matches ) {
+ return '';
+}
+
/**
* Filters and sanitizes a parsed block to remove non-allowable HTML from block
* attribute values.
diff --git a/src/wp-includes/formatting.php b/src/wp-includes/formatting.php
index 1b346fc4637ed..670bc006d8a08 100644
--- a/src/wp-includes/formatting.php
+++ b/src/wp-includes/formatting.php
@@ -2365,6 +2365,29 @@ function sanitize_html_class( $class, $fallback = '' ) {
return apply_filters( 'sanitize_html_class', $sanitized, $class, $fallback );
}
+/**
+ * Strips out all characters not allowed in a locale name.
+ *
+ * @since 6.2.1
+ *
+ * @param string $locale_name The locale name to be sanitized.
+ * @return string The sanitized value.
+ */
+function sanitize_locale_name( $locale_name ) {
+ // Limit to A-Z, a-z, 0-9, '_', '-'.
+ $sanitized = preg_replace( '/[^A-Za-z0-9_-]/', '', $locale_name );
+
+ /**
+ * Filters a sanitized locale name string.
+ *
+ * @since 6.2.1
+ *
+ * @param string $sanitized The sanitized locale name.
+ * @param string $locale_name The locale name before sanitization.
+ */
+ return apply_filters( 'sanitize_locale_name', $sanitized, $locale_name );
+}
+
/**
* Converts lone & characters into `&` (a.k.a. `&`)
*
diff --git a/src/wp-includes/l10n.php b/src/wp-includes/l10n.php
index 39aa6d498eee3..8d10ee9817ebf 100644
--- a/src/wp-includes/l10n.php
+++ b/src/wp-includes/l10n.php
@@ -139,7 +139,7 @@ function determine_locale() {
}
if ( ! empty( $_GET['wp_lang'] ) && ! empty( $GLOBALS['pagenow'] ) && 'wp-login.php' === $GLOBALS['pagenow'] ) {
- $determined_locale = sanitize_text_field( $_GET['wp_lang'] );
+ $determined_locale = sanitize_locale_name( wp_unslash( $_GET['wp_lang'] ) );
}
/**
diff --git a/src/wp-includes/media.php b/src/wp-includes/media.php
index ace9021fd7b80..855308c29ce99 100644
--- a/src/wp-includes/media.php
+++ b/src/wp-includes/media.php
@@ -3583,7 +3583,8 @@ function wp_enqueue_media( $args = array() ) {
/** This filter is documented in wp-admin/includes/media.php */
'captions' => ! apply_filters( 'disable_captions', '' ),
'nonce' => array(
- 'sendToEditor' => wp_create_nonce( 'media-send-to-editor' ),
+ 'sendToEditor' => wp_create_nonce( 'media-send-to-editor' ),
+ 'setAttachmentThumbnail' => wp_create_nonce( 'set-attachment-thumbnail' ),
),
'post' => array(
'id' => 0,
diff --git a/src/wp-includes/version.php b/src/wp-includes/version.php
index a9dab7231c735..3a9c69df72ef0 100644
--- a/src/wp-includes/version.php
+++ b/src/wp-includes/version.php
@@ -13,7 +13,7 @@
*
* @global string $wp_version
*/
-$wp_version = '5.1.15-src';
+$wp_version = '5.1.16-src';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
diff --git a/tests/phpunit/tests/ajax/Attachments.php b/tests/phpunit/tests/ajax/Attachments.php
index cf11ddc5a06c7..e8efdf2b21870 100644
--- a/tests/phpunit/tests/ajax/Attachments.php
+++ b/tests/phpunit/tests/ajax/Attachments.php
@@ -113,4 +113,95 @@ public function test_wp_ajax_send_attachment_to_editor_should_return_a_link() {
$this->assertTrue( $response['success'] );
$this->assertEquals( $expected, $response['data'] );
}
+
+ public function test_wp_ajax_set_attachment_thumbnail_success() {
+ // Become an administrator.
+ $post = $_POST;
+ $user_id = self::factory()->user->create(
+ array(
+ 'role' => 'administrator',
+ 'user_login' => 'user_36578_administrator',
+ 'user_email' => 'user_36578_administrator@example.com',
+ )
+ );
+ wp_set_current_user( $user_id );
+ $_POST = array_merge( $_POST, $post );
+
+ // Upload the attachment itself.
+ $filename = DIR_TESTDATA . '/uploads/small-audio.mp3';
+ $contents = file_get_contents( $filename );
+
+ $upload = wp_upload_bits( wp_basename( $filename ), null, $contents );
+ $attachment = $this->_make_attachment( $upload );
+
+ // Upload the thumbnail.
+ $filename = DIR_TESTDATA . '/images/waffles.jpg';
+ $contents = file_get_contents( $filename );
+
+ $upload = wp_upload_bits( wp_basename( $filename ), null, $contents );
+ $thumbnail = $this->_make_attachment( $upload );
+
+ // Set up a default request.
+ $_POST['_ajax_nonce'] = wp_create_nonce( 'set-attachment-thumbnail' );
+ $_POST['thumbnail_id'] = $thumbnail;
+ $_POST['urls'] = array( wp_get_attachment_url( $attachment ) );
+
+ // Make the request.
+ try {
+ $this->_handleAjax( 'set-attachment-thumbnail' );
+ } catch ( WPAjaxDieContinueException $e ) {
+ unset( $e );
+ }
+
+ // Get the response.
+ $response = json_decode( $this->_last_response, true );
+
+ // Ensure everything is correct.
+ $this->assertTrue( $response['success'] );
+ }
+
+ public function test_wp_ajax_set_attachment_thumbnail_missing_nonce() {
+ // Become an administrator.
+ $post = $_POST;
+ $user_id = self::factory()->user->create(
+ array(
+ 'role' => 'administrator',
+ 'user_login' => 'user_36578_administrator',
+ 'user_email' => 'user_36578_administrator@example.com',
+ )
+ );
+ wp_set_current_user( $user_id );
+ $_POST = array_merge( $_POST, $post );
+
+ // Upload the attachment itself.
+ $filename = DIR_TESTDATA . '/uploads/small-audio.mp3';
+ $contents = file_get_contents( $filename );
+
+ $upload = wp_upload_bits( wp_basename( $filename ), null, $contents );
+ $attachment = $this->_make_attachment( $upload );
+
+ // Upload the thumbnail.
+ $filename = DIR_TESTDATA . '/images/waffles.jpg';
+ $contents = file_get_contents( $filename );
+
+ $upload = wp_upload_bits( wp_basename( $filename ), null, $contents );
+ $thumbnail = $this->_make_attachment( $upload );
+
+ // Set up a default request.
+ $_POST['thumbnail_id'] = $thumbnail;
+ $_POST['urls'] = array( wp_get_attachment_url( $attachment ) );
+
+ // Make the request.
+ try {
+ $this->_handleAjax( 'set-attachment-thumbnail' );
+ } catch ( WPAjaxDieContinueException $e ) {
+ unset( $e );
+ }
+
+ // Get the response.
+ $response = json_decode( $this->_last_response, true );
+
+ // Check that success is false without sending nonce.
+ $this->assertFalse( $response['success'] );
+ }
}
diff --git a/tests/phpunit/tests/formatting/sanitizeLocaleName.php b/tests/phpunit/tests/formatting/sanitizeLocaleName.php
new file mode 100644
index 0000000000000..cd22acbf2c60a
--- /dev/null
+++ b/tests/phpunit/tests/formatting/sanitizeLocaleName.php
@@ -0,0 +1,49 @@
+assertSame( $expected, sanitize_locale_name( $input ) );
+ }
+
+ public function data_sanitize_locale_name_returns_non_empty_string() {
+ return array(
+ // array( expected, input )
+ array( 'en_US', 'en_US' ),
+ array( 'en', 'en' ),
+ array( 'fr_FR', 'fr_FR' ),
+ array( 'fr_FR', 'fr_FR' ),
+ array( 'fr_FR-e2791ba830489d23043be8650a22a22b', 'fr_FR-e2791ba830489d23043be8650a22a22b' ),
+ array( '-fr_FRmo', '-fr_FR.mo' ),
+ array( '12324', '$12324' ),
+ array( '4124FRRa', '/4124$$$%%FRRa' ),
+ array( 'FR', '