cloudworker icon indicating copy to clipboard operation
cloudworker copied to clipboard

inconsistency: disallow `new Function()` eval() loophole

Open iameli opened this issue 5 years ago • 4 comments

Ajv, the JSON-Schema validator doesn't work on Cloudflare Workers.. It relies on eval()'d code generation, and CF workers don't allow eval().

I was surprised to find that it worked perfectly fine in Cloudworker. I think it's because ajv doesn't actually use eval(), it uses the new Function(<string>) constructor, which we patch into the runtime environment here.

For consistency, we should find a way to disable that mechanism without breaking the foo instanceof Function construct.

iameli avatar Mar 08 '20 00:03 iameli

Hmm, a naive test shows that new Function() doesn't actually work here. Interesting. EIther AJV started working in contexts that disallow code generation or something else is going on... investigating further.

iameli avatar Mar 08 '20 05:03 iameli

Minimal repro case:

import Ajv from "ajv";

const handleEvent = () => {
  try {
    var schema = {
      type: "string"
    };
    var ajv = new Ajv(); // options can be passed, e.g. {allErrors: true}
    var validate = ajv.compile(schema);
    var valid = validate("foo");
    return new Response(`valid: ${valid}`);
  } catch (e) {
    return new Response(e.stack, { status: 500 });
  }
};

addEventListener("fetch", event => {
  event.respondWith(handleEvent());
});

I'm building that with parcel build -t browser --no-minify worker.js. It works with Cloudworker, but in CF itself I get

EvalError: Code generation from strings disallowed for this context
    at new Function (<anonymous>)
    at Ajv.localCompile (worker.js:2946:26)
    at Ajv.resolve (worker.js:2015:19)
    at Object.resolveRef (worker.js:3015:21)
    at Object.generate_ref [as code] (worker.js:3408:22)
    at Object.generate_validate [as validate] (worker.js:2615:37)
    at Object.generate_properties [as code] (worker.js:5344:26)
    at generate_validate (worker.js:2712:35)
    at localCompile (worker.js:2914:22)
    at Ajv.compile (worker.js:2881:13)

Spooky. How is AJV sneaking past vm.createContext(context, {codeGeneration: {strings: false}})?

iameli avatar Mar 08 '20 06:03 iameli

Okay, confirmed my original hypothesis - new Function("true"); seems to get around the ban on code generation.

iameli avatar Mar 08 '20 06:03 iameli

I added a few cases in your PR that should be disallowed. The rule is any evaluation of any generated code is disallowed (wasm is one non obvious case).

xtuc avatar Mar 09 '20 10:03 xtuc