stylelint: table sub-dependency Ajv breaking Stylelint in environments with blocked eval

Describe the issue. Is it a bug or a feature request (new rule, new option, etc.)?

It seems that in table@3.7.10 a dependency on ajv was brought in from https://github.com/gajus/table/pull/16. Unfortunately it seems this library uses eval to compile the JSON it is asked to validate. table@3.7.9 looks like it should still be safe to run in environments where that is blocked like Atom.

There are a few ways to move forward here:

  • Have Ajv update to no longer eval (unlikely, this looks to be a major part of how it works)
  • Have table move away from unsafe-eval dependencies
  • Move away from table here in stylelint
  • Give up on keeping stylelint able to run in environments where eval is blocked, and have linter-stylelint (and any other place that is using stylelint in an environment like this) run this package through a wrapper library.

Which rule, if any, is this issue related to?

N/A

What CSS is needed to reproduce this issue?

N/A

What stylelint configuration is needed to reproduce this issue?

N/A

Which version of stylelint are you using?

6.0.0 through 7.2.0 (table dependency introduced in https://github.com/stylelint/stylelint/commit/06b0fcd8105319870e1e87c990f10c95587bea62)

How are you running stylelint: CLI, PostCSS plugin, Node API?

Node API

Does your issue relate to non-standard syntax (e.g. SCSS, nesting, etc.)?

N/A

What did you expect to happen?

No unsafe-eval code being ran.

What actually happened (e.g. what warnings or errors you are getting)?

The following error is being thrown:

Stack trace:

EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self'".
    at Ajv.localCompile (/Users/lorisbettazza/.atom/packages/linter-stylelint/node_modules/ajv/lib/compile/index.js:130:26)
    at Ajv.resolve (/Users/lorisbettazza/.atom/packages/linter-stylelint/node_modules/ajv/lib/compile/resolve.js:53:19)
    at Object.resolveRef (/Users/lorisbettazza/.atom/packages/linter-stylelint/node_modules/ajv/lib/compile/index.js:195:21)
    at Object.generate_ref [as code] (/Users/lorisbettazza/.atom/packages/linter-stylelint/node_modules/ajv/lib/dotjs/ref.js:22:22)
    at Object.generate_validate [as validate] (/Users/lorisbettazza/.atom/packages/linter-stylelint/node_modules/ajv/lib/dotjs/validate.js:157:37)
    at Object.generate_properties [as code] (/Users/lorisbettazza/.atom/packages/linter-stylelint/node_modules/ajv/lib/dotjs/properties.js:198:26)
    at generate_validate (/Users/lorisbettazza/.atom/packages/linter-stylelint/node_modules/ajv/lib/dotjs/validate.js:230:37)
    at localCompile (/Users/lorisbettazza/.atom/packages/linter-stylelint/node_modules/ajv/lib/compile/index.js:91:22)
    at Ajv.compile (/Users/lorisbettazza/.atom/packages/linter-stylelint/node_modules/ajv/lib/compile/index.js:59:13)
    at _compile (/Users/lorisbettazza/.atom/packages/linter-stylelint/node_modules/ajv/lib/ajv.js:325:29)
    at getSchema (/Users/lorisbettazza/.atom/packages/linter-stylelint/node_modules/ajv/lib/ajv.js:189:51)
    at validate (/Users/lorisbettazza/.atom/packages/linter-stylelint/node_modules/ajv/lib/ajv.js:88:11)
    at validateSchema (/Users/lorisbettazza/.atom/packages/linter-stylelint/node_modules/ajv/lib/ajv.js:159:19)
    at _addSchema (/Users/lorisbettazza/.atom/packages/linter-stylelint/node_modules/ajv/lib/ajv.js:285:7)
    at Ajv.compile (/Users/lorisbettazza/.atom/packages/linter-stylelint/node_modules/ajv/lib/ajv.js:110:21)
    at Ajv.addKeyword (/Users/lorisbettazza/.atom/packages/linter-stylelint/node_modules/ajv/lib/keyword.js:46:40)
    at defFunc (/Users/lorisbettazza/.atom/packages/linter-stylelint/node_modules/ajv-keywords/keywords/typeof.js:37:7)
    at defineKeywords (/Users/lorisbettazza/.atom/packages/linter-stylelint/node_modules/ajv-keywords/index.js:20:17)
    at Object.<anonymous> (/Users/lorisbettazza/.atom/packages/linter-stylelint/node_modules/table/dist/validateConfig.js:29:27)
    at Module._compile (/Applications/Atom.app/Contents/Resources/app.asar/src/native-compile-cache.js:103:30)
    at Object.defineProperty.value [as .js] (/Applications/Atom.app/Contents/Resources/app.asar/src/compile-cache.js:208:21)
    at Module.load (module.js:357:32)
    at Function.Module._load (module.js:314:12)
    at Module.require (module.js:367:17)
    at require (/Applications/Atom.app/Contents/Resources/app.asar/src/native-compile-cache.js:50:27)
    at Object.<anonymous> (/Users/lorisbettazza/.atom/packages/linter-stylelint/node_modules/table/dist/makeConfig.js:15:23)
    at Module._compile (/Applications/Atom.app/Contents/Resources/app.asar/src/native-compile-cache.js:103:30)
    at Object.defineProperty.value [as .js] (/Applications/Atom.app/Contents/Resources/app.asar/src/compile-cache.js:208:21)
    at Module.load (module.js:357:32)
    at Function.Module._load (module.js:314:12)
    at Module.require (module.js:367:17)
    at require (/Applications/Atom.app/Contents/Resources/app.asar/src/native-compile-cache.js:50:27)
    at Object.<anonymous> (/Users/lorisbettazza/.atom/packages/linter-stylelint/node_modules/table/dist/table.js:15:19)
    at Module._compile (/Applications/Atom.app/Contents/Resources/app.asar/src/native-compile-cache.js:103:30)
    at Object.defineProperty.value [as .js] (/Applications/Atom.app/Contents/Resources/app.asar/src/compile-cache.js:208:21)
    at Module.load (module.js:357:32)

_Note: Originally filed under https://github.com/AtomLinter/linter-stylelint/issues/269._

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 5
  • Comments: 33 (21 by maintainers)

Commits related to this issue

Most upvoted comments

My mistake, sorry – forgot that NODE_ENV defaults to development. To fix it, I have added a prepublish step that rebuilds the package using NODE_ENV=production.

v3.8.3 has been published.

Maybe there is a library simpler than table that we can use in stylelint, since we hardly use any of table’s real capabilities. I don’t think ajv has to be involved to accomplish the simple layout that we need.

I am definitely going to implement pre-compiling schemas into functions - it was an old plan anyway and there are other reasons to do it (browser bundle size, also see epoberezkin/ajv#156). Table package will be able to use precompiled schemas so there will be no dynamic code evaluation there. I will make a PR within 2-4 weeks.

If you want it resolved quicker, using the loophole can be a temporary solution, which later can be reverted, it’s up to you. I see no harm in sticking with the previous version of table for this time.

Generally speaking, I think allowing dynamic code evaluation (via Function constructor only) is the right thing - there are quite a few use cases that are difficult/much slower otherwise. That’s not my call to estimate which security risks it introduces… Although I think that crippling JavaScript under security pretence is not the right thing. It could have been a bit more granular - for example, they could have crippled generated code instead. Maybe I just like using generated code…

I’d rather not have to use that myself as avoiding eval should be done if at all possible in my opinion, but I’m just a consumer of stylelint here so it’s not up to me 😛.

Does Atom allow to require other scripts?

If you look into Node.js source code, you will learn that require is using vm to run all the code. VM = eval.

I don’t see it as an issue to depend on eval code.

As a short term solution, just restrict table version to table@3.7.9 in your package.json.

table v3.8.3 works, thanks! 🎉

omg, I think we somehow managed to publish instrumented version of table package… That is good that it was broken at least, or we could have missed it.