presidentbeef/brakeman

View on GitHub
docs/warning_types/cross_site_scripting_to_json/index.markdown

Summary

Maintainability
Test Coverage
Cross-site scripting (or XSS) is #2 on the 2010 [OWASP Top Ten](https://www.owasp.org/index.php/Top_10_2010-A2) web security risks and it pops up nearly everywhere.

XSS occurs when a user-manipulatable value is displayed on a web page without escaping it, allowing someone to inject Javascript or HTML into the page.  Calls to `Hash#to_json` can be used to trigger XSS.  Brakeman will check to see if there are any calls to `Hash#to_json` with `ActiveSupport#escape_html_entities_in_json` set to false (or if you are running Rails < 2.1.0 which did not have this functionality).

`ActiveSupport#escape_html_entities_in_json` was introduced in the "new\_rails\_defaults" initializer in Rails 2.1.0 which is set to `false` by default.  In Rails 3.0.0, `true` became the default setting.  Setting this value to `true` will automatically escape '<', '>', '&' which are commonly used to break out of code generated by a to\_json call.

See [ActiveSupport#escape\_html\_entities\_in\_json](http://rubydoc.info/docs/rails/ActiveSupport/JSON/Encoding.escape_html_entities_in_json=) for more details.

### Exploiting to\_json

Consider the following snippet of Rails 2.x ERB:

    # controller
    @attrs = {:email => 'some@email.com</script><script>alert(document.domain)//'}

    <!-- view -->
    <script>
      var attributes = <%= @attrs.to_json %>
    </script>

Which generates the following html:

    <script>
      var attributes = {"email":"some@email.com</script><script>alert(document.domain)//"}
    </script>

While the generated Javascript appears valid, the browser parses the script tags first, so it sees something like this:

    <script>
      var attributes = {"email":"some@email.com
    </script>
    <script>
      alert(document.domain)//"}
    </script>

The attribute assignment causes a Javascript error, but the alert triggers just fine!

With `escape_html_entities_in_json = true`, you will receive the following innocuous output:

    <script>
      var attributes = {"email":"some@email.com\u003C/script\u003E\u003Cscript\u003Ealert(document.domain)//"}
    </script>