mozilla / nunjucks

A powerful templating engine with inheritance, asynchronous control, and more (jinja2 inspired)
https://mozilla.github.io/nunjucks/
BSD 2-Clause "Simplified" License
8.58k stars 639 forks source link

sandboxed environment #271

Open pierre-b opened 10 years ago

pierre-b commented 10 years ago

Hello everyone,

Could you please tell me if it's possible to sandbox the environment ? Users of my app will be allowed to customize their own emails templates and I would like to restrict some features.

Here is how Twig handles that: http://twig.sensiolabs.org/doc/api.html#sandbox-extension

Thanks

jlongster commented 9 years ago

We do not have a sandbox. I would love to have this feature, but I don't have time to work on it. A PR would be awesome :)

jlongster commented 9 years ago

Actually let's leave this open as a feature

damianstasik commented 5 years ago

@jlongster I know that you do not work on this project anymore, but could you tell me how would you go about implementing the sandbox environment? Anything would be really helpful! There are so many things that one could do to break out of sandbox 😞

fdintino commented 5 years ago

In node, you could use a package such as vm2 to render untrusted nunjucks templates inside an isolated execution context.

A-312 commented 5 years ago

Exemple of problem : https://github.com/mozilla/nunjucks/issues/1048#issuecomment-355869811

This can prevent with hasOwnProperty.

I wonder if we can make a change, a full security change. Is it possible make a change afterwards ? I mean the code wasn't designed to be safe/sandboxed.

squirrelchew commented 2 years ago

I'm unconvinced vm2 fully solves it.

nunjucks requires fs, events, and path to be available and the eval option to be set to true in a NodeVM in order to execute. the available examples I've found and played with still allow access to .constructor (I think as a result of eval:true ?) and as such allow RCE, although vaguely restricted.

The example available in the referenced thread above still works in a vm2 sandbox:

{{ (0).toString.constructor("return global.process.versions")() | dump | safe }}

though it does seem to resolve this, claiming require isn't available:

{{ "".constructor.__proto__.constructor("return require(`fs`).readFileSync(`Users/squirrelchew/.aws/credentials`, `utf8`)")() }}

vect-ybetou commented 10 months ago

Hello,

I ran into this issue recently and came with a solution using isolated-vm and the built version of nunjucks. It allows to render template in isolated secure env.

const ivm = require('isolated-vm');
const fs = require('fs');
const directNunjucks = require('nunjucks');
const isolate = new ivm.Isolate({ memoryLimit: 128 });

const codeNunjucks = fs.readFileSync(__dirname + '/node_modules/nunjucks/browser/nunjucks.min.js', 'utf8');

//we need to wrap the nunjucks browser code with a 'self' context
const isolatedModuleCode = `let self = {};

${codeNunjucks}

export default self;`;

const module1 = isolate.compileModuleSync(isolatedModuleCode);

const context = isolate.createContextSync();

module1.instantiateSync(context, (specifier, mod) => {
  return mod;
});
module1.evaluateSync();

const modref = module1.namespace.getSync('default');
const nunjucksIsolated = modref.getSync('nunjucks')
const nunjucksIsolatedRS = nunjucksIsolated.getSync('renderString')

//---

const template = 'zzzz {{ val }} {{ (0).toString.constructor("return global.process.versions")() | dump | safe }}';
const data = { val : 'test'};

const direct = directNunjucks.renderString(template, data);
console.log(direct); // will ouput sensitive data

const isolatedResult = nunjucksIsolatedRS(template, data);// will fail
console.log(isolatedResult); 

But you might lose some important nunjucks features, for example you will get no access to the filesystem. Imagine running nunjucks into a limited browser context.

vect-ybetou commented 9 months ago

@huggingface/jinja might help for some use cases as well