office365 calendar link vulnerability

In November 2015 I noticed that Microsoft Office 365’s calendar sharing option used an HTTP permalink.

the calendar link shown in Office365 settings is a HTTP link, not HTTPS

I reported this to Microsoft, and they have since fixed the issue. The rest of this article was written before the issue had been fully resolved.

what is the issue?

Before December 2016, the “share calendar” link Office 365 was giving to users to access their calendars is a bog-standard HTTP GET request permalink to your calendar, which, depending on your settings, can be used by anyone who has the link, to access:

  • all of your calendar details
  • some of your calendar details
  • just your availability
  • or nothing

If, like me, you use your calendar for work, to organise and attend video-conferences, online meetings, or discuss anything sensitive, then you will probably at some point have URLs, usernames, passwords, conference IDs, VOIP call numbers and passwords, within the details of your calendar appointments.

If your calendar sharing option is set to “Full Details”, then anyone with the generated URL can get full read-only access to your entire calendar, and also access to all of these details.

The above is all expected behaviour, because you’re supposed to keep the URL secret – the problem is that the generated URL is not prefixed with HTTPS…. (at least it didn’t used to be.)

So all the standard MITM attack stuff applies – anyone with access to see any raw otherwise unprotected network traffic between your browser and the Microsoft Office 365 server will be able to see the content of this GET request.

Microsoft have even done 99% of the work required to fix this issue – when the link is accessed, the following happens:

shows the HTTP request being redirected to HTTPS

So the request is immediately upgraded to HTTPS using a 301 Moved Permanently response, with exactly the same URL content.

But the problem is that the GET request has already been sent over HTTP, which contains the secret permalink key (which I have redacted) that you need in order to access the data. Even though an attacker wouldn’t be able to see the second request being made or the content being downloaded over HTTPS, they could just follow the HTTPS redirect themselves to see the content, and then repeat that request when they want to see your latest calendar content.

There is no tracking available through Office 365 to see what devices are using this link, how often, where from, or anything of that nature. It also doesn’t give you the option of resetting the link in case you think someone else might have gotten access to it.

At some point between November 2015 and April 2016, Microsoft have changed the default links being generated, so they default to HTTPS – but this still leaves any existing links vulnerable, and Microsoft haven’t informed users of the problem (to my knowledge).

what can i do?

If the link in your calendar sharing settings begins with HTTP://, then do this:

  1. Disable calendar sharing completely
  2. Save the changes
  3. Re-load the options window
  4. Re-enable calendar sharing

Your link will now be different, and the old link will now be dead.

so what did Microsoft do?

They changed all new links to be HTTPS instead of HTTP, but they didn’t change any existing links, or provide a nice easy button to press to do this.

what does the content of an ics file look like anyway?

ICS files just contains structured plaintext. So your usernames, passwords, phone numbers, email addresses, dates, times and locations are all sent in a very easy to read format. Any typical off-the-shelf network traffic scanning tool will be able to easily pick out your sensitive information from the data for later abuse.

http security headers

There is a new breed of HTTP response headers, the sole purpose of which is to improve the security of your site for your readers.

In the following post, I’m going to describe the most popular headers, what they do, and why you should use them.

Content-Security-Policy: connect-src 'none' ;
    font-src 'self' ;
    form-action 'none' ;
    frame-ancestors 'none' ;
    child-src ;
    img-src 'self' data: ;
    media-src 'none' ;
    object-src 'none' ;
    script-src 'self'
        'unsafe-inline' ;
    style-src 'self' ;
    default-src 'none'
Strict-Transport-Security: max-age=31531337; includeSubDomains; preload
Upgrade-Insecure-Requests: 1
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1 ; mode=block
Public-Key-Pins: pin-sha256="abcabcabcabcabcabcabcabcabcabcabc=="; max-age=31531337 ; includeSubdomains;

Content-Security-Policy (CSP)

This header tells the browser where it is allowed to fetch extra content from. It basically helps thwart code injection attacks that would normally fetch and run code from a remote site hosting malicious code.
This injected code could be unwittingly served from your website, or could be injected in mid-air MITM style.

Strict-Transport-Security (HSTS)

This header should ONLY be included in your headers when served over HTTPS, otherwise it is a breach of the specification. This is pretty much because this header is saying “Always Use HTTPS” and to put it in the HTTP header enables a MITM attack to remove the header entirely, which provides you as a site owner with a false sense of security that you’ve used the header in the first place.

You should be upgrading all HTTP requests to HTTPS and setting this header on all subsequent HTTPS responses – this way any browser that re-connects to your site won’t attempt to connect using HTTP, it will remember to only use HTTPS. This is helpful for when you have an old site with lots of links around the place referring to your site using the HTTP protocol.


This header is somewhat redundant with site-wide usage of HSTS, but if portions of your site are still HTTP and are being migrated to HTTPS, this is the header you should use in your HTTP (not HTTPS) responses to tell the browser that all links in the content being served should be treated as if they were `https://` instead of `http://`.


The only value for this header is `nosniff`. It basically prevents the browser from trying to guess the content type of a fetched resource.
This adds a useful stop-gap in the event that one of the resources being referenced from your site changes from something benign to something malicious – if an image hosted on your server is replaced somehow with malicious JavaScript, but the header type being returned along with the javascript is still `Content-Type: image/png` or similar, then the browser should try to interpret that JavaScript as an image, and if it fails, then ignore it, raise an error, and move on.

Historically, where the Content-Type of data returned from a request doesn’t match what the browser is expecting, the browser takes it upon itself to try to guess the content type to use the content anyway, which lead to security issues.


Prevent your site from being served from within someone else’s `iframe`. This has been a popular way for hackers and clickjackers to make you think you are browsing one site, but instead you are just browsing the site through an invisible frame in a different site. This enables mouse or keyboard actions on the iframe (making it look like you’re clicking on your site) to be hijacked and/or recorded.

The `SAMEORIGIN` policy as used above, ensures any iframes linking to [parts of] your site are themselves hosted on the same domain as your site itself. So you can have parts of your own site in your own iframes, but no other domains are allowed to host an iframe pointing to [parts of] your site.


This header is largely redundant, in that XSS protection should be enabled by default in all browsers anyway, but this serves to forcefully turn it on if it isn’t already.

Cross-Site Scripting can happen in several ways, but generally involves scripts executed on a different site to send requests from that site to your site, but to make it look like the user is doing it deliberately. A common scenario is that a request launched via JavaScript from `` makes a `POST` request to your site, e.g. to perform some action that only that user can perform, such as update their password… Or transfer money from their bank account…

Public-Key-Pins (PKP)

This is a way of “pinning” the SSL certificate your site is using to your domain, so if a server tries to impersonate your site, the SSL connection will be rejected, as they won’t have the site certificate they need.

These days there are a lot more CAs than there ever used to be, and recently there have been some emerging that offer free SSL certificates – like Let’s Encrypt for example.
(Incidentally, I wholly recommend this site and will be switching my site over to using it very soon.)

In the event that the domain is DNS hijacked, your browser may try to make an SSL connection to a new server… if this happens for a long enough time period, an SSL certificate could be systematically issued to this new server, so when you connect to this new server, you’d see the pleasing green address bar (assuming their very new certificate is valid), and the domain name matches what you originally typed in.
At this point, before you’ve even typed anything in, your browser has sent this malicious site your protected session cookies, and possibly even entered your username and password into the login dialog on your behalf, if you’ve got a password manager that does this for you.

Your browser doesn’t know not to do this! It’s a legitimate site that you’ve logged into before, it’s just got a different SSL certificate, but who cares, right? As long as it’s valid?!…..

Public Key Pinning means that when you connect to a legitimate site with SSL, the browser will remember the signature of that certificate until it expires (with some extra conditions to enable the certificate to be updated).

So when a MITM attack does happen and your browser tries to connect to this new IP with HTTPS, it will be automatically rejected and you should receive a nice big red warning page telling you the site certificate is not what it expected.
This thwarts an attack that is getting progressively easier and cheaper to carry out.

*   *   *

At last count there were 176 Root CAs in the list bundled within Mozilla Firefox.

These authorities are trusted implicitly – any valid certificate signed by one of these is trusted by your browser, at least unless it violates the PKP header.

These CAs sign certificates for “Intermediate Certificate Authorities” who in turn can sign certificates for other intermediate CAs, as well as the usual end-user domains.

This all means that there is a whole heap of delegated trust out there, just one of those CAs or intermediate CAs needs to be compromised in order to allow the hacker to sign certificates for any domain they like, and carry out highly successful MITM attacks without detection.

/! If you install your own root CA certificate into your system, you’d better make sure that the private key for that certificate is kept somewhere *really really safe* – because if anyone else gets hold of it, they can perform a MITM attack against you on any site and you probably won’t notice.

Companies unfortunately use internal root CA certificates quite a bit, primarily so that they can easily manage secure connections within the company intranet, but it also enables them to intercept all your other SSL connection setup requests at the gateway, and effectively perform a MITM attack against you at your work’s gateway, albeit with less malicious intentions… (you hope.) So do you trust your company to handle this certificate responsibly? If it gets into the wrong hands, a person with malicious intentions could intercept and read all of your communications made on the company network.

All of them. (Except the ones protected with PKP!)

This is why it’s a big deal when owners of root CA certificates misbehave – the consequences could be catastrophic.

Similarly, when CAs are compromised – it will undoubtedly end badly for the company responsible, or they will at least have the wrath of governments to deal with. These incidents undermine the security that is fundamental to the Internet.

According to Scott Helme’s research, only 0.0265% of sites in the top 1 million sites on the web (according to Alexa rankings) were using PKP. This is a little concerning, given what we’ve just learned – and although this number has increased by ~68% in 6 months, it’s still a tiny number. Companies aren’t doing enough, but maybe

I leave the choice up to you which security headers you use on your site. I suggest you use them all.

WordPress Plugin

I have written a WordPress plugin that enables the owner to add their own custom HTTP response headers to their WordPress site. I wrote it because I couldn’t find any existing plugin that enabled me to do this, at least not with the flexibility I wanted.
This is the method I used to add (nearly) all of the security headers described in this blog, to my site.

Check it out here: Headit.

Further Reading