diff --git a/its/ruling/src/test/expected/jsts/TypeScript/typescript-S1523.json b/its/ruling/src/test/expected/jsts/TypeScript/typescript-S1523.json index 4213191861c..49c34aa047a 100644 --- a/its/ruling/src/test/expected/jsts/TypeScript/typescript-S1523.json +++ b/its/ruling/src/test/expected/jsts/TypeScript/typescript-S1523.json @@ -1,9 +1,12 @@ { "TypeScript:src/harness/fourslash.ts": [ 588, -2886 +2886, +2887 ], "TypeScript:src/harness/harness.ts": [ -87 +87, +92, +95 ] } diff --git a/its/ruling/src/test/expected/jsts/ace/javascript-S1523.json b/its/ruling/src/test/expected/jsts/ace/javascript-S1523.json index 9a961755214..29df294afd5 100644 --- a/its/ruling/src/test/expected/jsts/ace/javascript-S1523.json +++ b/its/ruling/src/test/expected/jsts/ace/javascript-S1523.json @@ -1,6 +1,7 @@ { "ace:demo/kitchen-sink/dev_util.js": [ -166 +166, +167 ], "ace:experiments/worker.js": [ 2 diff --git a/its/ruling/src/test/expected/jsts/es5-shim/javascript-S1523.json b/its/ruling/src/test/expected/jsts/es5-shim/javascript-S1523.json index 489b284fb55..2766d5e80c4 100644 --- a/its/ruling/src/test/expected/jsts/es5-shim/javascript-S1523.json +++ b/its/ruling/src/test/expected/jsts/es5-shim/javascript-S1523.json @@ -1,5 +1,8 @@ { "es5-shim:es5-sham.js": [ 255 +], +"es5-shim:es5-shim.js": [ +302 ] } diff --git a/its/ruling/src/test/expected/jsts/file-for-rules/javascript-S1451.json b/its/ruling/src/test/expected/jsts/file-for-rules/javascript-S1451.json index d93fe3d4437..5649e2bb11e 100644 --- a/its/ruling/src/test/expected/jsts/file-for-rules/javascript-S1451.json +++ b/its/ruling/src/test/expected/jsts/file-for-rules/javascript-S1451.json @@ -5,6 +5,9 @@ "file-for-rules:S1291.js": [ 0 ], +"file-for-rules:S1523.js": [ +0 +], "file-for-rules:S1534.js": [ 0 ], @@ -23,6 +26,9 @@ "file-for-rules:S2639.js": [ 0 ], +"file-for-rules:S2755.js": [ +0 +], "file-for-rules:S2871.js": [ 0 ], diff --git a/its/ruling/src/test/expected/jsts/file-for-rules/javascript-S1523.json b/its/ruling/src/test/expected/jsts/file-for-rules/javascript-S1523.json new file mode 100644 index 00000000000..a9c542ae7f9 --- /dev/null +++ b/its/ruling/src/test/expected/jsts/file-for-rules/javascript-S1523.json @@ -0,0 +1,5 @@ +{ +"file-for-rules:S1523.js": [ +5 +] +} diff --git a/its/ruling/src/test/expected/jsts/file-for-rules/javascript-S2755.json b/its/ruling/src/test/expected/jsts/file-for-rules/javascript-S2755.json new file mode 100644 index 00000000000..26bafb8b1b2 --- /dev/null +++ b/its/ruling/src/test/expected/jsts/file-for-rules/javascript-S2755.json @@ -0,0 +1,5 @@ +{ +"file-for-rules:S2755.js": [ +8 +] +} diff --git a/its/ruling/src/test/expected/jsts/redux/javascript-S1523.json b/its/ruling/src/test/expected/jsts/redux/javascript-S1523.json new file mode 100755 index 00000000000..8c6eb72acb8 --- /dev/null +++ b/its/ruling/src/test/expected/jsts/redux/javascript-S1523.json @@ -0,0 +1,5 @@ +{ +"redux:test/utils/isPlainObject.spec.js": [ +12 +] +} diff --git a/its/ruling/src/test/expected/jsts/sizzle/javascript-S1523.json b/its/ruling/src/test/expected/jsts/sizzle/javascript-S1523.json index 6a4c98659bd..31cd0f5a5fc 100644 --- a/its/ruling/src/test/expected/jsts/sizzle/javascript-S1523.json +++ b/its/ruling/src/test/expected/jsts/sizzle/javascript-S1523.json @@ -1,5 +1,6 @@ { "sizzle:speed/speed.js": [ -371 +371, +378 ] } diff --git a/its/sources/jsts/custom/S1523.js b/its/sources/jsts/custom/S1523.js new file mode 100644 index 00000000000..29f084dc197 --- /dev/null +++ b/its/sources/jsts/custom/S1523.js @@ -0,0 +1,5 @@ +import vm from 'node:vm'; + +const sandbox = { data: 'data' }; +vm.createContext(sandbox); +vm.runInContext('code', sandbox, { timeout: 2000 }); diff --git a/its/sources/jsts/custom/S2755.js b/its/sources/jsts/custom/S2755.js new file mode 100644 index 00000000000..a2160ce2e78 --- /dev/null +++ b/its/sources/jsts/custom/S2755.js @@ -0,0 +1,9 @@ +import libxmljs from 'libxmljs'; +import libxmljs2 from 'libxmljs2'; +import fs from 'node:fs'; + +const xml = fs.readFileSync('xxe.xml', 'utf8'); +const opts = { noblanks: true, noent: true, nocdata: true }; + +libxmljs.parseXmlString(xml, { noblanks: true, noent: true, nocdata: true }); // Detected +libxmljs2.parseXmlString(xml, opts); // Undetected diff --git a/packages/jsts/src/rules/S1523/rule.ts b/packages/jsts/src/rules/S1523/rule.ts index d2f1255d218..3c0de850eff 100644 --- a/packages/jsts/src/rules/S1523/rule.ts +++ b/packages/jsts/src/rules/S1523/rule.ts @@ -20,11 +20,21 @@ import type { Rule } from 'eslint'; import type estree from 'estree'; import { getESLintCoreRule } from '../external/core.js'; -import { generateMeta } from '../helpers/index.js'; +import { generateMeta, getFullyQualifiedName } from '../helpers/index.js'; import * as meta from './generated-meta.js'; const noScriptUrlRule = getESLintCoreRule('no-script-url'); +const EVAL_LIKE_FUNCTIONS: Set = new Set([ + 'eval', + 'Function', + 'vm.Script', + 'vm.SourceTextModule', + 'vm.runInContext', + 'vm.runInNewContext', + 'vm.runInThisContext', +]); + export const rule: Rule.RuleModule = { meta: generateMeta(meta, { messages: { @@ -44,9 +54,9 @@ export const rule: Rule.RuleModule = { }; function checkCallExpression(node: estree.CallExpression, context: Rule.RuleContext) { - if (node.callee.type === 'Identifier') { - const { name } = node.callee; - if ((name === 'eval' || name === 'Function') && hasAtLeastOneVariableArgument(node.arguments)) { + if (['Identifier', 'MemberExpression'].includes(node.callee.type)) { + const name = getFullyQualifiedName(context, node) || ''; + if (EVAL_LIKE_FUNCTIONS.has(name) && hasAtLeastOneVariableArgument(node.arguments)) { context.report({ messageId: 'safeCode', node: node.callee, diff --git a/packages/jsts/src/rules/S2755/rule.ts b/packages/jsts/src/rules/S2755/rule.ts index 641a80f1a55..3015b7cc618 100644 --- a/packages/jsts/src/rules/S2755/rule.ts +++ b/packages/jsts/src/rules/S2755/rule.ts @@ -28,15 +28,19 @@ import { } from '../helpers/index.js'; import * as meta from './generated-meta.js'; -const XML_LIBRARY = 'libxmljs'; -const XML_PARSERS = ['parseXml', 'parseXmlString']; +const TARGET_XML_FQNS: Set = new Set([ + 'libxmljs.parseXml', + 'libxmljs.parseXmlString', + 'libxmljs2.parseXml', + 'libxmljs2.parseXmlString', +]); export const rule: Rule.RuleModule = { meta: generateMeta(meta), create(context: Rule.RuleContext) { function isXmlParserCall(call: estree.CallExpression) { - const fqn = getFullyQualifiedName(context, call); - return XML_PARSERS.some(parser => fqn === `${XML_LIBRARY}.${parser}`); + const fqn = getFullyQualifiedName(context, call) || ''; + return TARGET_XML_FQNS.has(fqn); } return {