I have a client who got a security check done on their site (they are a security company) and they came back with this in relation to an expresso store checkout:

  1. Checkout functionality

Although there was good input filtering in place on the checkout functionality, the team were able to inject html tags into the response. An attacker with sufficient time would likely to be able to construct a viable XSS payload. The following parameters were found to be vulnerable:

/shop/checkout [billing_address1 parameter]

/shop/checkout [billing_address2 parameter]

/shop/checkout [billing_city parameter]

/shop/checkout [billing_first_name parameter]

/shop/checkout [billing_last_name parameter]

/shop/checkout [billing_phone parameter]

/shop/checkout [billing_postcode parameter]

/shop/checkout [order_email parameter]

The team also observed that these values are stored in a database, meaning stored XSS attacks are feasibly possible, although the team could not identify a location where the values are subsequently output.

Basically, I can enter <script> into the field inputs, which comes back as [removed] in my form, which is great. But I was able to add the following into my input field for the billing name:


And it saved this into the database along with my name.

So my real question is: what are the security implications of this, and is there a 'dictionary of bad things' file somewhere I can add the above tags to in EE that when submitted, my form will come back with [removed] like it did with the script tag?

3 Answers 3


I too have been faced with rather demanding security injection testing on EE (and non EE) sites so I can fee lyour pain, and speak from some experiance.

First the direct answer to your question. There isn't a directory/list, however you can read and modify the security library here (it uses the CodeIgniter Lib, whcih is assimilated by the EE_Security file) :


Let me stress You SHOULD NOT edit or tamper with these files however warnings aside you'll see the defined naughty strings in the top of the file...

Next take a look at line 276 of the CI Security lib, you see how your naughty words are in there?

So one of 2 things is happening, either the naughty tags are getting properly encoded into the DB (ie &lt;applet&gt;) and are getting transformed or unencoded before display (uh ho), resulting in correct storage, incorrect display, or there is a problem with the sanitisor and it's not picking them up properly.

This tells us that in fact Expresso checkout might be avoiding the XSS filter somehow, or it is using its own...

If you look to this page (https://ellislab.com/expressionengine/user-guide/development/guidelines/security.html#cross-site-scripting-xss) you'll see the real hint, XSS filtering is not applied by default to GET or POST. ( I beleive the script check might be, but not extended XSS filtering)

What I would be inclined to do is check your Expresso version (ensure it's latest and greatest) and check your EE version for how it applies XS filtering to normal POST values.

If you can still inject <applet> ect then I'd get into the module files for expresso checkout and find where the values are taken from the POST. Expresso should be using ee()->input->post('var_name', true); to fetch values (the second parameter is for applying XSS filtering).

If this is missing you could simply add the true second parameter and you should be good to go (apart from having to edit a 3rd party module).

If they are using the $_POST directly (tut tut) then you'll have to add a call to xss_clean function, by example :

//expresso retreived the value
$retrievedValue = $_POST['myvalue'];

//START Added Code : we'll clean this for you!
$retrievedValue = ee()->security->xss_clean($retrievedValue )
//END Added Code

//expresso uses the value

Either way debug the values as you go and you should be able to identify the why and the resolution.

Let us know how you get on fella, and keep the faith, cleaning a site for a strict security pen test can be a bit of a grind, but you'll get there and you'll know all about securing EE sites next time! :)


Remember EE is built on CI, so in many cases you can refer to the CI docs.

See here for info on the input library of CI : https://ellislab.com/codeigniter/user-guide/libraries/input.html

And here for the security library : https://ellislab.com/codeigniter/user-guide/libraries/security.html

  • A quick look at v2.5 of Store and all $_POST variables are thrown through this method: $this->ee->security->xss_clean($_POST). Specific to the question: CheckoutAction.php line 55. ellislab.com/expressionengine/user-guide/development/guidelines/… Apr 10, 2015 at 12:28
  • Ohhhh, that is strange then. CI Security should be encoding those <applet> tags into &gt;applet&lt;. Can you debug in the security library to see what exacly is getting cleaned and what isn't around line 276? It may be that the value is encoded and saved, then on display it is rendering the html entity < and >. otherwise if it's saving the unencoded entity you'd have to debug the xss_clean function further to see why not...
    – Blatant
    Apr 10, 2015 at 12:35
  • [removed] not relivent
    – Blatant
    Apr 10, 2015 at 12:38
  • ok I tested it in store and it looks like it is encoded as &lt;object&gt;&lt;APPLET>&lt;embed&gt;&lt;form>, but does this alleviate the problem since it is encoded back when displayed? Would this answer satisfy a pen test?
    – Aaron
    Apr 10, 2015 at 14:18
  • depends, if it literally displays <object><APPLET><embed><form> on the page then this is clean (you can further clean it on dispaly by doing the old php strip_tags before echoing it out). You can tell the security firm that the tags are encoded and not renderable. If however it actually renders the form, applet or embed on the page (try with a standard youtube embed perhaps?) then it is getting un-escaped before being echoed out (i.e. your echoing < not &lt; to the output) and is a security concern.
    – Blatant
    Apr 10, 2015 at 14:26

I'm going to start another answer as the question and solution seem to have departed from the previous answer. The previous answer shows that we have debugged and checked that XSS filtering is actually taking and the correctly encoded values are saved in the database.

So now we just need to determin that, anywhere these fields are displayed (frontend or CP) are they displayed in their encoded form (i.e. using html elements &lt; and &gt;) or are they being decoded before display (i.e. < and >).

The former would be considered safe, though not optimal. It's basically behaving a bit like htmlspecialchars(). You could improve this by decoding the sting in PHP, running it through strip_tags() and re-encoding (for saftey) before display anlthough this is just an enhancement to stop the naughty user from seeing their results.

The latter would be considered unsafe, as the malicious user can input some markup, allow it to be saved encoded and displayed uncoded, thus allowing injection. If this is the case the solution is the same, but required to 'make safe', either strip the tags before calling xss_clean (let it clean a tidier string) to clean before save (the determined hacker could work out other ways to encode the lt and gt (like unicode) so this in itself is not 100%) or better would be to also ensure wherever it is displayed, make sure to pass the output through strip_tags() to obfuscate the tags that where saved as encoded.

I personally beleive that the OP is referring to the first case where the html encoded output is being displayed on the page, but I'm sure Aaron will re-confirm soon!

Perhaps Aaron can also confirm exactly what the security company has stated, did they indicate where the display was happening? Did they provide a recommendation on resolution? If they did we can probably fashion the solution to meet their requirements, which is much easier than trying to convince them that this case doesn't break their rules, or get them to modify their rules...

  • Inspecting the admin panel (for the store order view) in chrome shows me rendered <> tags and not &lt; etc. so it would seem they are being decoded before display. They are indeed recorded in the DB as encoded values. I can't actually change the values of this 'incomplete' order int he store amdin panel, as the ability to change the status is not available
    – Aaron
    Apr 10, 2015 at 16:30
  • Also, I haven't spit this information out to the page anywhere, I only put these sample tags in to test it on my local install, so it is only rendering for the moment in the store admin order view in my name field
    – Aaron
    Apr 10, 2015 at 16:32
  • I'd definatly run the output thorugh strip_tags() or something like that then before display. Also check the views of expresso in case it could be displayed anywhere else like account -> previous orders.
    – Blatant
    Apr 10, 2015 at 16:37
  • I will refer the guys in store and my client to this as well. Thanks for your input on this. The EE community pretty much rocks because of people like you.
    – Aaron
    Apr 10, 2015 at 16:47
  • Very happy to have helped :) i remember my last site with pen test, and the issues where server level as well as CMS and site level, that was an ordeal! Hope you get the A grade after all your dilligence!
    – Blatant
    Apr 10, 2015 at 17:06

The fix for this (thanks Store guys!) is here:


under this (line 57 ish)

$form_params = $this->form_params(); $update_data = $this->ee->security->xss_clean($_POST); $cart = $this->ee->store->orders->get_cart();

Put this:

    // check to remove any html
    foreach ($update_data as $key => $val) {
        if (strpos($key, 'billing_') === false && strpos($key, 'shipping_') === false) continue;
        $val = html_entity_decode($val);
        $val = str_replace('[removed]', '', $val);
        $update_data[$key] = strip_tags($val);

And all html, including the [removed] notice that EE catches is disappeared and never enters the DB

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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