CMS Airship

CSPR.NG

Indistinguishable from line-noise.

CSPR.NG Blog

Cryptographically Secure Pseudorandom Number Generator

CMS Airship < 1.1.2 - Stored XSS Post-Mortem

Earlier today, a stored XSS vulnerability was reported by Lucas Reschke and fixed in version 1.1.2. Unfortunately, this news arrived at the same time as I discovered the auto-updater was refusing to run. If you've set up your own Airship already, you'll need to manually update to the latest version (1.1.3).

The Vulnerability

There were several locations, but most prominently in the "name" field of an Author, which could store an XSS payload. On two pages, this payload bypassed Twig's auto-escaping and could trigger Javascript in the end users' browser.

Sounds bad, and you should definitely update if you haven't already, but the impact was severely mitigated by our default configuration for Content-Security-Policy headers. In fact, these headers were so effective that it actually caused a false negative when I was testing for these vulnerabilities during the pre-1.0.0 code audit! From now on, I'll remember to turn these off when testing for XSS vulnerabilities.

The patch for this vulnerability is here.

How the Vulnerability Happened

In several places, we wrote something similar to this in a Twig template to allow for internationalization, going forward:

<h2>{{ __("Edit Author \"%s\" Details", "default", author.name) }}</h2>

Because I had hard-coded autoescape to true in our Twig_Environment, I had incorrectly assumed that everything would be escaped in the html context. It turns out, these __() calls were an exception to the rule.

Because author.name was never escaped, it was placed verbatim into the HTML, triggering the vulnerability.

What the Impact Could Be

If your target used a browser that doesn't support Content-Security-Policy headers, and they were tricked into accessing one of the vulnerable templates (i.e. they didn't notice the massive blob of HTML in the authors list before clicking the Edit or Users icons), you could potentially execute untrusted Javascript in their browser.

The cross-section of both circumstances is thin enough to consider an edge case, but don't rest on your laurels. Update immediately.

Lessons Learned

  1. If you rely on autoescaping, make sure it's being applied everywhere. Where it's not applied, escape manually.
  2. Be more skeptical of patterns intended to promote i18n.
  3. Turn off Content-Security-Policy headers when testing locally so it's easier to catch these failures.

We're pretty confident that this entire avenue for exploitation has been thoroughly expunged from our codebase, along with other risk factors identified by Paragon Initiative Enterprises.

We'd like to thank Lucas Reschke for reporting this.

About the Author

Friends of CSPR.NG

Multiple Authors

People with access to this Author profile:

  • Scott Arciszewski
  • Taylor Hornby

Leave a Comment

:
:
:
: