This document describes common OAuth/Single Sign On/OpenID-related vulnerabilities. Many cross-site interactions are vulnerable to different kinds of leakings and hijackings.
Both hackers and developers can benefit from reading it.
Because of OAuth many startups including Soundcloud, Foursquare, Airbnb, About.me, Bit.ly, Pinterest, Digg, Stumbleupon, Songkick had an account hijacking vulnerability. And a lot of websites are still vulnerable. Our motivation is to make people aware of "Social login" risks, and we encourage you to use OAuth very carefully.
The cheatsheet does not explain how OAuth flows work, please look for it on the official website.
Also known as The Most Common OAuth2 Vulnerability. In other words, CSRF.
code by redirecting user-agent to
Now the client must send
code along with client credentials and
redirect_uri to obtain
If the client implementation doesn't use
state parameter to mitigate CSRF, we can easily connect our provider account to the victim's client account.
It works for clients with social login and ability to add a login option to existing master account (screenshots of pinterest.com below).
Remediation: Before sending user to the provider generate a random nonce and save it in cookies or session. When user is back make sure
state you received is equal one from cookies.
This is another OAuth design issue - sometimes developers want to use
state for own purposes. Although you can send both values concatenated
state=welcome_landing.random_nonce, but no doubt it looks ugly. A neat solution is to use JSON Web Token as state
Even if the client properly validates the
state we are able to replace auth cookies on the provider with the attacker's account: using CSRF on login (VK, Facebook), header injection, or cookie forcing or tossing.
Then we just load a GET request triggering connect (
/user/auth/facebook in omniauth), Facebook will respond with the attacker's user info (uid=attacker's uid) and it will eventually connect the attacker's provider account to the victim's client account.
Remediation: make sure that adding a new social connection requires a valid csrf_token, so it is not possible to trigger the process with CSRF. Ideally, use POST instead of GET.
Facebook refused to fix CSRF on login from their side, and many libraries remain vulnerable. Do not expect providers to give you reliable authentication data.
OAuth documentation makes it clear that providers must check the first
redirect_uri is equal
redirect_uri the client uses to obtain
We didn't really check this because it looked too hard to get it wrong.
Surprisingly many providers got it wrong: Foursquare (reported), VK (report, in Russian), Github (could be used to leak tokens to private repos), and a lot of "home made" Single Sign Ons.
The attack is straightforward: find a leaking page on the client's domain, insert cross domain image or a link to your website, then use this page as
When your victim will load crafted URL it will send him to
leaking_page?code=CODE and victim's user-agent will expose the code in the Referrer header.
Now you can re-use leaked authorization code on the actual
redirect_uri to log in the victim account.
redirect_uri is a bad practise. But if you need it, store redirect_uri for every code you issue and verify it on access_token creation.
It was a media hype called "cover redirect" but in fact it was known for years. You simply need to find an open redirect on the client's domain or its subdomains, send it as
redirect_uri and replace
access_token can be used for spam and ruining your privacy.
signed_request is even more sensitive data. By finding an open redirect on the client you compromise Login with Facebook completely.
Remediation: whitelist only one redirect_uri in app's settings:
Also known as One Token to Rule Them All. This bug is relevant to mobile and client-side apps, because they often use access_token directly supplied by the user.
Imagine, user has many "authorization rings" and gives a ring to every new website where he wants to log in. A malicious website admin can use rings of its users to log in other websites his customers have accounts on.
Remediation: Before accepting user supplied access_token check if it was issued for your
For better support of client-side applications (or browser apps) some of OAuth 2 providers added an out-of-specs custom variant of implicit flow, involving a proxy/relay page as a sort of router for access tokens. This proxy communicates with the client page of application either through standard HTML5 postMessage API, or using legacy ways: manipulating window name and url (known as Fragment transport, rmr) and Adobe Flash LocalConnection API.
Regardless of the selected method, it is important to ensure that proxy can exchange messages only with the target origin, to disallow malicious page from impersonating the application page, and finally to verify that these client-side checks are consistent with server-side checks. Fail to properly secure client-side transport usually results in two kinds of problems:
- leaking data to an attacker (authorization and authentication bypass , )
- trusting data from an attacker (session fixation , )
- Completely disable all legacy client-side communication methods (Flash or Fragment), use postMessage
- Check origins of all incoming and outgoing messages, allow only the target application domain
- Ensure that all client-side origin checks are consistent with server-side origin checks
- Use a cryptographic nonce validation before starting data transmission with another party
Client credetials are not as important as it sounds. All you can do is using leaking pages to leak auth code, then manually getting an access_token for them (providing leaking redirect_uri instead of actual). Even this threat can be mitigated when providers use static redirect_uri.
Main difference between OAuth2 and 1 is the way you transfer parameters to providers. In the first version you send all parameters to the provider and obtain according request_token. Then you navigate user to
provider?request_token=TOKEN and after authorization user is redirected back to
The idea of fixation here is we can trick user into accepting Token1 supplied by us which was issued for us, then re-use Token1 on the client's callback.
This is not a severe vulnerability because it is mostly based on phishing. FYI Paypal express checkout has this bug
Many startups have Facebook Connect, and at the same time they are providers too. Being providers, they must redirect users to 3rd party websites, and those are "open redirects" you just cannot fix. It makes this chain possible: Facebook -> Middleware Provider -> Client's callback, leading to FB token leakage.
To fix this problem Facebook adds
#_=_ in the end of callback URLs. Your startup should "kill" fragment to prevent leaking. Redirect this way:
If you are allowed to set subdirectory here are path traversal tricks:
/old/path/.%0a./.%0d./new/path (For Rails, because it strips \n\d\0)
code is sent via GET and potentionally will be stored in the logs. Providers must delete it after use or expire in 5 minutes.
Usually you need a referrer-leaking page to leak ?query parameters. There are two tricks to do it with an open redirect though:
- When redirect uses
<meta>tag instead of 302 status and Location header. It will leak redirecting page's referrer to in the next request.
- When you managed to add
%23(#) in the end of
redirect_uri. It will result in sending the code in the fragment