# Abusing HTTP Status Codes to Expose Private Information
**Update:** Some of the example tests on this page no longer work (I don't have
a Facebook account anymore and the Twitter URL I used went offline). The
technique it's self is still alive and relevant though.
When you visit my website, I can automatically and silently determine if you're
logged into [Facebook](https://www.facebook.com/),
[Twitter](https://www.twitter.com), [GMail](https://gmail.com/) and
[Digg](https://digg.com/). There are almost certainly thousands of other sites
with this issue too, but I picked a few vulnerable well known ones to get your
attention. You may not care that I can tell you're logged into GMail, but would
you care if I could tell you're logged into one or more porn or warez sites?
Perhaps http://oppressive-regime.example.org/ would like to collect a list of
their users who are logged into http://controversial-website.example.com/?
Ignoring the privacy implications for a second, as a website developer, you
might like to know if your visitors are logged into GMail; you could use that
information to automatically fill the email fields in your forms with
"@gmail.com"... Perhaps you might want to make your Facebook "like" buttons more
prominent if you can tell your visitor is logged into Facebook at the moment?
Here's how I achieve this:
First of all. Lets check if you're logged into GMail right now (this check is
disabled)... Now, how did I get that information? Really, really, easily... I
generated a hidden image in my HTML similar to this:
```html
```
I generated the URL in the "src" attribute by logging into my own GMail account,
then going into the general settings and uploading a picture in the "My Picture"
section. I then ticked the "Visible to everyone" checkbox, and right clicked the
uploaded image to get the image location. Fetching the content at that URL does
two different things depending on whether or not you're logged into GMail. If
you are logged into GMail, it returns an image. If you're not logged into GMail,
it redirects to a HTML page. This is why the img tag in my example above works.
"onload" is triggered if an image is returned, but "onerror" is triggered
otherwise.
I tested this technique in [Firefox](https://www.mozilla.com/),
[Safari](https://www.apple.com/safari/),
[Chrome](https://www.google.com/chrome), [Opera](https://www.opera.com/) and
various versions of [Internet
Explorer](https://www.microsoft.com/windows/internet-explorer/) and it worked in
them all. I reported it to Google and they described it as "expected behaviour"
and ignored it.
At this point, you might be wondering why I have "Status Codes" in the title;
the method I use for attacking Facebook, Twitter and Digg is slightly different
and works because various URLs provide different HTTP status codes depending on
your logged in status. Unfortunately, this attack doesn't seem to work in
Internet Explorer or Opera, but does work in Firefox, Chrome and Safari. If
you're using a non-IE, non-Opera browser, here are tests for Twitter and
Facebook:
```text
Are you logged into Twitter ? (this test is disabled)
Are you logged into Facebook? (this test is disabled)
```
If you have JavaScript disabled on twitter.com and facebook.com, the above tests
wont work.
Here is how they work when you have JavaScript enabled:
```html
```
In Firefox, Safari and Chrome, the script tags fire onload if a 200 HTTP status
code is returned, even if there was no valid JavaScript and the Content-Type was
text/html. But if the status code was one of 404, 403, 406 or 500, then onerror
is triggered instead. In the above examples, the Twitter URL returns an error
code if you're logged in, but redirects to the login form with a success status
code if you're not logged in. The Facebook one works because my profile is only
visible to people who are logged in and returns a 404 if you're not. There is a
similar problem with Digg. https://digg.com/settings returns a 403 status code
if you're not logged in, but a 200 if you are.
This can be an awkward problem to avoid if you're developing a website. Some of
these requests could be stopped by doing referrer checks; reject all external
referrers for content only accessible when logged in. You want your status codes
and responses to image requests to be relevant, but that can leak information.
Firefox users could defend from this problem by using the [Request
Policy](https://www.requestpolicy.com/) addon. I've never used it myself because
it looks like a pain to manage, but it sounds like it would do the job.
And finally, this isn't just an issue of detecting whether or not a user is
logged in. The question could technically be anything, if a HTTP response
results in an image or html depending on the answer, or results in a
success/error status code depending on the answer.
For the web developers out there who are familiar with jQuery, as a
demonstration of the usefulness of this technique. The following chunk of code
will detect if a user is logged into GMail, and if they are will replace all the
mailto: links on your webpage with links to the GMail compose window
(automatically filling in the To field):
```javascript
$('
').hide().attr('src',
'https://mail.google.com/mail/photos/img/photos/public/AIbEiAIAAABDCKa_hYq24u2WUyILdmNhcmRfcGhvdG8qKDI1ODFkOGViM2I5ZjUwZmZlYjE3MzQ2YmQyMjAzMjFlZTU3NjEzOTYwAZwSCm_MMUDjh599IgoA2muEmEZD'
).load(function(){
$('a[href^="mailto:"]').each(function(){
var email = $(this).attr('href').replace(/^mailto:/,'');
$(this).attr('href',
'https://mail.google.com/mail/?view=cm&fs=1&tf=0&to='+escape(email)
);
});
}).appendTo('body');
```