-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add warning against running untrusted templates #17
Comments
Good point! I wonder if other templating autoescaping escapes |
Auto-escaping works on the variables you feed into the template, not in the template itself. (and correctly fixes the problem: http://jsfiddle.net/vjeux/3rzsn4sy/ ). What I'm trying to point here is that it's not safe to have the user define the template itself. |
Oh, duh, right. I misinterpreted. Yeah, of course by default it will output HTML. I will add a warning to the docs. |
I think the fact that rendering a template can execute arbitrary javascript code on the server is even more unexpected nunjucks.renderString('{{a.constructor.__proto__.constructor("alert()")()}}'); |
We parse a grammar similar to JS, and output the corresponding JS to the AST, so yes, those holes are exposed. Accessing native methods is an easy way to get a lot for free, so users can just do {{ arr.length }} and stuff. You're right though; we should blacklist a few properties that allow you to access this so that this safety is on by default. I know other engines have a "sandboxed" mode which we could also support. Is there anything other than Regardless, I will add a warning that we don't guarantee a full sandboxed mode yet. |
Blacklisting properties is very dangerous. If you ever attempt to have a sandboxed mode, I would highly recommend you talk to someone with a web security background. Cure53 audited most of the template engines out there. https://code.google.com/p/mustache-security/ They also privately audited React and had a lot of good suggestions to improve it's security edge cases :) |
Yeah, blackboxing is just a false sense of security. Nunjucks does not really provide a solution for user-defined templates that should not be able to run arbitrary JS. Some of the current products that use nunjucks are CMS-es where this doesn't matter, because you are using it to customize your own site and you could freely run JS in just a Handlebars is a better solution for a completely safe user-defined template. I will add notes about this in the docs somewhere. |
I added a warning in the updated docs (published soon, thanks!) |
For those reading this, there are two bits of info that may be helpful:
|
Hi @vjeux, what exactly is this supposed to do, and how does it work? nunjucks.renderString('{{a.constructor.__proto__.constructor("alert()")()}}'); I checked out the JSFiddle and it doesn't do anything. I'm guessing it's because I'm on a newer version of Chrome? |
The variable |
Thanks @vjeux! |
In JavaScript, you can define a function statically: function() { alert() } or dynamically from a string Function("alert()") I'm using Once you have a function created like this, you can call it Function("alert()")() in order to execute it. So now, the game is all about figuring out a way to access the If you have access to any function, you can get (function() {}).constructor === Function // true nunjucks won't let you define anonymous functions like that either. If it would, we could just have done What we can do is to create a new object and ask for its constructor, which is a function. We don't really care what that function does, the important thing is that it's a function. ({}).constructor // function from there, we can access ({}).constructor.constructor === Function // true At this point we won, now we just need to assemble everything back together ({}).constructor.constructor("alert()")() and we're done. In the example above I added a |
Thanks so much @vjeux! I'm re-writing my template engine, Squirrelly, and wondering if I should implement some of these protections like preventing the user from accessing global variables, etc. Currently, I'm thinking that I'll just have Squirrelly as a tool to output untrusted JavaScript, and a tool which shouldn't be used with untrusted data or templates. In your opinion, does this sound like a bad idea? |
You should likely treat the data that you pass as untrusted: if someone sets his username as For templates, if they are part of a build system and only requiring sources checked in the repo. Then this is trusted and fine. But for a lot of template systems, it's just a function call with a string. So it's --very easy-- to have someone that work in your codebase pass a dynamic string that is built with user-provided information. Then you're screwed if you don't have a proper sandbox, which all the templating engines that were written pre-react that I know about didn't have. If you go that route, be aware that doing proper protection is --very hard--. You should look at projects like https://developers.google.com/caja/ instead of trying to fix it yourself. |
Can't you just use something like DOMPurify as a wrapper to fix this issue? |
I talked to people that are under the impression that it's safe to feed user-defined templates to nunjucks. However it is not. It may be good to add a warning about this.
Proof of concept to run arbitrary code on viewers: http://jsfiddle.net/vjeux/q55ads7r/
Proof of concept to run arbitrary code on the execution environment: http://jsfiddle.net/vjeux/2kcjjgt2/
The text was updated successfully, but these errors were encountered: