Skip to content

Commit 35c0ab3

Browse files
committed
Media: Prevent CSRF setting attachment thumbnails.
Props martinkrcho, paulkevan, peterwilsoncc, xknown, peterwilsoncc. git-svn-id: https://develop.svn.wordpress.org/trunk@55764 602fd350-edb4-49c9-b593-d223f7449a82
1 parent a6f0f3e commit 35c0ab3

4 files changed

Lines changed: 98 additions & 1 deletion

File tree

src/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-admin/includes/ajax-actions.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2771,6 +2771,10 @@ function wp_ajax_set_attachment_thumbnail() {
27712771
wp_send_json_error();
27722772
}
27732773

2774+
if ( false === check_ajax_referer( 'set-attachment-thumbnail', '_ajax_nonce', false ) ) {
2775+
wp_send_json_error();
2776+
}
2777+
27742778
$post_ids = array();
27752779
// For each URL, try to find its corresponding post ID.
27762780
foreach ( $_POST['urls'] as $url ) {

src/wp-includes/media.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4528,7 +4528,8 @@ function wp_enqueue_media( $args = array() ) {
45284528
/** This filter is documented in wp-admin/includes/media.php */
45294529
'captions' => ! apply_filters( 'disable_captions', '' ),
45304530
'nonce' => array(
4531-
'sendToEditor' => wp_create_nonce( 'media-send-to-editor' ),
4531+
'sendToEditor' => wp_create_nonce( 'media-send-to-editor' ),
4532+
'setAttachmentThumbnail' => wp_create_nonce( 'set-attachment-thumbnail' ),
45324533
),
45334534
'post' => array(
45344535
'id' => 0,

tests/phpunit/tests/ajax/wpAjaxSendAttachmentToEditor.php

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

0 commit comments

Comments
 (0)