The profile page
let customers add a website.
The rule was simple.
It had to start with https,
then a host name,
and nothing else.
The check was one line of Ruby.
url =~ /^https:\/\/[a-z0-9.-]+$/
Start of the string,
end of the string,
or so everyone read it.
In Ruby
^ and $ do not mean that.
They mean the start and end
of a line.
Any line.
So someone saved a website
with two lines in it.
javascript:alert(document.cookie)//
then a newline,
https://example.com
The second line matched.
The check passed.
The value went into an href
on every page
that showed the profile.
Browsers remove newlines
from URLs before they use them.
So the link became
javascript:alert(document.cookie)// https://example.com
The first part ran as script.
The two slashes
turned the rest into a comment.
Anyone who clicked
ran the attacker's code
inside their own session.
Ruby is not the only one.
In Python
$ also matches
just before a newline
at the very end.
re.match(r"^[a-z0-9_]+$",…