Export to GitHub

mustache-security - CanJS.wiki


Introduction

"Want to share code between a Zepto mobile app and a jQuery desktop app? No problem. CanJS code (especially models) can be shared across libraries, and so can skill sets! Working on a Dojo project today and a YUI one tomorrow? Don’t throw away all of your skills."

From http://canjs.com/guides/Why.html

Quick Facts

  • CanJS 1.1.6 (Uncompressed)
  • CanJS 2.0.3 (Uncompressed)
  • Usage Stats http://trends.builtwith.com/framework/CanJS

  • {}SEC-A FAIL Template expressions are equivalent to eval

  • {}SEC-B FAIL No sandbox or isolated execution scope
  • {}SEC-C PASS Only SCRIPT elements with proper type can serve as template containers
  • {}SEC-D FAIL No enforced separation, no obvious way to outsource templates to static files
  • {}SEC-E FAIL No dedicated security response program, no security@canjs.com address

Injection Attacks

CanJS uses ERB-style templates by default. Everything that is placed in-between the <% and %> or its siblings is being treated as raw JavaScript. CanJS throws the content of the ERB-style templates into an actual eval method - that is called myEval but doesn't do anything but wrapping the real eval.

In other words: whenever the user has control over content of the ERB-style template blocks, script injections and XSS are very much likely. The "paste-and-go" code example below shows several cases an attacker can use to bypass server- and browser side XSS filters in case the attacked CanJS application allows injections.

```

<% alert(0) %> > > <%== '\x3Cimg src=x onerror=alert(3)>' %> <%%= '' %> can.view('todoList', {}); ```

Another injection problem can be abused by using a concatenation feature that will be discussed later on this page.

```

<%==($a)->abc})-alert(1)-can.proxy(function(){%> can.view('todoList', {}); ```

Now, how do these work internally?

Eval via myEval

CanJS takes it easy and simply throws the extracted template data into a string, wrapped by a bunch of with() blocks and afterwards sends it to an eval. That's all.

``` myEval = function(script) { eval(script); },

[...]

var template = buff.join(''), out = { out: 'with(_VIEW) { with (_CONTEXT) {' + template + " " + finishTxt + "}}" }; // Use eval instead of creating a function, because it is easier to debug. myEval.call(out, 'this.fn = (function(_CONTEXT,_VIEW){' + out.out + '});\r\n//@ sourceURL=' + name + ".js");

return out; ```

Eval via string.concatenated code in Scanner.helpers.fn()

CanJS shows no mercy when coming to quirky injection sinks. Aside from the aforementioned eval via myEval, CanJS also allows to inject code into a string-concatenated call against can.proxy() - that is later being evaluated.

``` Scanner.prototype = {

        helpers: [

            {
                name: /\s*\(([\$\w]+)\)\s*->([^\n]*)/,
                fn: function(content) {
                    var quickFunc = /\s*\(([\$\w]+)\)\s*->([^\n]*)/,
                        parts = content.match(quickFunc);

                    return "can.proxy(function(__){var " + parts[1] + "=can.$(__);" + parts[2] + "}, this);";
                }
            }
        ],

```