Detecting XSS-Auditor in Safari
27 Feb. 2020
2 minute read

TLDR

Safari (13.0.4) will not log iframe requests in the performance API list, when the iframe page is blocked by the XSS-Auditor. So the length of performance.getEntries() can leak the status of the Auditor.

const check = async(url) => {
    let perfEntries = performance.getEntries().length
    return new Promise(r => {
        let frame = document.createElement('iframe')
        frame.src = url
        frame.onload = (e) => {
            e.target.remove()
            return r(performance.getEntries().length - perfEntries)
        }
        framesdiv.appendChild(frame)
    })
}
// r(0) = XSS auditor triggered
// r(1) = no XSS auditor

XS-Leaks with Performance API

Since the auditor got removed from Chrome 78+ i was wondering if you can still detect it cross origin in Safari. In Safari the current page is just replaced with an empty page instead of changing to an error page like Chrome, which makes it harder to detect.

When a page has iframes, a block would remove them and window.frames.length could be used to detect the auditor cross domain. Without iframes it is a bit harder as other techniques used to detect the Chrome Auditor do not work with Safari.

The Performance API is very interesting for all kind of timing leaks and teranq showed how to detect xframe options with it in Chrome, using embeds or iframes.

Safari will also not log iframe requests in certain conditions which can be used for XS-Leaks:

  • if the XSS-Auditor blocked the page => Detect XSS-Auditor
  • if the response has 4XX or 5XX status code => Status-Code Leak
  • if X-Frame-Options deny/sameorigin denied the iframe request => X-Frame Option Leak

Also in Safari redirect times can be read for cross-origin performance entries, thus leaking whether a page redirected the user.

Chrome has the same problem with X-Frame Options only Firefox seems to get it right (also no XSS auditor 🙃).

Reddit Post