No, in modern browsers no XSS is possible via the style
or src
attribute of an <img>
tag.
So neither of these would execute the JS code in any up-to-date browser:
<img src="javascript:alert(1)">
<img src="x.jpg" style=background-image:url('javascript:alert(2)')">
Support for Javascript in CSS attributes has long been abandoned. You can find some older references about it here.
Analysis of your example code
location.hash
always starts with a #
symbol. Since this character is illegal in JS and not a valid beginnig of a new URL, no XSS would be possible in the first place. (For instance, eval(location.hash)
always produces a syntax error.)
Let's assume, you ignore the #
and location.hash
could really contain any string you want.
Then this security check is flawed:
(location.hash.indexOf('javascript:') !== 0)
An attacker could still construct a URL starting with JaVaScRiPt:
. Also, it's risky to assume that no implementation would ever allow leading spaces or control characters (e.g. \t\x00javascript:
). And what about URL-encoding? A payload starting with javascript%3a
would pass your filter. Also, do you want to allow the data:
protocol? If you like to restrict the URL to absolute locations, you could whitelist the beginnings http://
and https://
instead of blacklisting javascript:
.
This is fine:
img.src='some/local/path/'+location.hash;
Even if the src
attribute was susceptible to script code, your prefix some/local/path/
ensures that it cannot be turned into a JS URL. However, an attacker could specify any relative path to an image file on the same server, which you might find undesirable.
NB: This is about constructing malicious javascript:
URLs. If you want to use user-controlled values like location.hash
for HTML output or a different context, you have to properly sanitize the string.