Skip to content

Commit a392d87

Browse files
Grouped backports to the 4.9 branch.
- Media: Prevent CSRF setting attachment thumbnails. - Embeds: Add protocol validation for WordPress Embed code. Merges [55763] and [55764] to the 4.9 branch. Props dd32, isabel_brison, martinkrcho, matveb, ocean90, paulkevan, peterwilsoncc, timothyblynjacobs, xknown, youknowriad. git-svn-id: https://develop.svn.wordpress.org/branches/4.9@55787 602fd350-edb4-49c9-b593-d223f7449a82
1 parent 365728c commit a392d87

File tree

9 files changed

+127
-4
lines changed

9 files changed

+127
-4
lines changed

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "WordPress",
3-
"version": "4.9.22",
3+
"version": "4.9.23",
44
"description": "WordPress is web software you can use to create a beautiful website or blog.",
55
"repository": {
66
"type": "svn",

src/wp-admin/about.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,26 @@
3333

3434
<div class="changelog point-releases">
3535
<h3><?php _e( 'Maintenance and Security Releases' ); ?></h3>
36+
<p>
37+
<?php
38+
printf(
39+
/* translators: %s: WordPress version number */
40+
__( '<strong>Version %s</strong> addressed some security issues.' ),
41+
'4.9.23'
42+
);
43+
?>
44+
<?php
45+
printf(
46+
/* translators: %s: HelpHub URL */
47+
__( 'For more information, see <a href="%s">the release notes</a>.' ),
48+
sprintf(
49+
/* translators: %s: WordPress version */
50+
esc_url( __( 'https://wordpress.org/support/wordpress-version/version-%s/' ) ),
51+
sanitize_title( '4.9.23' )
52+
)
53+
);
54+
?>
55+
</p>
3656
<p>
3757
<?php
3858
printf(

src/wp-admin/includes/ajax-actions.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2259,6 +2259,10 @@ function wp_ajax_set_attachment_thumbnail() {
22592259
wp_send_json_error();
22602260
}
22612261

2262+
if ( false === check_ajax_referer( 'set-attachment-thumbnail', '_ajax_nonce', false ) ) {
2263+
wp_send_json_error();
2264+
}
2265+
22622266
$post_ids = array();
22632267
// For each URL, try to find its corresponding post ID.
22642268
foreach ( $_POST['urls'] as $url ) {

src/wp-includes/js/media/views/frame/video-details.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ VideoDetails = MediaDetails.extend(/** @lends wp.media.view.MediaFrame.VideoDeta
106106

107107
wp.ajax.send( 'set-attachment-thumbnail', {
108108
data : {
109+
_ajax_nonce: wp.media.view.settings.nonce.setAttachmentThumbnail,
109110
urls: urls,
110111
thumbnail_id: attachment.get( 'id' )
111112
}

src/wp-includes/js/wp-embed.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343

4444
var iframes = document.querySelectorAll( 'iframe[data-secret="' + data.secret + '"]' ),
4545
blockquotes = document.querySelectorAll( 'blockquote[data-secret="' + data.secret + '"]' ),
46+
allowedProtocols = new RegExp( '^https?:$', 'i' ),
4647
i, source, height, sourceURL, targetURL;
4748

4849
for ( i = 0; i < blockquotes.length; i++ ) {
@@ -78,6 +79,11 @@
7879
sourceURL.href = source.getAttribute( 'src' );
7980
targetURL.href = data.value;
8081

82+
/* Only follow link if the protocol is in the allow list. */
83+
if ( ! allowedProtocols.test( targetURL.protocol ) ) {
84+
continue;
85+
}
86+
8187
/* Only continue if link hostname matches iframe's hostname. */
8288
if ( targetURL.host === sourceURL.host ) {
8389
if ( document.activeElement === source ) {

src/wp-includes/media.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3442,7 +3442,8 @@ function wp_enqueue_media( $args = array() ) {
34423442
/** This filter is documented in wp-admin/includes/media.php */
34433443
'captions' => ! apply_filters( 'disable_captions', '' ),
34443444
'nonce' => array(
3445-
'sendToEditor' => wp_create_nonce( 'media-send-to-editor' ),
3445+
'sendToEditor' => wp_create_nonce( 'media-send-to-editor' ),
3446+
'setAttachmentThumbnail' => wp_create_nonce( 'set-attachment-thumbnail' ),
34463447
),
34473448
'post' => array(
34483449
'id' => 0,

src/wp-includes/version.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*
55
* @global string $wp_version
66
*/
7-
$wp_version = '4.9.22-src';
7+
$wp_version = '4.9.23-src';
88

99
/**
1010
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.

tests/phpunit/tests/ajax/Attachments.php

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,95 @@ public function test_wp_ajax_send_attachment_to_editor_should_return_a_link() {
109109
$this->assertTrue( $response['success'] );
110110
$this->assertEquals( $expected, $response['data'] );
111111
}
112+
113+
public function test_wp_ajax_set_attachment_thumbnail_success() {
114+
// Become an administrator.
115+
$post = $_POST;
116+
$user_id = self::factory()->user->create(
117+
array(
118+
'role' => 'administrator',
119+
'user_login' => 'user_36578_administrator',
120+
'user_email' => '[email protected]',
121+
)
122+
);
123+
wp_set_current_user( $user_id );
124+
$_POST = array_merge( $_POST, $post );
125+
126+
// Upload the attachment itself.
127+
$filename = DIR_TESTDATA . '/uploads/small-audio.mp3';
128+
$contents = file_get_contents( $filename );
129+
130+
$upload = wp_upload_bits( wp_basename( $filename ), null, $contents );
131+
$attachment = $this->_make_attachment( $upload );
132+
133+
// Upload the thumbnail.
134+
$filename = DIR_TESTDATA . '/images/waffles.jpg';
135+
$contents = file_get_contents( $filename );
136+
137+
$upload = wp_upload_bits( wp_basename( $filename ), null, $contents );
138+
$thumbnail = $this->_make_attachment( $upload );
139+
140+
// Set up a default request.
141+
$_POST['_ajax_nonce'] = wp_create_nonce( 'set-attachment-thumbnail' );
142+
$_POST['thumbnail_id'] = $thumbnail;
143+
$_POST['urls'] = array( wp_get_attachment_url( $attachment ) );
144+
145+
// Make the request.
146+
try {
147+
$this->_handleAjax( 'set-attachment-thumbnail' );
148+
} catch ( WPAjaxDieContinueException $e ) {
149+
unset( $e );
150+
}
151+
152+
// Get the response.
153+
$response = json_decode( $this->_last_response, true );
154+
155+
// Ensure everything is correct.
156+
$this->assertTrue( $response['success'] );
157+
}
158+
159+
public function test_wp_ajax_set_attachment_thumbnail_missing_nonce() {
160+
// Become an administrator.
161+
$post = $_POST;
162+
$user_id = self::factory()->user->create(
163+
array(
164+
'role' => 'administrator',
165+
'user_login' => 'user_36578_administrator',
166+
'user_email' => '[email protected]',
167+
)
168+
);
169+
wp_set_current_user( $user_id );
170+
$_POST = array_merge( $_POST, $post );
171+
172+
// Upload the attachment itself.
173+
$filename = DIR_TESTDATA . '/uploads/small-audio.mp3';
174+
$contents = file_get_contents( $filename );
175+
176+
$upload = wp_upload_bits( wp_basename( $filename ), null, $contents );
177+
$attachment = $this->_make_attachment( $upload );
178+
179+
// Upload the thumbnail.
180+
$filename = DIR_TESTDATA . '/images/waffles.jpg';
181+
$contents = file_get_contents( $filename );
182+
183+
$upload = wp_upload_bits( wp_basename( $filename ), null, $contents );
184+
$thumbnail = $this->_make_attachment( $upload );
185+
186+
// Set up a default request.
187+
$_POST['thumbnail_id'] = $thumbnail;
188+
$_POST['urls'] = array( wp_get_attachment_url( $attachment ) );
189+
190+
// Make the request.
191+
try {
192+
$this->_handleAjax( 'set-attachment-thumbnail' );
193+
} catch ( WPAjaxDieContinueException $e ) {
194+
unset( $e );
195+
}
196+
197+
// Get the response.
198+
$response = json_decode( $this->_last_response, true );
199+
200+
// Check that success is false without sending nonce.
201+
$this->assertFalse( $response['success'] );
202+
}
112203
}

0 commit comments

Comments
 (0)