Circumventing OWASP ESAPI for PHP

Školení, která pořádám

Enterprise Security API – what a name! You should expect writing “enterprise level” applications with it. Let's start with the code:

require_once dirname(__FILE__) . "/ESAPI/src/ESAPI.php";
require_once dirname(__FILE__) . "/ESAPI/src/codecs/HTMLEntityCodec.php";

new ESAPI("ESAPI.xml");
$html = new HTMLEntityCodec;
echo $html->encode(array(), "Test.");
// prints: Test&#x2e;

Maybe you wonder what the line new ESAPI("ESAPI.xml") is good for when the created object is not used anywhere? Well, it specifies a configuration which is used as a global variable in the rest of the library. The application just fatals without it.

The method encode has an unusual API: The string to be escaped is passed as the second argument while the first argument is an array of “safe characters”. So the library allows you to shoot you in the foot very easily:

echo $html->encode(range('!', '?'), "<script>alert('XSS');</script>");
// prints: <script>alert('XSS');</script>

What's the default behavior? Basically encoding all non-alphanumeric characters, even those with absolutely no special meaning in HTML. So you can tell the HTMLEntityCodec: Don't touch characters with a special meaning in HTML but encode everything else:

echo $html->encode(array('<', '&', '"', '>'), "<b>Bold.");
// prints: <b>Bold&#x2e;

Very useful!

Circumventing the library

Create a file named Codec.php anywhere in your include_path or in the working directory:

class Codec {
    function __construct() {
    function encode($foo, $s) {
        return $s;

Now run the code from the beginning of this article. What happens? The library works as expected, no warning is issued. The only difference is that no characters are suddenly encoded:

echo $html->encode(array(), "<script>alert('XSS');</script>");
// prints: <script>alert('XSS');</script>

Your application shouldn't of course allow an attacker to create this file on a place where it could be read by require_once. But you can create it for some other purpose or some other library may use it. Codec is a pretty common name. Your application will continue working normally until the day when you realize that ESAPI doesn't work.

I've read the 12 page install guide very thoroughly and there is nothing like “Don't you dare to create a file named Codec.php anywhere in your include_path.”


The first part of the solution is to include the file from an absolute path. I've sent a patch for it.

The second part is avoiding common names like Codec in a general use library. OWASP_ESAPI_Codec or OWASP\ESAPI\Codec (since PHP 5.3) would be more appropriate.


I don't personally plan to use ESAPI for several reasons:

  1. It has a poor API which is hard to use for common operations and allows you to do dangerous things at the same time.
  2. It encodes characters with no special meaning by default so it is doing useless work.
  3. I don't like the way how the code is architectured (e.g. depending on global configuration and fataling if it isn't set).
Jakub Vrána, Dobře míněné rady, 28.3.2012, comments: 0 (new: 0)

Insert Comment

Input is understood as plain text but URLs will be converted to links and PHP code enclosed in <?php ?> will be highlighted.

Name: URL:

avatar © 2005-2018 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.