Persistent cross-site scripting (XSS) vulnerability in Postmill

An issue was discovered in Postmill’s handling of background image uploads that allows malicious files to be uploaded and accessed. When opened in a browser, scripts in these malicious files can act as the currently logged in user.

Note: This post is backdated. The Postmill website’s news section did not exist at the time this vulnerability was discovered.


When uploading background images, a check on the file’s MIME type is performed in order to prevent uploading arbitrary file types, but a programming error resulted in the file being stored regardless of the outcome of the check. Uploading background images is available to everyone with moderator privileges.

Using this vulnerability, an attacker could upload a malicious HTML/XML document containing JavaScript. By tricking an unsuspecting user into opening the file, the script can then perform actions in Postmill on the user’s behalf, including (but not limited to) accessing private messages, or changing their credentials.

This exploit is only possible when user-uploaded images are served from the same domain as Postmill, and requires that uploaded malicious files don’t have any headers that prevent them from being treated as HTML/XML documents by the browser. A typical Postmill instance would be configured this way.

Additionally, the vulnerability is a theoretical attack vector for remote code execution. A PHP file might be uploaded and automatically given the .php extension, thereby allowing it to be executed on the server. However, we have not been able to produce such an outcome, as Postmill would not detect any PHP script as having PHP’s MIME type.


The vulnerability is patched since commit b865e36f26db.

In addition to patching, instance admins should consider these preventative measures:

  • Serving uploaded files from a separate (sub)domain.
  • Disable serving of non-image files from the upload directories (public/submission_images and public/media).
  • Disabling execution as PHP for any file other than public/index.php.