Friday, February 7, 2014

Paperclip vulnerability leading to XSS or RCE.

Paperclip is the most popular upload tool for Ruby on Rails, and I found a way to upload a file with arbitrary extension, which can lead to XSS (file.html) or RCE (file.php/

By default Paperclip allows all types of files, and I believe it's a vulnerability on its own, "insecure-by-default". Developer is supposed to write validates_attachment :avatar, :content_type => { :content_type => "image/jpg" } and even paperclip_demo was misconfigured.

io_adapters/uri_adapter.rb looked like an interesting file. It's a built-in adapter to download a remote file from user-supplied URL. When Paperclip downloads a remote file it validates the Content-Type header instead of the actual file extension:
      @original_filename = @target.path.split("/").last
      @original_filename ||= "index.html"
      self.original_filename = @original_filename.strip

      @content_type = @content.content_type if @content.respond_to?(:content_type)
      @content_type ||= "text/html"

I crafted special URL serving a JPEG file with content-type = image/jpg, but having .htm extension in the path:  (also it serves - might be useful)

Paperclip thinks the file we supplied with URL is an image and saves it with original filename (file.jpg.htm). Furthermore, to make Paperclip download your remote file no configuration is required! Just remove type="file" from <input>. Omakase Rails Magic.

If you send a URL instead of a file, Paperclip automatically switches to another (vulnerable) URI adapter, which downloads and saves it like /PaperclipPath/01/02/03/file.jpg.htm

Finally, when Apache/nginx/%webserver% is serving the static file.jpg.htm it responds with according text/html Content-Type and JPG's internals.

We can hide our XSS (or PHP <?=code();?>)  payload in the EXIF header.

ÛßÙ4Ù¬ıPıfiˆmˆ˚˜ä¯ ¯®˘8˘«˙W˙Á˚w¸ ¸ò˝)˝∫˛K˛‹ˇmˇˇˇ· ‚ExifII*
Ü å ¢ ™( 1 ≤2 «£ €iá ¯CanonCanon DIGITAL IXUS 70¥ ¥ f-spot version 0.3.52008:09:08 11:29:26<img src=x onerror=alert(0)> öÇ Z ùÇ b 'à Pê 0220

To get a RCE (code execution) you would need file.php/.pl/.cgi to be executed by the web server, IMO it is a rare case for regular Rails apps, I didn't research it though.

Reported to thoughtbot: 11 Dec 2013
Thoughtbot releases new major Paperclip 4 version: 2 Feb 2014

You definitely should bundle-update and check:
1) You have properly whitelisted content-type
2) Your Paperclip version > 4.0 now
3) Look for suspicious .html/.%smth% in your paperclip uploads folder.


  1. nice. thanks, egor!

  2. Nice work, and excellent down-to-earth explanation.

  3. extremely helpful, many thanks. Helped us to analyze or file attachment feature.