Skip to content
This repository has been archived by the owner on Jun 6, 2024. It is now read-only.

inconsistency: disallow new Function() eval() loophole #146

Open
iameli opened this issue Mar 8, 2020 · 4 comments · May be fixed by #149
Open

inconsistency: disallow new Function() eval() loophole #146

iameli opened this issue Mar 8, 2020 · 4 comments · May be fixed by #149

Comments

@iameli
Copy link

iameli commented Mar 8, 2020

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 iameli changed the title Disallow new Function() eval() loophole desync: disallow new Function() eval() loophole Mar 8, 2020
@iameli
Copy link
Author

iameli commented Mar 8, 2020

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 iameli changed the title desync: disallow new Function() eval() loophole inconsistency: disallow new Function() eval() loophole Mar 8, 2020
@iameli
Copy link
Author

iameli commented Mar 8, 2020

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
Copy link
Author

iameli commented Mar 8, 2020

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

@xtuc
Copy link

xtuc commented Mar 9, 2020

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).

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants