@locker/eslint-plugin-unsafe-types
Version:
Detect usage of unsigned unsafe types.
152 lines (139 loc) • 7.56 kB
JavaScript
/** Original file https://github.com/eslint/eslint/blob/main/tests/lib/rules/no-eval.js
* @fileoverview Detect usage of unsigned eval calls.
* @author Lightning Web Security Team
*/
'use strict';
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const RuleTester = require('eslint').RuleTester;
const rule = require('../../../lib/rules/unsafe-eval');
//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------
const env = { browser: true, commonjs: true, es2024: true, jquery: true };
const ruleTester = new RuleTester();
ruleTester.run('unsafe-eval', rule, {
valid: [
'Eval(foo)',
"setTimeout('foo')",
"setInterval('foo')",
"window.setTimeout('foo')",
"window.setInterval('foo')",
"window.noeval('foo')",
"function foo() { var eval = 'foo'; window[eval]('foo') }",
"globalThis.noneval('foo')",
"function foo() { var eval = 'foo'; globalThis[eval]('foo') }",
"this.noeval('foo');",
"function foo() { 'use strict'; this.eval('foo'); }",
"var obj = {foo: function() { this.eval('foo'); }}",
"var obj = {}; obj.foo = function() { this.eval('foo'); }",
"function f() { 'use strict'; () => { this.eval('foo') } }",
"(function f() { 'use strict'; () => { this.eval('foo') } })",
'class A { foo() { this.eval(); } }',
'class A { static foo() { this.eval(); } }',
'class A { field = this.eval(); }',
'class A { field = () => this.eval(); }',
'class A { static { this.eval(); } }',
// User-defined this.eval in callbacks
"array.findLast(function (x) { return this.eval.includes(x); }, { eval: ['foo', 'bar'] });",
'callbacks.findLastIndex(function (cb) { return cb(this.eval); }, this);',
"['1+1'].flatMap(function (str) { return this.eval(str); }, new Evaluator);",
// Signed direct eval
"eval($A.lockerService.trusted.createScript('foo'))",
"eval($A.$lockerService$.$trusted$.$createScript$('foo'))",
"eval($A.lockerService.restricted.createScript('foo'))",
"eval($A.$lockerService$.$restricted$.$createScript$('foo'))",
'eval($A.lockerService.trusted.createScript(foo))',
"this.eval($A.lockerService.trusted.createScript('foo'));",
"'use strict'; this.eval($A.lockerService.trusted.createScript('foo'));",
"function foo(eval) { eval($A.lockerService.trusted.createScript('foo')) }",
"function foo() { this.eval($A.lockerService.trusted.createScript('foo')); }",
"() => { this.eval($A.lockerService.trusted.createScript('foo')) }",
'eval($A.lockerService.trusted.createScript(foo))',
"eval($A.lockerService.trusted.createScript('foo'))",
"window.eval($A.lockerService.trusted.createScript('foo'))",
"global.eval($A.lockerService.trusted.createScript('foo'))",
"globalThis.eval($A.lockerService.trusted.createScript('foo'))",
// Signed indirect eval
"(0, eval)($A.lockerService.trusted.createScript('foo'))",
"(0, window.eval)($A.lockerService.trusted.createScript('foo'))",
"(0, window['eval'])($A.lockerService.trusted.createScript('foo'))",
"() => { this.eval($A.lockerService.trusted.createScript('foo')); }",
"() => { 'use strict'; this.eval($A.lockerService.trusted.createScript('foo')); }",
"'use strict'; () => { this.eval($A.lockerService.trusted.createScript('foo')); }",
"() => { 'use strict'; () => { this.eval($A.lockerService.trusted.createScript('foo')); } }",
"window.window.eval($A.lockerService.trusted.createScript('foo'))",
"window.window['eval']($A.lockerService.trusted.createScript('foo'))",
"global.global.eval($A.lockerService.trusted.createScript('foo'))",
"global.global[`eval`]($A.lockerService.trusted.createScript('foo'))",
"this.eval($A.lockerService.trusted.createScript('foo'))",
"'use strict'; this.eval($A.lockerService.trusted.createScript('foo'))",
"function foo() { this.eval($A.lockerService.trusted.createScript('foo')) }",
"globalThis.globalThis.eval($A.lockerService.trusted.createScript('foo'))",
"globalThis.globalThis['eval']($A.lockerService.trusted.createScript('foo'))",
"(0, globalThis.eval)($A.lockerService.trusted.createScript('foo'))",
"(0, globalThis['eval'])($A.lockerService.trusted.createScript('foo'))",
"var EVAL = eval; EVAL($A.lockerService.trusted.createScript('foo'))",
].map((code) => ({ code, env })),
invalid: [
// Direct eval
"eval(foo);eval($A.lockerService.trusted.createScript('foo'))",
'eval(foo)',
"eval('foo')",
"function foo(eval) { eval('foo') }",
"function foo() { this.eval('foo'); }",
"() => { this.eval('foo') }",
'eval(foo)',
"eval('foo')",
"function foo(eval) { eval('foo') }",
"window.eval('foo')",
"global.eval('foo')",
// Indirect eval
"(0, eval)('foo')",
"(0, window.eval)('foo')",
"(0, window['eval'])('foo')",
"var EVAL = eval; EVAL('foo')",
"var EVAL = this.eval; EVAL('foo')",
"var EVAL = this.eval; EVAL($A.lockerService.trusted.createScript('foo'))",
"'use strict'; var EVAL = this.eval; EVAL('foo')",
"'use strict'; var EVAL = this.eval; EVAL($A.lockerService.trusted.createScript('foo'))",
"() => { this.eval('foo'); }",
"() => { 'use strict'; this.eval('foo'); }",
"'use strict'; () => { this.eval('foo'); }",
"() => { 'use strict'; () => { this.eval('foo'); } }",
"(function(exe){ exe('foo') })(eval);",
"(function(exe){ exe($A.lockerService.trusted.createScript('foo')) })(eval);",
"window.eval('foo')",
"window.window.eval('foo')",
"window.window['eval']('foo')",
"global.eval('foo')",
"global.global.eval('foo')",
"global.global[`eval`]('foo')",
"this.eval('foo')",
"'use strict'; this.eval('foo')",
"function foo() { this.eval('foo') }",
"var EVAL = globalThis.eval; EVAL('foo')",
"globalThis.eval('foo')",
"globalThis.globalThis.eval('foo')",
"globalThis.globalThis['eval']('foo')",
"(0, globalThis.eval)('foo')",
"(0, globalThis['eval'])('foo')",
// Optional chaining
"window?.eval('foo')",
"(window?.eval)('foo')",
"(window?.window).eval('foo')",
// Class fields
"class C { [this.eval('foo')] }",
"'use strict'; class C { [this.eval('foo')] }",
'class A { static {} [this.eval()]; }',
// this.eval in callbacks (not user-defined)
"array.findLast(x => this.eval.includes(x), { eval: 'abc' });",
'callbacks.findLastIndex(function (cb) { return cb(eval); }, this);',
"['1+1'].flatMap(function (str) { return this.eval(str); });",
"['1'].reduce(function (a, b) { return this.eval(a) ? a : b; }, '0');",
// Signed using wrong syntax
"eval($A.lockerService.trusted['createScript']('foo'))",
"eval($A.lockerService.trusted.createScript.call($A.lockerService.trusted, 'foo'))",
].map((code) => ({ code, env, errors: [{ messageId: 'unexpected' }] })),
});