From 309adc67d9ac09eaf4646ddef5e3e7958bd13041 Mon Sep 17 00:00:00 2001 From: fraxken Date: Wed, 9 Jul 2025 16:49:53 +0200 Subject: [PATCH] refactor: remove trojan-source detection from SourceFile constructor Update workspaces/js-x-ray/test/probes/isSerializeEnv.spec.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> chore: add changeset --- .changeset/poor-jars-smile.md | 5 ++ workspaces/js-x-ray/src/AstAnalyser.ts | 9 +++- workspaces/js-x-ray/src/SourceFile.ts | 12 ----- workspaces/js-x-ray/test/ProbeRunner.spec.ts | 18 +++---- .../test/probes/isArrayExpression.spec.ts | 6 +-- .../test/probes/isBinaryExpression.spec.ts | 4 +- .../test/probes/isImportDeclaration.spec.ts | 12 ++--- .../js-x-ray/test/probes/isLiteral.spec.ts | 34 ++++++------- .../test/probes/isLiteralRegex.spec.ts | 2 +- .../test/probes/isRegexObject.spec.ts | 6 +-- .../js-x-ray/test/probes/isRequire.spec.ts | 48 +++++++++---------- .../test/probes/isSerializeEnv.spec.ts | 16 +++---- .../test/probes/isUnsafeCallee.spec.ts | 8 ++-- .../test/probes/isUnsafeCommand.spec.ts | 12 ++--- workspaces/js-x-ray/test/utils/index.ts | 3 +- 15 files changed, 97 insertions(+), 98 deletions(-) create mode 100644 .changeset/poor-jars-smile.md diff --git a/.changeset/poor-jars-smile.md b/.changeset/poor-jars-smile.md new file mode 100644 index 0000000..602ba63 --- /dev/null +++ b/.changeset/poor-jars-smile.md @@ -0,0 +1,5 @@ +--- +"@nodesecure/js-x-ray": minor +--- + +Move trojan-source detection from SourceFile to AstAnalyser diff --git a/workspaces/js-x-ray/src/AstAnalyser.ts b/workspaces/js-x-ray/src/AstAnalyser.ts index afc63ce..e4adc63 100644 --- a/workspaces/js-x-ray/src/AstAnalyser.ts +++ b/workspaces/js-x-ray/src/AstAnalyser.ts @@ -21,6 +21,7 @@ import { import { isOneLineExpressionExport } from "./utils/index.js"; import { JsSourceParser, type SourceParser } from "./JsSourceParser.js"; import { ProbeRunner, type Probe } from "./ProbeRunner.js"; +import * as trojan from "./obfuscators/trojan-source.js"; export interface Dependency { unsafe: boolean; @@ -143,7 +144,13 @@ export class AstAnalyser { const body = this.parser.parse(this.prepareSource(str, { removeHTMLComments }), { isEcmaScriptModule: Boolean(module) }); - const source = new SourceFile(str); + const source = new SourceFile(); + if (trojan.verify(str)) { + source.warnings.push( + generateWarning("obfuscated-code", { value: "trojan-source" }) + ); + } + const runner = new ProbeRunner(source, this.probes); if (initialize) { diff --git a/workspaces/js-x-ray/src/SourceFile.ts b/workspaces/js-x-ray/src/SourceFile.ts index 3ba9f4d..7d934ea 100644 --- a/workspaces/js-x-ray/src/SourceFile.ts +++ b/workspaces/js-x-ray/src/SourceFile.ts @@ -11,7 +11,6 @@ import { } from "./warnings.js"; import type { Dependency } from "./AstAnalyser.js"; import { Deobfuscator } from "./Deobfuscator.js"; -import * as trojan from "./obfuscators/trojan-source.js"; // CONSTANTS const kMaximumEncodedLiterals = 10; @@ -30,17 +29,6 @@ export class SourceFile { encodedLiterals = new Map(); warnings: Warning[] = []; flags = new Set(); - - constructor( - sourceCodeString: string - ) { - if (trojan.verify(sourceCodeString)) { - this.warnings.push( - generateWarning("obfuscated-code", { value: "trojan-source" }) - ); - } - } - addDependency( name: string, location?: ESTree.SourceLocation | null, diff --git a/workspaces/js-x-ray/test/ProbeRunner.spec.ts b/workspaces/js-x-ray/test/ProbeRunner.spec.ts index d15c41e..23061a0 100644 --- a/workspaces/js-x-ray/test/ProbeRunner.spec.ts +++ b/workspaces/js-x-ray/test/ProbeRunner.spec.ts @@ -15,7 +15,7 @@ import { SourceFile } from "../src/SourceFile.js"; describe("ProbeRunner", () => { describe("constructor", () => { it("should instanciate class with Defaults probes when none are provide", () => { - const pr = new ProbeRunner(new SourceFile("")); + const pr = new ProbeRunner(new SourceFile()); assert.strictEqual(pr.probes, ProbeRunner.Defaults); }); @@ -30,7 +30,7 @@ describe("ProbeRunner", () => { ]; // @ts-expect-error - const pr = new ProbeRunner(new SourceFile(""), fakeProbe); + const pr = new ProbeRunner(new SourceFile(), fakeProbe); assert.strictEqual(pr.probes, fakeProbe); }); @@ -44,7 +44,7 @@ describe("ProbeRunner", () => { ]; // @ts-expect-error - const pr = new ProbeRunner(new SourceFile(""), fakeProbe); + const pr = new ProbeRunner(new SourceFile(), fakeProbe); assert.strictEqual(pr.probes, fakeProbe); }); @@ -56,7 +56,7 @@ describe("ProbeRunner", () => { function instantiateProbeRunner() { // @ts-expect-error - return new ProbeRunner(new SourceFile(""), [fakeProbe]); + return new ProbeRunner(new SourceFile(), [fakeProbe]); } assert.throws(instantiateProbeRunner, Error, "Invalid probe"); @@ -70,7 +70,7 @@ describe("ProbeRunner", () => { function instantiateProbeRunner() { // @ts-expect-error - return new ProbeRunner(new SourceFile(""), [fakeProbe]); + return new ProbeRunner(new SourceFile(), [fakeProbe]); } assert.throws(instantiateProbeRunner, Error, "Invalid probe"); @@ -85,7 +85,7 @@ describe("ProbeRunner", () => { function instantiateProbeRunner() { // @ts-expect-error - return new ProbeRunner(new SourceFile(""), [fakeProbe]); + return new ProbeRunner(new SourceFile(), [fakeProbe]); } assert.throws(instantiateProbeRunner, Error, "Invalid probe"); @@ -94,7 +94,7 @@ describe("ProbeRunner", () => { describe("walk", () => { it("should pass validateNode, enter main and then teardown", () => { - const sourceFile = new SourceFile(""); + const sourceFile = new SourceFile(); const fakeProbe = { validateNode: (node: ESTree.Node) => [node.type === "Literal"], main: mock.fn(), @@ -130,7 +130,7 @@ describe("ProbeRunner", () => { }; const pr = new ProbeRunner( - new SourceFile(""), + new SourceFile(), // @ts-expect-error [fakeProbe] ); @@ -170,7 +170,7 @@ describe("ProbeRunner", () => { const probes = [fakeProbe, fakeProbeBreak, fakeProbeSkip]; - const sourceFile = new SourceFile(""); + const sourceFile = new SourceFile(); const pr = new ProbeRunner( sourceFile, diff --git a/workspaces/js-x-ray/test/probes/isArrayExpression.spec.ts b/workspaces/js-x-ray/test/probes/isArrayExpression.spec.ts index 3376d24..d4bfcc1 100644 --- a/workspaces/js-x-ray/test/probes/isArrayExpression.spec.ts +++ b/workspaces/js-x-ray/test/probes/isArrayExpression.spec.ts @@ -10,7 +10,7 @@ test("it should trigger analyzeLiteral method one time", (t) => { const str = "['foo']"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isArrayExpression); + const sastAnalysis = getSastAnalysis(isArrayExpression); const analyzeLiteralMock = t.mock.method(sastAnalysis.sourceFile, "analyzeLiteral"); sastAnalysis.execute(ast.body); @@ -28,7 +28,7 @@ test("it should trigger analyzeLiteral method two times (ignoring the holey betw const str = "[5, ,10]"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isArrayExpression); + const sastAnalysis = getSastAnalysis(isArrayExpression); const analyzeLiteralMock = t.mock.method(sastAnalysis.sourceFile, "analyzeLiteral"); sastAnalysis.execute(ast.body); @@ -43,7 +43,7 @@ test("it should trigger analyzeLiteral one time (ignoring non-literal Node)", (t const str = "[5, () => void 0]"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isArrayExpression); + const sastAnalysis = getSastAnalysis(isArrayExpression); const analyzeLiteralMock = t.mock.method(sastAnalysis.sourceFile, "analyzeLiteral"); sastAnalysis.execute(ast.body); diff --git a/workspaces/js-x-ray/test/probes/isBinaryExpression.spec.ts b/workspaces/js-x-ray/test/probes/isBinaryExpression.spec.ts index b7ebc74..487bf4a 100644 --- a/workspaces/js-x-ray/test/probes/isBinaryExpression.spec.ts +++ b/workspaces/js-x-ray/test/probes/isBinaryExpression.spec.ts @@ -9,7 +9,7 @@ import isBinaryExpression from "../../src/probes/isBinaryExpression.js"; test("should detect 1 deep binary expression", () => { const str = "0x1*-0x12df+-0x1fb9*-0x1+0x2*-0x66d"; const ast = parseScript(str); - const { sourceFile } = getSastAnalysis(str, isBinaryExpression) + const { sourceFile } = getSastAnalysis(isBinaryExpression) .execute(ast.body); assert.equal(sourceFile.deobfuscator.deepBinaryExpression, 1); @@ -18,7 +18,7 @@ test("should detect 1 deep binary expression", () => { test("should not detect deep binary expression", () => { const str = "10 + 5 - (10)"; const ast = parseScript(str); - const { sourceFile } = getSastAnalysis(str, isBinaryExpression) + const { sourceFile } = getSastAnalysis(isBinaryExpression) .execute(ast.body); assert.equal(sourceFile.deobfuscator.deepBinaryExpression, 0); diff --git a/workspaces/js-x-ray/test/probes/isImportDeclaration.spec.ts b/workspaces/js-x-ray/test/probes/isImportDeclaration.spec.ts index 6607cc9..f0551af 100644 --- a/workspaces/js-x-ray/test/probes/isImportDeclaration.spec.ts +++ b/workspaces/js-x-ray/test/probes/isImportDeclaration.spec.ts @@ -9,7 +9,7 @@ import isImportDeclaration from "../../src/probes/isImportDeclaration.js"; test("should detect 1 dependency for an ImportNamespaceSpecifier", () => { const str = "import * as foo from \"bar\""; const ast = parseScript(str); - const { sourceFile } = getSastAnalysis(str, isImportDeclaration) + const { sourceFile } = getSastAnalysis(isImportDeclaration) .execute(ast.body); const { dependencies } = sourceFile; @@ -19,7 +19,7 @@ test("should detect 1 dependency for an ImportNamespaceSpecifier", () => { test("should detect 1 dependency for an ImportDefaultSpecifier", () => { const str = "import foo from \"bar\""; const ast = parseScript(str); - const { sourceFile } = getSastAnalysis(str, isImportDeclaration) + const { sourceFile } = getSastAnalysis(isImportDeclaration) .execute(ast.body); const { dependencies } = sourceFile; @@ -29,7 +29,7 @@ test("should detect 1 dependency for an ImportDefaultSpecifier", () => { test("should detect 1 dependency for an ImportSpecifier", () => { const str = "import { xd } from \"bar\""; const ast = parseScript(str); - const { sourceFile } = getSastAnalysis(str, isImportDeclaration) + const { sourceFile } = getSastAnalysis(isImportDeclaration) .execute(ast.body); const { dependencies } = sourceFile; @@ -39,7 +39,7 @@ test("should detect 1 dependency for an ImportSpecifier", () => { test("should detect 1 dependency with no specificiers", () => { const str = "import \"bar\""; const ast = parseScript(str); - const { sourceFile } = getSastAnalysis(str, isImportDeclaration) + const { sourceFile } = getSastAnalysis(isImportDeclaration) .execute(ast.body); const { dependencies } = sourceFile; @@ -49,7 +49,7 @@ test("should detect 1 dependency with no specificiers", () => { test("should detect 1 dependency for an ImportExpression", () => { const str = "import(\"bar\")"; const ast = parseScript(str); - const { sourceFile } = getSastAnalysis(str, isImportDeclaration) + const { sourceFile } = getSastAnalysis(isImportDeclaration) .execute(ast.body); const { dependencies } = sourceFile; @@ -66,7 +66,7 @@ test("should detect an unsafe import using data:text/javascript and throw a unsa importNodes.forEach((str) => { const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isImportDeclaration) + const sastAnalysis = getSastAnalysis(isImportDeclaration) .execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 1); diff --git a/workspaces/js-x-ray/test/probes/isLiteral.spec.ts b/workspaces/js-x-ray/test/probes/isLiteral.spec.ts index 60f5b05..1fa5735 100644 --- a/workspaces/js-x-ray/test/probes/isLiteral.spec.ts +++ b/workspaces/js-x-ray/test/probes/isLiteral.spec.ts @@ -10,7 +10,7 @@ test("should throw an unsafe-import because the hexadecimal string is equal to t const str = "const foo = '68747470'"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isLiteral); + const sastAnalysis = getSastAnalysis(isLiteral); const analyzeStringMock = t.mock.method(sastAnalysis.sourceFile.deobfuscator, "analyzeString"); sastAnalysis.execute(ast.body); @@ -28,7 +28,7 @@ test("should throw an encoded-literal warning because the hexadecimal value is e const str = "const _t = globalThis['72657175697265']"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isLiteral); + const sastAnalysis = getSastAnalysis(isLiteral); const analyzeStringMock = t.mock.method(sastAnalysis.sourceFile.deobfuscator, "analyzeString"); sastAnalysis.execute(ast.body); @@ -44,7 +44,7 @@ test("should throw an encoded-literal warning because the hexadecimal value is e test("should not throw an encoded-literal warning because hexadecimal value is safe", () => { const str = "const foo = '123456789'"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isLiteral) + const sastAnalysis = getSastAnalysis(isLiteral) .execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 0); @@ -54,7 +54,7 @@ test("should throw an encoded-literal warning because hexadecimal value is not s // Note: hexadecimal equal 'hello world' const str = "const foo = '68656c6c6f20776f726c64'"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isLiteral) + const sastAnalysis = getSastAnalysis(isLiteral) .execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 1); @@ -66,7 +66,7 @@ test("should not throw any warnings without hexadecimal value (and should call a const str = "const foo = 'hello world!'"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isLiteral); + const sastAnalysis = getSastAnalysis(isLiteral); const analyzeLiteralMock = t.mock.method(sastAnalysis.sourceFile, "analyzeLiteral"); sastAnalysis.execute(ast.body); @@ -81,7 +81,7 @@ test("should not throw any warnings without hexadecimal value (and should call a test("should detect shady link when an URL is bit.ly", () => { const str = "const foo = 'http://bit.ly/foo'"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isLiteral).execute(ast.body); + const sastAnalysis = getSastAnalysis(isLiteral).execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 1); const warning = sastAnalysis.getWarning("shady-link"); @@ -91,7 +91,7 @@ test("should detect shady link when an URL is bit.ly", () => { test("should detect shady link when an URL is ipinfo.io when protocol is http", () => { const str = "const foo = 'http://ipinfo.io/json'"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isLiteral).execute(ast.body); + const sastAnalysis = getSastAnalysis(isLiteral).execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 1); const warning = sastAnalysis.getWarning("shady-link"); assert.strictEqual(warning.value, "http://ipinfo.io/json"); @@ -100,7 +100,7 @@ test("should detect shady link when an URL is ipinfo.io when protocol is http", test("should detect shady link when an URL is ipinfo.io when protocol is https", () => { const str = "const foo = 'https://ipinfo.io/json'"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isLiteral).execute(ast.body); + const sastAnalysis = getSastAnalysis(isLiteral).execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 1); const warning = sastAnalysis.getWarning("shady-link"); assert.strictEqual(warning.value, "https://ipinfo.io/json"); @@ -109,7 +109,7 @@ test("should detect shady link when an URL is ipinfo.io when protocol is https", test("should detect shady link when an URL is httpbin.org when protocol is http", () => { const str = "const foo = 'http://httpbin.org/ip'"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isLiteral).execute(ast.body); + const sastAnalysis = getSastAnalysis(isLiteral).execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 1); const warning = sastAnalysis.getWarning("shady-link"); assert.strictEqual(warning.value, "http://httpbin.org/ip"); @@ -118,7 +118,7 @@ test("should detect shady link when an URL is httpbin.org when protocol is http" test("should detect shady link when an URL is httpbin.org when protocol is https", () => { const str = "const foo = 'https://httpbin.org/ip'"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isLiteral).execute(ast.body); + const sastAnalysis = getSastAnalysis(isLiteral).execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 1); const warning = sastAnalysis.getWarning("shady-link"); assert.strictEqual(warning.value, "https://httpbin.org/ip"); @@ -127,7 +127,7 @@ test("should detect shady link when an URL is httpbin.org when protocol is https test("should detect shady link when an URL has a suspicious domain", () => { const str = "const foo = 'http://foobar.link'"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isLiteral).execute(ast.body); + const sastAnalysis = getSastAnalysis(isLiteral).execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 1); const warning = sastAnalysis.getWarning("shady-link"); @@ -137,7 +137,7 @@ test("should detect shady link when an URL has a suspicious domain", () => { test("should not mark suspicious links the IPv4 address range 127.0.0.0/8 (localhost 127.0.0.1)", () => { const str = "const IPv4URL = ['http://127.0.0.1/script', 'http://127.7.7.7/script']"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isLiteral).execute(ast.body); + const sastAnalysis = getSastAnalysis(isLiteral).execute(ast.body); assert.ok(!sastAnalysis.warnings().length); }); @@ -145,7 +145,7 @@ test("should not mark suspicious links the IPv4 address range 127.0.0.0/8 (local test("should not be considered suspicious a link with a raw IPv4 address 127.0.0.1 and a port", () => { const str = "const IPv4URL = 'http://127.0.0.1:80/script'"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isLiteral).execute(ast.body); + const sastAnalysis = getSastAnalysis(isLiteral).execute(ast.body); assert.ok(!sastAnalysis.warnings().length); }); @@ -153,7 +153,7 @@ test("should not be considered suspicious a link with a raw IPv4 address 127.0.0 test("should detect the link as suspicious when a URL contains a raw IPv4 address", () => { const str = "const IPv4URL = 'http://77.244.210.247/burpcollaborator.txt'"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isLiteral).execute(ast.body); + const sastAnalysis = getSastAnalysis(isLiteral).execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 1); const warning = sastAnalysis.getWarning("shady-link"); @@ -163,7 +163,7 @@ test("should detect the link as suspicious when a URL contains a raw IPv4 addres test("should detect suspicious links when a URL contains a raw IPv4 address with port", () => { const str = "const IPv4URL = 'http://77.244.210.247:8080/script'"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isLiteral).execute(ast.body); + const sastAnalysis = getSastAnalysis(isLiteral).execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 1); const warning = sastAnalysis.getWarning("shady-link"); @@ -173,7 +173,7 @@ test("should detect suspicious links when a URL contains a raw IPv4 address with test("should detect suspicious links when a URL contains a raw IPv6 address", () => { const str = "const IPv6URL = 'http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]/index.html'"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isLiteral).execute(ast.body); + const sastAnalysis = getSastAnalysis(isLiteral).execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 1); const warning = sastAnalysis.getWarning("shady-link"); @@ -183,7 +183,7 @@ test("should detect suspicious links when a URL contains a raw IPv6 address", () test("should detect suspicious links when a URL contains a raw IPv6 address with port", () => { const str = "const IPv6URL = 'http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:100/script'"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isLiteral).execute(ast.body); + const sastAnalysis = getSastAnalysis(isLiteral).execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 1); const warning = sastAnalysis.getWarning("shady-link"); diff --git a/workspaces/js-x-ray/test/probes/isLiteralRegex.spec.ts b/workspaces/js-x-ray/test/probes/isLiteralRegex.spec.ts index f02c2ed..adf5100 100644 --- a/workspaces/js-x-ray/test/probes/isLiteralRegex.spec.ts +++ b/workspaces/js-x-ray/test/probes/isLiteralRegex.spec.ts @@ -9,7 +9,7 @@ import isLiteralRegex from "../../src/probes/isLiteralRegex.js"; test("should throw a 'unsafe-regex' warning because the given RegExp Literal is unsafe", () => { const str = "const foo = /(a+){10}/g;"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isLiteralRegex) + const sastAnalysis = getSastAnalysis(isLiteralRegex) .execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 1); diff --git a/workspaces/js-x-ray/test/probes/isRegexObject.spec.ts b/workspaces/js-x-ray/test/probes/isRegexObject.spec.ts index 8963739..f26cf95 100644 --- a/workspaces/js-x-ray/test/probes/isRegexObject.spec.ts +++ b/workspaces/js-x-ray/test/probes/isRegexObject.spec.ts @@ -9,7 +9,7 @@ import isRegexObject from "../../src/probes/isRegexObject.js"; test("should not throw a warning because the given Literal RegExp is considered 'safe'", () => { const str = "const foo = new RegExp('^hello');"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isRegexObject) + const sastAnalysis = getSastAnalysis(isRegexObject) .execute(ast.body); assert.equal(sastAnalysis.warnings().length, 0); @@ -18,7 +18,7 @@ test("should not throw a warning because the given Literal RegExp is considered test("should throw a 'unsafe-regex' warning because the given RegExp Object is unsafe", () => { const str = "const foo = new RegExp('(a+){10}');"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isRegexObject) + const sastAnalysis = getSastAnalysis(isRegexObject) .execute(ast.body); assert.equal(sastAnalysis.warnings().length, 1); @@ -29,7 +29,7 @@ test("should throw a 'unsafe-regex' warning because the given RegExp Object is u test("should throw a 'unsafe-regex' warning because the given RegExp Object (with RegExpLiteral) is unsafe", () => { const str = "const foo = new RegExp(/(a+){10}/);"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isRegexObject) + const sastAnalysis = getSastAnalysis(isRegexObject) .execute(ast.body); assert.equal(sastAnalysis.warnings().length, 1); diff --git a/workspaces/js-x-ray/test/probes/isRequire.spec.ts b/workspaces/js-x-ray/test/probes/isRequire.spec.ts index 4d58285..92f3869 100644 --- a/workspaces/js-x-ray/test/probes/isRequire.spec.ts +++ b/workspaces/js-x-ray/test/probes/isRequire.spec.ts @@ -11,7 +11,7 @@ test("it should ignore require CallExpression with no (zero) arguments", () => { require() `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isRequire) + const sastAnalysis = getSastAnalysis(isRequire) .execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 0); @@ -25,7 +25,7 @@ test("it should execute probe using require.resolve (detected by the VariableTra require.resolve("http"); `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isRequire) + const sastAnalysis = getSastAnalysis(isRequire) .execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 0); @@ -38,7 +38,7 @@ test("it should execute probe using process.mainModule.require (detected by the process.mainModule.require("http"); `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isRequire) + const sastAnalysis = getSastAnalysis(isRequire) .execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 0); @@ -56,7 +56,7 @@ test("it should execute probe using process.getBuiltinModule (detected by the Va } `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isRequire) + const sastAnalysis = getSastAnalysis(isRequire) .execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 0); @@ -74,7 +74,7 @@ test("it should execute probe on a variable reassignments of require (detected b b("http"); `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isRequire) + const sastAnalysis = getSastAnalysis(isRequire) .execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 0); @@ -93,7 +93,7 @@ test("it should execute probe on a variable reassignments of require extended (d r.require("fs"); `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isRequire) + const sastAnalysis = getSastAnalysis(isRequire) .execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 0); @@ -110,7 +110,7 @@ test("it should catch require with an Identifier argument pointing to the Node.j require(foo); `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isRequire) + const sastAnalysis = getSastAnalysis(isRequire) .execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 0); @@ -124,7 +124,7 @@ test("it should throw an 'unsafe-import' warning for a require with an unknown I require(foo); `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isRequire) + const sastAnalysis = getSastAnalysis(isRequire) .execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 1); @@ -137,7 +137,7 @@ test("it should throw an 'unsafe-import' warning for a require with an unknown M require(foo.bar); `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isRequire) + const sastAnalysis = getSastAnalysis(isRequire) .execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 1); @@ -150,7 +150,7 @@ test("it should catch require with a Literal argument having for value the Node. require("http"); `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isRequire) + const sastAnalysis = getSastAnalysis(isRequire) .execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 0); @@ -165,7 +165,7 @@ are equal to the Node.js core http module`, () => { require(["h", "t", "t", "p"]); `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isRequire) + const sastAnalysis = getSastAnalysis(isRequire) .execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 0); @@ -181,7 +181,7 @@ are equal to the Node.js core http module (with charCodes as values)`, () => { require([104, 101, 108, 108, 111]); `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isRequire) + const sastAnalysis = getSastAnalysis(isRequire) .execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 0); @@ -199,7 +199,7 @@ are equal to the Node.js core http module (with VariableTracer usage)`, () => { require([a, b, b, "p"]); `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isRequire) + const sastAnalysis = getSastAnalysis(isRequire) .execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 0); @@ -214,7 +214,7 @@ where all Literals values concatened is equal to an empty string`, () => { require(["", ""]); `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isRequire) + const sastAnalysis = getSastAnalysis(isRequire) .execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 1); @@ -228,7 +228,7 @@ are equal to the Node.js core http module`, () => { require("ht" + "tp"); `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isRequire) + const sastAnalysis = getSastAnalysis(isRequire) .execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 0); @@ -246,7 +246,7 @@ are equal to the Node.js core http module (with VariableTracer usage)`, () => { require(left + right); `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isRequire) + const sastAnalysis = getSastAnalysis(isRequire) .execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 0); @@ -261,7 +261,7 @@ with an operator not equal to '+' as require argument`, () => { require(5 - 5); `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isRequire) + const sastAnalysis = getSastAnalysis(isRequire) .execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 1); @@ -274,7 +274,7 @@ test("it should throw an 'unsafe-import' warning for using a BinaryExpression wi require("foo" + evil()); `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isRequire) + const sastAnalysis = getSastAnalysis(isRequire) .execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 1); @@ -290,7 +290,7 @@ test("(require CallExpression): it should always throw an 'unsafe-import' warnin require(evil()); `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isRequire) + const sastAnalysis = getSastAnalysis(isRequire) .execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 1); @@ -311,7 +311,7 @@ and then add the unobfuscated value in the dependency list`, () => { require(unhex("68747470")); `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isRequire) + const sastAnalysis = getSastAnalysis(isRequire) .execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 1); @@ -328,7 +328,7 @@ test("(require CallExpression): it should detect MemberExpression Buffer.from", require(Buffer.from("68747470", "hex").toString()); `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isRequire) + const sastAnalysis = getSastAnalysis(isRequire) .execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 1); @@ -345,7 +345,7 @@ test("(require CallExpression): it should detect MemberExpression Buffer.from (w require(Buffer.from([104, 101, 108, 108, 111]).toString()); `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isRequire) + const sastAnalysis = getSastAnalysis(isRequire) .execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 1); @@ -362,7 +362,7 @@ test("(require CallExpression): it should detect MemberExpression require.resolv require(require.resolve("foo")); `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isRequire) + const sastAnalysis = getSastAnalysis(isRequire) .execute(ast.body); assert.strictEqual( @@ -385,7 +385,7 @@ test("(require CallExpression): it should detect obfuscated atob value", () => { `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isRequire) + const sastAnalysis = getSastAnalysis(isRequire) .execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 1); diff --git a/workspaces/js-x-ray/test/probes/isSerializeEnv.spec.ts b/workspaces/js-x-ray/test/probes/isSerializeEnv.spec.ts index 124a94e..2e3cac0 100644 --- a/workspaces/js-x-ray/test/probes/isSerializeEnv.spec.ts +++ b/workspaces/js-x-ray/test/probes/isSerializeEnv.spec.ts @@ -9,7 +9,7 @@ import isSerializeEnv from "../../src/probes/isSerializeEnv.js"; test("should detect JSON.stringify(process.env)", () => { const str = "JSON.stringify(process.env)"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isSerializeEnv).execute(ast.body); + const sastAnalysis = getSastAnalysis(isSerializeEnv).execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 1); const warning = sastAnalysis.getWarning("serialize-environment"); @@ -20,7 +20,7 @@ test("should detect JSON.stringify(process.env)", () => { test("should detect JSON.stringify(process['env'])", () => { const str = "JSON.stringify(process['env'])"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isSerializeEnv).execute(ast.body); + const sastAnalysis = getSastAnalysis(isSerializeEnv).execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 1); const warning = sastAnalysis.getWarning("serialize-environment"); @@ -31,7 +31,7 @@ test("should detect JSON.stringify(process['env'])", () => { test("should detect JSON.stringify(process[\"env\"])", () => { const str = "JSON.stringify(process[\"env\"])"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isSerializeEnv).execute(ast.body); + const sastAnalysis = getSastAnalysis(isSerializeEnv).execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 1); const warning = sastAnalysis.getWarning("serialize-environment"); @@ -45,7 +45,7 @@ test("should detect process.env reassignment", () => { JSON.stringify(env); `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isSerializeEnv).execute(ast.body); + const sastAnalysis = getSastAnalysis(isSerializeEnv).execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 1); const warning = sastAnalysis.getWarning("serialize-environment"); @@ -60,7 +60,7 @@ test("should not detect process.env", () => { JSON.stringify(env); `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isSerializeEnv).execute(ast.body); + const sastAnalysis = getSastAnalysis(isSerializeEnv).execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 0); }); @@ -72,7 +72,7 @@ test("should be able to detect reassigned JSON.stringify", () => { stringify(env); `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isSerializeEnv).execute(ast.body); + const sastAnalysis = getSastAnalysis(isSerializeEnv).execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 1); const warning = sastAnalysis.getWarning("serialize-environment"); @@ -83,7 +83,7 @@ test("should be able to detect reassigned JSON.stringify", () => { test("should not detect other JSON.stringify calls", () => { const str = "JSON.stringify({ foo: 'bar' })"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isSerializeEnv).execute(ast.body); + const sastAnalysis = getSastAnalysis(isSerializeEnv).execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 0); }); @@ -91,7 +91,7 @@ test("should not detect other JSON.stringify calls", () => { test("should not detect non-JSON.stringify calls", () => { const str = "const env = process.env"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isSerializeEnv).execute(ast.body); + const sastAnalysis = getSastAnalysis(isSerializeEnv).execute(ast.body); assert.strictEqual(sastAnalysis.warnings().length, 0); }); diff --git a/workspaces/js-x-ray/test/probes/isUnsafeCallee.spec.ts b/workspaces/js-x-ray/test/probes/isUnsafeCallee.spec.ts index 291ca41..ab84415 100644 --- a/workspaces/js-x-ray/test/probes/isUnsafeCallee.spec.ts +++ b/workspaces/js-x-ray/test/probes/isUnsafeCallee.spec.ts @@ -13,7 +13,7 @@ test("should detect eval", () => { const str = "eval(\"this\");"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isUnsafeCallee) + const sastAnalysis = getSastAnalysis(isUnsafeCallee) .execute(ast.body); const result = sastAnalysis.getWarning(kWarningUnsafeStmt); @@ -25,7 +25,7 @@ test("should not detect warnings for Function with return this", () => { const str = "Function(\"return this\")()"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isUnsafeCallee) + const sastAnalysis = getSastAnalysis(isUnsafeCallee) .execute(ast.body); assert.strictEqual(sastAnalysis.warnings.length, 0); @@ -35,7 +35,7 @@ test("should detect for unsafe Function statement", () => { const str = "Function(\"anything in here\")()"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isUnsafeCallee) + const sastAnalysis = getSastAnalysis(isUnsafeCallee) .execute(ast.body); const result = sastAnalysis.getWarning(kWarningUnsafeStmt); @@ -47,7 +47,7 @@ test("should not detect Function", () => { const str = "Function('foo');"; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isUnsafeCallee) + const sastAnalysis = getSastAnalysis(isUnsafeCallee) .execute(ast.body); const result = sastAnalysis.getWarning(kWarningUnsafeStmt); diff --git a/workspaces/js-x-ray/test/probes/isUnsafeCommand.spec.ts b/workspaces/js-x-ray/test/probes/isUnsafeCommand.spec.ts index 7a5c40d..0cef099 100644 --- a/workspaces/js-x-ray/test/probes/isUnsafeCommand.spec.ts +++ b/workspaces/js-x-ray/test/probes/isUnsafeCommand.spec.ts @@ -23,7 +23,7 @@ test("should detect csrutil command", () => { `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isUnsafeCommand) + const sastAnalysis = getSastAnalysis(isUnsafeCommand) .execute(ast.body); const result = sastAnalysis.getWarning(kWarningUnsafeCommand); @@ -44,7 +44,7 @@ test.skip("should detect hidden csrutil command", () => { `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isUnsafeCommand) + const sastAnalysis = getSastAnalysis(isUnsafeCommand) .execute(ast.body); const result = sastAnalysis.getWarning(kWarningUnsafeCommand); @@ -63,7 +63,7 @@ test("should detect csrutil command with require", () => { `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isUnsafeCommand) + const sastAnalysis = getSastAnalysis(isUnsafeCommand) .execute(ast.body); const result = sastAnalysis.getWarning(kWarningUnsafeCommand); @@ -83,7 +83,7 @@ test("should not detect non suspicious command", () => { `; const ast = parseScript(str); - const sastAnalysis = getSastAnalysis(str, isUnsafeCommand) + const sastAnalysis = getSastAnalysis(isUnsafeCommand) .execute(ast.body); assert.equal(sastAnalysis.warnings().length, 0); @@ -107,7 +107,7 @@ test("aog-checker detection", () => { `; const ast = parseScript(maliciousCode); - const sastAnalysis = getSastAnalysis(maliciousCode, isUnsafeCommand) + const sastAnalysis = getSastAnalysis(isUnsafeCommand) .execute(ast.body); const result = sastAnalysis.getWarning(kWarningUnsafeCommand); @@ -124,7 +124,7 @@ test("mydummyproject-zyp detection", () => { `; const ast = parseScript(maliciousCode); - const sastAnalysis = getSastAnalysis(maliciousCode, isUnsafeCommand) + const sastAnalysis = getSastAnalysis(isUnsafeCommand) .execute(ast.body); const result = sastAnalysis.warnings(); diff --git a/workspaces/js-x-ray/test/utils/index.ts b/workspaces/js-x-ray/test/utils/index.ts index 9e924c1..1f15ed1 100644 --- a/workspaces/js-x-ray/test/utils/index.ts +++ b/workspaces/js-x-ray/test/utils/index.ts @@ -33,11 +33,10 @@ export function parseScript( } export function getSastAnalysis( - sourceCodeString: string, probe: Probe ) { return { - sourceFile: new SourceFile(sourceCodeString), + sourceFile: new SourceFile(), getWarning(warning: string): Warning | undefined { return this.warnings().find( (item: Warning) => item.kind === warning