Brakeman

Ruby on Rails Static Analysis Security Tool

Cross Site Scripting (JSON)

Cross site scripting (or XSS) is #2 on the 2010 OWASP Top Ten 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 for more details.

Exploiting to_json

Consider the following snippet of Rails 2.x ERB:

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

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

Which generates the following html:

<script>
  var attributes = {"email":"[email protected]</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":"[email protected]
</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":"[email protected]\u003C/script\u003E\u003Cscript\u003Ealert(document.domain)//"}
</script>

Back to Warning Types