Uploadcare closed a potential security breach involving text/html files

At Uploadcare, we always take security seriously, and that’s why we try to avoid even hypothetical security problems. That’s the reason behind this latest decision.

As a service provider for handling user-generated content, we need to keep the data from your users in its original state unless you request any changes. That’s why Uploadcare’s URL API for content processing not only allows you to apply an unlimited number of transformations, but also query the original file anytime by simply removing all URL API operations.

The content itself, however, tells nothing about what to do with it — it’s just a stream of bytes. That’s why each uploaded file has a Content-Type HTTP header associated with it. Browsers and other clients can distinguish different file types by the so-called MIME type (which is a part of the Content-Type header). For example, if the MIME is text/plain, then the file should be shown as a text without any formatting. If the MIME is image/jpeg, then the file is probably a valid JPEG image.

An example of JPEG HTTP headersHTTP headers for a typical JPEG file.

The problem comes when a file uploaded by a user has a text/html MIME type. Basically, this means that the file is an HTML page and can execute scripts. This reveals a bunch of attack vectors including phishing and XSS.

Fortunately, another header comes to the rescue. Content-Disposition allows choosing what to do with the content. When the value of the header is Content-Disposition: inline, the browser must try to process the content (e.g., show images and web pages, open PDF files). When the value is Content-Disposition: attachment, the browser must not process content, but save it locally instead.

What’s the catch?

Every time a user uploads a file, Uploadcare inspects it and determines its format. If the system comes to the conclusion that the file is an image, you’ll be able to process the file as an image, for example, by applying transformations: resize, enhance, flip, etc. Also, by default, Content-Disposition is set to inline if the file is an image.

And this is where the problem arises. If an intruder uploads a specially crafted file that could be decoded as an image (JPEG, for example) but with a MIME type of text/html, it could execute arbitrary JavaScript code on the user’s side if you’ve used plain URLs without any operations in your application.

That’s not a big deal in and of itself. Under a certain set of circumstances, however, it might lead to serious consequences. For example, if the file is served from your subdomain and, by a tragic coincidence, you have cookies that are visible on subdomains for JavaScript, the intruder could steal the user’s credentials.

A text/html file upload vulnerabilityThis file contains JavaScript code while remaining a perfectly valid JPEG.

Uploadcare fixes security flaw

To fix this problem, our first intention was to turn all original files into attachments by default. This would solve the problem, since attachments can’t execute Javascript even if they have a text/html MIME type. But, after having a better look at how our customers work with files, we came to the conclusion that it would only delay the problem and eventually make it even worse.

Bare file URLs (without any operations applied) are quite common for our customers’ applications, since it’s a simple way to show uploaded files to the end user. So, if we made all bare URLs into attachments, customers would have to search for another way to show files, and chances are it would be to force Content-Disposition to inline regardless of file content using the inline operation. Not only would it not solve the vulnerability issue, but it would also lead to extra work for Uploadcare clients. This is quite the opposite of what we wanted to achieve.

Instead, we picked several safe types that most browsers could display natively and made them inlinable. Those types include: text/plain, application/pdf, image/*, audio/* and video/*. All other MIME types are attachments by default.

Important: this update isn’t backward compatible

Usually, we try to make all changes to our URL API backward compatible. This case is a noticeable exception, since we believe the influence on existing applications is moderate while the benefits for further applications are significant.

However, please check your application and consider adding the -/inline/no/ operation if you relied on the old behavior where all files except images are attachments.

All these changes are only related to the default behavior for bare file URLs, where no inline operation is applied. If the inline operation is applied, the behavior is unchanged.

Infrastructure for user images, videos & documents