@nodesecure/js-x-ray 9.1.0 → 10.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. package/dist/AstAnalyser.d.ts +79 -0
  2. package/dist/AstAnalyser.d.ts.map +1 -0
  3. package/dist/AstAnalyser.js +183 -0
  4. package/dist/AstAnalyser.js.map +1 -0
  5. package/dist/Deobfuscator.d.ts +36 -0
  6. package/dist/Deobfuscator.d.ts.map +1 -0
  7. package/dist/Deobfuscator.js +154 -0
  8. package/dist/Deobfuscator.js.map +1 -0
  9. package/dist/EntryFilesAnalyser.d.ts +20 -0
  10. package/dist/EntryFilesAnalyser.d.ts.map +1 -0
  11. package/dist/EntryFilesAnalyser.js +121 -0
  12. package/dist/EntryFilesAnalyser.js.map +1 -0
  13. package/dist/JsSourceParser.d.ts +18 -0
  14. package/dist/JsSourceParser.d.ts.map +1 -0
  15. package/dist/JsSourceParser.js +38 -0
  16. package/dist/JsSourceParser.js.map +1 -0
  17. package/dist/NodeCounter.d.ts +24 -0
  18. package/dist/NodeCounter.d.ts.map +1 -0
  19. package/dist/NodeCounter.js +62 -0
  20. package/dist/NodeCounter.js.map +1 -0
  21. package/dist/ProbeRunner.d.ts +45 -0
  22. package/dist/ProbeRunner.d.ts.map +1 -0
  23. package/dist/ProbeRunner.js +136 -0
  24. package/dist/ProbeRunner.js.map +1 -0
  25. package/dist/SourceFile.d.ts +26 -0
  26. package/dist/SourceFile.d.ts.map +1 -0
  27. package/dist/SourceFile.js +108 -0
  28. package/dist/SourceFile.js.map +1 -0
  29. package/dist/index.d.ts +7 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/{src/index.ts → dist/index.js} +2 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/obfuscators/freejsobfuscator.d.ts +3 -0
  34. package/dist/obfuscators/freejsobfuscator.d.ts.map +1 -0
  35. package/dist/obfuscators/freejsobfuscator.js +10 -0
  36. package/dist/obfuscators/freejsobfuscator.js.map +1 -0
  37. package/dist/obfuscators/jjencode.d.ts +3 -0
  38. package/dist/obfuscators/jjencode.d.ts.map +1 -0
  39. package/dist/obfuscators/jjencode.js +24 -0
  40. package/dist/obfuscators/jjencode.js.map +1 -0
  41. package/dist/obfuscators/jsfuck.d.ts +3 -0
  42. package/dist/obfuscators/jsfuck.d.ts.map +1 -0
  43. package/dist/obfuscators/jsfuck.js +13 -0
  44. package/dist/obfuscators/jsfuck.js.map +1 -0
  45. package/dist/obfuscators/obfuscator-io.d.ts +3 -0
  46. package/dist/obfuscators/obfuscator-io.d.ts.map +1 -0
  47. package/dist/obfuscators/obfuscator-io.js +15 -0
  48. package/dist/obfuscators/obfuscator-io.js.map +1 -0
  49. package/dist/obfuscators/trojan-source.d.ts +2 -0
  50. package/dist/obfuscators/trojan-source.d.ts.map +1 -0
  51. package/dist/obfuscators/trojan-source.js +27 -0
  52. package/dist/obfuscators/trojan-source.js.map +1 -0
  53. package/dist/pipelines/Runner.class.d.ts +11 -0
  54. package/dist/pipelines/Runner.class.d.ts.map +1 -0
  55. package/dist/pipelines/Runner.class.js +20 -0
  56. package/dist/pipelines/Runner.class.js.map +1 -0
  57. package/dist/pipelines/deobfuscate.d.ts +8 -0
  58. package/dist/pipelines/deobfuscate.d.ts.map +1 -0
  59. package/dist/pipelines/deobfuscate.js +33 -0
  60. package/dist/pipelines/deobfuscate.js.map +1 -0
  61. package/dist/pipelines/index.d.ts +8 -0
  62. package/dist/pipelines/index.d.ts.map +1 -0
  63. package/dist/pipelines/index.js +8 -0
  64. package/dist/pipelines/index.js.map +1 -0
  65. package/dist/probes/data-exfiltration.d.ts +19 -0
  66. package/dist/probes/data-exfiltration.d.ts.map +1 -0
  67. package/dist/probes/data-exfiltration.js +84 -0
  68. package/dist/probes/data-exfiltration.js.map +1 -0
  69. package/dist/probes/isArrayExpression.d.ts +21 -0
  70. package/dist/probes/isArrayExpression.d.ts.map +1 -0
  71. package/dist/probes/isArrayExpression.js +27 -0
  72. package/dist/probes/isArrayExpression.js.map +1 -0
  73. package/dist/probes/isBinaryExpression.d.ts +21 -0
  74. package/dist/probes/isBinaryExpression.d.ts.map +1 -0
  75. package/dist/probes/isBinaryExpression.js +54 -0
  76. package/dist/probes/isBinaryExpression.js.map +1 -0
  77. package/dist/probes/isESMExport.d.ts +24 -0
  78. package/dist/probes/isESMExport.d.ts.map +1 -0
  79. package/dist/probes/isESMExport.js +30 -0
  80. package/dist/probes/isESMExport.js.map +1 -0
  81. package/dist/probes/isFetch.d.ts +14 -0
  82. package/dist/probes/isFetch.d.ts.map +1 -0
  83. package/dist/probes/isFetch.js +26 -0
  84. package/dist/probes/isFetch.js.map +1 -0
  85. package/dist/probes/isImportDeclaration.d.ts +26 -0
  86. package/dist/probes/isImportDeclaration.d.ts.map +1 -0
  87. package/dist/probes/isImportDeclaration.js +38 -0
  88. package/dist/probes/isImportDeclaration.js.map +1 -0
  89. package/dist/probes/isLiteral.d.ts +21 -0
  90. package/dist/probes/isLiteral.d.ts.map +1 -0
  91. package/dist/probes/isLiteral.js +66 -0
  92. package/dist/probes/isLiteral.js.map +1 -0
  93. package/dist/probes/isLiteralRegex.d.ts +20 -0
  94. package/dist/probes/isLiteralRegex.d.ts.map +1 -0
  95. package/dist/probes/isLiteralRegex.js +30 -0
  96. package/dist/probes/isLiteralRegex.js.map +1 -0
  97. package/dist/probes/isRegexObject.d.ts +22 -0
  98. package/dist/probes/isRegexObject.d.ts.map +1 -0
  99. package/dist/probes/isRegexObject.js +50 -0
  100. package/dist/probes/isRegexObject.js.map +1 -0
  101. package/dist/probes/isRequire/RequireCallExpressionWalker.d.ts +15 -0
  102. package/dist/probes/isRequire/RequireCallExpressionWalker.d.ts.map +1 -0
  103. package/dist/probes/isRequire/RequireCallExpressionWalker.js +92 -0
  104. package/dist/probes/isRequire/RequireCallExpressionWalker.js.map +1 -0
  105. package/dist/probes/isRequire/isRequire.d.ts +15 -0
  106. package/dist/probes/isRequire/isRequire.d.ts.map +1 -0
  107. package/dist/probes/isRequire/isRequire.js +136 -0
  108. package/dist/probes/isRequire/isRequire.js.map +1 -0
  109. package/dist/probes/isSerializeEnv.d.ts +22 -0
  110. package/dist/probes/isSerializeEnv.d.ts.map +1 -0
  111. package/dist/probes/isSerializeEnv.js +68 -0
  112. package/dist/probes/isSerializeEnv.js.map +1 -0
  113. package/dist/probes/isSyncIO.d.ts +14 -0
  114. package/dist/probes/isSyncIO.d.ts.map +1 -0
  115. package/dist/probes/isSyncIO.js +73 -0
  116. package/dist/probes/isSyncIO.js.map +1 -0
  117. package/dist/probes/isUnsafeCallee.d.ts +19 -0
  118. package/dist/probes/isUnsafeCallee.d.ts.map +1 -0
  119. package/dist/probes/isUnsafeCallee.js +58 -0
  120. package/dist/probes/isUnsafeCallee.js.map +1 -0
  121. package/dist/probes/isUnsafeCommand.d.ts +21 -0
  122. package/dist/probes/isUnsafeCommand.d.ts.map +1 -0
  123. package/dist/probes/isUnsafeCommand.js +110 -0
  124. package/dist/probes/isUnsafeCommand.js.map +1 -0
  125. package/dist/probes/isWeakCrypto.d.ts +14 -0
  126. package/dist/probes/isWeakCrypto.d.ts.map +1 -0
  127. package/dist/probes/isWeakCrypto.js +46 -0
  128. package/dist/probes/isWeakCrypto.js.map +1 -0
  129. package/dist/types/estree.d.ts +12 -0
  130. package/dist/types/estree.d.ts.map +1 -0
  131. package/dist/types/estree.js +26 -0
  132. package/dist/types/estree.js.map +1 -0
  133. package/dist/utils/extractNode.d.ts +5 -0
  134. package/dist/utils/extractNode.d.ts.map +1 -0
  135. package/dist/utils/extractNode.js +13 -0
  136. package/dist/utils/extractNode.js.map +1 -0
  137. package/dist/utils/index.d.ts +5 -0
  138. package/dist/utils/index.d.ts.map +1 -0
  139. package/{src/utils/index.ts → dist/utils/index.js} +1 -0
  140. package/dist/utils/index.js.map +1 -0
  141. package/dist/utils/isOneLineExpressionExport.d.ts +3 -0
  142. package/dist/utils/isOneLineExpressionExport.d.ts.map +1 -0
  143. package/dist/utils/isOneLineExpressionExport.js +49 -0
  144. package/dist/utils/isOneLineExpressionExport.js.map +1 -0
  145. package/dist/utils/notNullOrUndefined.d.ts +2 -0
  146. package/dist/utils/notNullOrUndefined.d.ts.map +1 -0
  147. package/dist/utils/notNullOrUndefined.js +4 -0
  148. package/dist/utils/notNullOrUndefined.js.map +1 -0
  149. package/dist/utils/toArrayLocation.d.ts +5 -0
  150. package/dist/utils/toArrayLocation.d.ts.map +1 -0
  151. package/dist/utils/toArrayLocation.js +14 -0
  152. package/dist/utils/toArrayLocation.js.map +1 -0
  153. package/dist/walker/index.d.ts +9 -0
  154. package/dist/walker/index.d.ts.map +1 -0
  155. package/dist/walker/index.js +10 -0
  156. package/dist/walker/index.js.map +1 -0
  157. package/dist/walker/walker.base.d.ts +17 -0
  158. package/dist/walker/walker.base.d.ts.map +1 -0
  159. package/dist/walker/walker.base.js +45 -0
  160. package/dist/walker/walker.base.js.map +1 -0
  161. package/dist/walker/walker.sync.d.ts +15 -0
  162. package/dist/walker/walker.sync.d.ts.map +1 -0
  163. package/dist/walker/walker.sync.js +87 -0
  164. package/dist/walker/walker.sync.js.map +1 -0
  165. package/dist/warnings.d.ts +93 -0
  166. package/dist/warnings.d.ts.map +1 -0
  167. package/dist/warnings.js +96 -0
  168. package/dist/warnings.js.map +1 -0
  169. package/package.json +4 -8
  170. package/src/AstAnalyser.ts +0 -283
  171. package/src/Deobfuscator.ts +0 -228
  172. package/src/EntryFilesAnalyser.ts +0 -206
  173. package/src/JsSourceParser.ts +0 -77
  174. package/src/NodeCounter.ts +0 -90
  175. package/src/ProbeRunner.ts +0 -167
  176. package/src/SourceFile.ts +0 -226
  177. package/src/obfuscators/freejsobfuscator.ts +0 -17
  178. package/src/obfuscators/jjencode.ts +0 -39
  179. package/src/obfuscators/jsfuck.ts +0 -19
  180. package/src/obfuscators/obfuscator-io.ts +0 -25
  181. package/src/obfuscators/trojan-source.ts +0 -30
  182. package/src/probes/isArrayExpression.ts +0 -41
  183. package/src/probes/isBinaryExpression.ts +0 -74
  184. package/src/probes/isESMExport.ts +0 -50
  185. package/src/probes/isFetch.ts +0 -28
  186. package/src/probes/isImportDeclaration.ts +0 -58
  187. package/src/probes/isLiteral.ts +0 -91
  188. package/src/probes/isLiteralRegex.ts +0 -42
  189. package/src/probes/isRegexObject.ts +0 -71
  190. package/src/probes/isRequire/RequireCallExpressionWalker.ts +0 -142
  191. package/src/probes/isRequire/isRequire.ts +0 -195
  192. package/src/probes/isSerializeEnv.ts +0 -65
  193. package/src/probes/isSyncIO.ts +0 -96
  194. package/src/probes/isUnsafeCallee.ts +0 -89
  195. package/src/probes/isUnsafeCommand.ts +0 -133
  196. package/src/probes/isWeakCrypto.ts +0 -69
  197. package/src/types/estree.ts +0 -35
  198. package/src/utils/extractNode.ts +0 -22
  199. package/src/utils/isOneLineExpressionExport.ts +0 -70
  200. package/src/utils/notNullOrUndefined.ts +0 -5
  201. package/src/utils/toArrayLocation.ts +0 -22
  202. package/src/warnings.ts +0 -146
@@ -1,195 +0,0 @@
1
- /* eslint-disable consistent-return */
2
-
3
- // Import Third-party Dependencies
4
- import {
5
- concatBinaryExpression,
6
- arrayExpressionToString,
7
- getCallExpressionIdentifier,
8
- getCallExpressionArguments
9
- } from "@nodesecure/estree-ast-utils";
10
- import type { ESTree } from "meriyah";
11
-
12
- // Import Internal Dependencies
13
- import { ProbeSignals } from "../../ProbeRunner.js";
14
- import { SourceFile } from "../../SourceFile.js";
15
- import { isLiteral } from "../../types/estree.js";
16
- import { RequireCallExpressionWalker } from "./RequireCallExpressionWalker.js";
17
- import { generateWarning } from "../../warnings.js";
18
-
19
- function validateNodeRequire(
20
- node: ESTree.Node,
21
- { tracer }: SourceFile
22
- ): [boolean, any?] {
23
- const id = getCallExpressionIdentifier(node, {
24
- resolveCallExpression: false
25
- });
26
- if (id === null) {
27
- return [false];
28
- }
29
-
30
- const data = tracer.getDataFromIdentifier(id, {
31
- removeGlobalIdentifier: true
32
- });
33
-
34
- return [
35
- data !== null && data.name === "require",
36
- id ?? void 0
37
- ];
38
- }
39
-
40
- function validateNodeEvalRequire(
41
- node: ESTree.Node
42
- ): [boolean, any?] {
43
- const id = getCallExpressionIdentifier(node);
44
-
45
- if (id !== "eval") {
46
- return [false];
47
- }
48
-
49
- const castedNode = node as ESTree.CallExpression;
50
- if (castedNode.callee.type !== "CallExpression") {
51
- return [false];
52
- }
53
-
54
- const args = getCallExpressionArguments(castedNode.callee);
55
- if (args === null) {
56
- return [false];
57
- }
58
-
59
- return [
60
- args.length > 0 && args.at(0) === "require",
61
- id
62
- ];
63
- }
64
-
65
- function teardown(
66
- { sourceFile }: { sourceFile: SourceFile; }
67
- ) {
68
- sourceFile.dependencyAutoWarning = false;
69
- }
70
-
71
- function main(
72
- node: ESTree.CallExpression,
73
- options: { sourceFile: SourceFile; data?: string; }
74
- ) {
75
- const { sourceFile, data: calleeName } = options;
76
- const { tracer } = sourceFile;
77
-
78
- if (node.arguments.length === 0) {
79
- return;
80
- }
81
- const arg = node.arguments.at(0);
82
- if (arg === undefined) {
83
- return;
84
- }
85
-
86
- if (calleeName === "eval") {
87
- sourceFile.dependencyAutoWarning = true;
88
- }
89
- const location = node.loc;
90
-
91
- switch (arg.type) {
92
- // const foo = "http"; require(foo);
93
- case "Identifier":
94
- if (sourceFile.tracer.literalIdentifiers.has(arg.name)) {
95
- sourceFile.addDependency(
96
- sourceFile.tracer.literalIdentifiers.get(arg.name)!,
97
- node.loc
98
- );
99
- }
100
- else {
101
- sourceFile.warnings.push(
102
- generateWarning("unsafe-import", { value: null, location })
103
- );
104
- }
105
- break;
106
-
107
- // require("http")
108
- case "Literal":
109
- if (isLiteral(arg)) {
110
- sourceFile.addDependency(arg.value, node.loc);
111
- }
112
- break;
113
-
114
- // require(["ht", "tp"])
115
- case "ArrayExpression": {
116
- const value = [
117
- ...arrayExpressionToString(arg, {
118
- externalIdentifierLookup: (name) => tracer.literalIdentifiers.get(name) ?? null
119
- })
120
- ]
121
- .join("")
122
- .trim();
123
-
124
- if (value === "") {
125
- sourceFile.warnings.push(
126
- generateWarning("unsafe-import", { value: null, location })
127
- );
128
- }
129
- else {
130
- sourceFile.addDependency(value, node.loc);
131
- }
132
- break;
133
- }
134
-
135
- // require("ht" + "tp");
136
- case "BinaryExpression": {
137
- if (arg.operator !== "+") {
138
- sourceFile.warnings.push(
139
- generateWarning("unsafe-import", { value: null, location })
140
- );
141
- break;
142
- }
143
-
144
- try {
145
- const iter = concatBinaryExpression(arg, {
146
- externalIdentifierLookup: (name) => tracer.literalIdentifiers.get(name) ?? null,
147
- stopOnUnsupportedNode: true
148
- });
149
-
150
- sourceFile.addDependency([...iter].join(""), node.loc);
151
- }
152
- catch {
153
- sourceFile.warnings.push(
154
- generateWarning("unsafe-import", { value: null, location })
155
- );
156
- }
157
- break;
158
- }
159
-
160
- // require(Buffer.from("...", "hex").toString());
161
- case "CallExpression": {
162
- const walker = new RequireCallExpressionWalker(tracer);
163
- const { dependencies, triggerWarning } = walker.walk(arg);
164
- dependencies.forEach((depName) => sourceFile.addDependency(depName, node.loc, true));
165
-
166
- if (triggerWarning) {
167
- sourceFile.warnings.push(
168
- generateWarning("unsafe-import", { value: null, location })
169
- );
170
- }
171
-
172
- // We skip walking the tree to avoid anymore warnings...
173
- return ProbeSignals.Skip;
174
- }
175
-
176
- default:
177
- sourceFile.warnings.push(
178
- generateWarning("unsafe-import", { value: null, location })
179
- );
180
- }
181
-
182
- return;
183
- }
184
-
185
- export default {
186
- name: "isRequire",
187
- validateNode: [
188
- validateNodeRequire,
189
- validateNodeEvalRequire
190
- ],
191
- main,
192
- teardown,
193
- breakOnMatch: true,
194
- breakGroup: "import"
195
- };
@@ -1,65 +0,0 @@
1
- // Import Third-party Dependencies
2
- import {
3
- getCallExpressionIdentifier,
4
- getMemberExpressionIdentifier
5
- } from "@nodesecure/estree-ast-utils";
6
- import type { ESTree } from "meriyah";
7
-
8
- // Import Internal Dependencies
9
- import { SourceFile } from "../SourceFile.js";
10
- import { generateWarning } from "../warnings.js";
11
- import { ProbeSignals } from "../ProbeRunner.js";
12
-
13
- /**
14
- * @description Detect serialization of process.env which could indicate environment variable exfiltration
15
- * @example
16
- * JSON.stringify(process.env)
17
- * JSON.stringify(process["env"])
18
- * JSON.stringify(process["env"])
19
- * JSON.stringify(process[`env`])
20
- */
21
- function validateNode(
22
- node: ESTree.Node
23
- ): [boolean, any?] {
24
- const id = getCallExpressionIdentifier(node);
25
- if (id !== "JSON.stringify") {
26
- return [false];
27
- }
28
-
29
- const castedNode = node as ESTree.CallExpression;
30
- if (castedNode.arguments.length === 0) {
31
- return [false];
32
- }
33
-
34
- const firstArg = castedNode.arguments[0];
35
- if (firstArg.type === "MemberExpression") {
36
- const memberExprId = [...getMemberExpressionIdentifier(firstArg)].join(".");
37
- if (memberExprId === "process.env") {
38
- return [true];
39
- }
40
- }
41
-
42
- return [false];
43
- }
44
-
45
- function main(
46
- node: ESTree.Node,
47
- options: { sourceFile: SourceFile; }
48
- ) {
49
- const { sourceFile } = options;
50
-
51
- const warning = generateWarning("serialize-environment", {
52
- value: "JSON.stringify(process.env)",
53
- location: node.loc
54
- });
55
- sourceFile.warnings.push(warning);
56
-
57
- return ProbeSignals.Skip;
58
- }
59
-
60
- export default {
61
- name: "isSerializeEnv",
62
- validateNode,
63
- main,
64
- breakOnMatch: false
65
- };
@@ -1,96 +0,0 @@
1
- // Import Third-party Dependencies
2
- import { getCallExpressionIdentifier } from "@nodesecure/estree-ast-utils";
3
- import type { ESTree } from "meriyah";
4
-
5
- // Import Internal Dependencies
6
- import { SourceFile } from "../SourceFile.js";
7
- import { generateWarning } from "../warnings.js";
8
-
9
- // CONSTANTS
10
- const kTracedNodeCoreModules = ["fs", "crypto", "child_process", "zlib"];
11
- const kSyncIOIdentifierOrMemberExps = [
12
- "crypto.pbkdf2Sync",
13
- "crypto.scryptSync",
14
- "crypto.generateKeyPairSync",
15
- "fs.readFileSync",
16
- "fs.writeFileSync",
17
- "fs.appendFileSync",
18
- "fs.readSync",
19
- "fs.writeSync",
20
- "fs.readdirSync",
21
- "fs.statSync",
22
- "fs.mkdirSync",
23
- "fs.renameSync",
24
- "fs.unlinkSync",
25
- "fs.symlinkSync",
26
- "fs.openSync",
27
- "fs.fstatSync",
28
- "fs.linkSync",
29
- "fs.realpathSync",
30
- "child_process.execSync",
31
- "child_process.spawnSync",
32
- "child_process.execFileSync",
33
- "zlib.deflateSync",
34
- "zlib.inflateSync",
35
- "zlib.gzipSync",
36
- "zlib.gunzipSync",
37
- "zlib.brotliCompressSync",
38
- "zlib.brotliDecompressSync"
39
- ];
40
-
41
- function validateNode(
42
- node: ESTree.Node,
43
- { tracer }: SourceFile
44
- ): [boolean, any?] {
45
- const id = getCallExpressionIdentifier(
46
- node,
47
- {
48
- externalIdentifierLookup: (name) => tracer.literalIdentifiers.get(name) ?? null
49
- }
50
- );
51
- if (
52
- id === null ||
53
- !kTracedNodeCoreModules.some((moduleName) => tracer.importedModules.has(moduleName))
54
- ) {
55
- return [false];
56
- }
57
-
58
- const data = tracer.getDataFromIdentifier(id);
59
-
60
- return [
61
- data !== null &&
62
- data.identifierOrMemberExpr.endsWith("Sync")
63
- ];
64
- }
65
-
66
- function initialize(
67
- sourceFile: SourceFile
68
- ) {
69
- kSyncIOIdentifierOrMemberExps.forEach((identifierOrMemberExp) => {
70
- const moduleName = identifierOrMemberExp.split(".")[0];
71
-
72
- return sourceFile.tracer.trace(identifierOrMemberExp, {
73
- followConsecutiveAssignment: true,
74
- moduleName
75
- });
76
- });
77
- }
78
-
79
- function main(
80
- node: ESTree.CallExpression,
81
- { sourceFile }: { sourceFile: SourceFile; }
82
- ) {
83
- const warning = generateWarning("synchronous-io", {
84
- value: node.callee.name,
85
- location: node.loc
86
- });
87
- sourceFile.warnings.push(warning);
88
- }
89
-
90
- export default {
91
- name: "isSyncIO",
92
- validateNode,
93
- main,
94
- initialize,
95
- breakOnMatch: false
96
- };
@@ -1,89 +0,0 @@
1
- // Import Third-party Dependencies
2
- import type { ESTree } from "meriyah";
3
- import { getCallExpressionIdentifier } from "@nodesecure/estree-ast-utils";
4
-
5
- // Import Internal Dependencies
6
- import { SourceFile } from "../SourceFile.js";
7
- import { generateWarning } from "../warnings.js";
8
- import { ProbeSignals } from "../ProbeRunner.js";
9
-
10
- /**
11
- * @description Detect unsafe statement
12
- * @example
13
- * eval("this");
14
- * Function("return this")();
15
- */
16
- function validateNode(
17
- node: ESTree.Node
18
- ): [boolean, any?] {
19
- return isUnsafeCallee(node);
20
- }
21
-
22
- function main(
23
- node: ESTree.CallExpression,
24
- options: { sourceFile: SourceFile; data?: string; }
25
- ) {
26
- const { sourceFile, data: calleeName } = options;
27
-
28
- if (!calleeName) {
29
- return ProbeSignals.Skip;
30
- }
31
- if (
32
- calleeName === "Function" &&
33
- node.callee.arguments.length > 0 &&
34
- node.callee.arguments[0].value === "return this"
35
- ) {
36
- return ProbeSignals.Skip;
37
- }
38
-
39
- const warning = generateWarning("unsafe-stmt", {
40
- value: calleeName,
41
- location: node.loc
42
- });
43
- sourceFile.warnings.push(warning);
44
-
45
- return ProbeSignals.Skip;
46
- }
47
-
48
- function isEvalCallee(
49
- node: ESTree.CallExpression
50
- ): boolean {
51
- const identifier = getCallExpressionIdentifier(node, {
52
- resolveCallExpression: false
53
- });
54
-
55
- return identifier === "eval";
56
- }
57
-
58
- function isFunctionCallee(
59
- node: ESTree.CallExpression
60
- ): boolean {
61
- const identifier = getCallExpressionIdentifier(node);
62
-
63
- return identifier === "Function" && node.callee.type === "CallExpression";
64
- }
65
-
66
- export function isUnsafeCallee(
67
- node: ESTree.CallExpression | ESTree.Node
68
- ): [boolean, "eval" | "Function" | null] {
69
- if (node.type !== "CallExpression") {
70
- return [false, null];
71
- }
72
-
73
- if (isEvalCallee(node)) {
74
- return [true, "eval"];
75
- }
76
-
77
- if (isFunctionCallee(node)) {
78
- return [true, "Function"];
79
- }
80
-
81
- return [false, null];
82
- }
83
-
84
- export default {
85
- name: "isUnsafeCallee",
86
- validateNode,
87
- main,
88
- breakOnMatch: false
89
- };
@@ -1,133 +0,0 @@
1
- // Import Third-party Dependencies
2
- import type { ESTree } from "meriyah";
3
-
4
- // Import Internal Dependencies
5
- import { SourceFile } from "../SourceFile.js";
6
- import { generateWarning } from "../warnings.js";
7
- import { ProbeSignals } from "../ProbeRunner.js";
8
- import { isLiteral } from "../types/estree.js";
9
-
10
- // CONSTANTS
11
- const kUnsafeCommands = ["csrutil"];
12
-
13
- function isUnsafeCommand(
14
- command: string
15
- ): boolean {
16
- return kUnsafeCommands.some((unsafeCommand) => command.includes(unsafeCommand));
17
- }
18
-
19
- function isSpawnOrExec(
20
- name: string
21
- ): boolean {
22
- return name === "spawn" ||
23
- name === "exec" ||
24
- name === "spawnSync" ||
25
- name === "execSync";
26
- }
27
-
28
- /**
29
- * @description Detect spawn or exec unsafe commands
30
- * @example
31
- * child_process.spawn("csrutil", ["status"]);
32
- *
33
- * require("child_process").spawn("csrutil", ["disable"]);
34
- *
35
- * const { exec } = require("child_process");
36
- * exec("csrutil status");
37
- */
38
- function validateNode(
39
- node: ESTree.Node
40
- ): [boolean, any?] {
41
- if (node.type !== "CallExpression" || node.arguments.length === 0) {
42
- return [false];
43
- }
44
-
45
- // const { spawn } = require("child_process");
46
- // spawn("...", ["..."]);
47
- // or
48
- // const { exec } = require("child_process");
49
- // exec(...);
50
- if (node.type === "CallExpression" &&
51
- node.callee.type === "Identifier" &&
52
- isSpawnOrExec(node.callee.name)
53
- ) {
54
- return [true, node.callee.name];
55
- }
56
-
57
- // child_process.spawn(...) or require("child_process").spawn(...)
58
- // child_process.exec(...) or require("child_process").exec(...)
59
- if (
60
- node.callee.type === "MemberExpression" &&
61
- node.callee.property.type === "Identifier" &&
62
- isSpawnOrExec(node.callee.property.name)
63
- ) {
64
- // child_process.spawn(...)
65
- // child_process.exec(...)
66
- if (
67
- node.callee.object.type === "Identifier" &&
68
- node.callee.object.name === "child_process"
69
- ) {
70
- return [true, node.callee.property.name];
71
- }
72
- // require("child_process").spawn(...)
73
- // require("child_process").exec(...)
74
- if (
75
- node.callee.object.type === "CallExpression" &&
76
- node.callee.object.callee.type === "Identifier" &&
77
- node.callee.object.callee.name === "require" &&
78
- node.callee.object.arguments.length === 1 &&
79
- node.callee.object.arguments[0].type === "Literal" &&
80
- node.callee.object.arguments[0].value === "child_process"
81
- ) {
82
- return [true, node.callee.property.name];
83
- }
84
- }
85
-
86
- return [false];
87
- }
88
-
89
- function main(
90
- node: ESTree.CallExpression,
91
- options: { sourceFile: SourceFile; data?: string; }
92
- ) {
93
- const { sourceFile, data: methodName } = options;
94
-
95
- const commandArg = node.arguments[0];
96
- if (!isLiteral(commandArg)) {
97
- return null;
98
- }
99
-
100
- let command = commandArg.value;
101
- if (isUnsafeCommand(command)) {
102
- // Spawned command arguments are filled into an Array
103
- // as second arguments. This is why we should add them
104
- // manually to the command string.
105
- if (methodName === "spawn" || methodName === "spawnSync") {
106
- const arrExpr = node.arguments.at(1);
107
-
108
- if (arrExpr && arrExpr.type === "ArrayExpression") {
109
- arrExpr.elements
110
- .filter((element) => isLiteral(element))
111
- .forEach((element) => {
112
- command += ` ${element.value}`;
113
- });
114
- }
115
- }
116
-
117
- const warning = generateWarning("unsafe-command", {
118
- value: command,
119
- location: node.loc
120
- });
121
- sourceFile.warnings.push(warning);
122
-
123
- return ProbeSignals.Skip;
124
- }
125
-
126
- return null;
127
- }
128
-
129
- export default {
130
- name: "isUnsafeCommand",
131
- validateNode,
132
- main
133
- };
@@ -1,69 +0,0 @@
1
- // Import Third-party Dependencies
2
- import { getCallExpressionIdentifier } from "@nodesecure/estree-ast-utils";
3
- import type { ESTree } from "meriyah";
4
-
5
- // Import Internal Dependencies
6
- import { SourceFile } from "../SourceFile.js";
7
- import { generateWarning } from "../warnings.js";
8
- import {
9
- isLiteral
10
- } from "../types/estree.js";
11
-
12
- // CONSTANTS
13
- const kWeakAlgorithms = new Set([
14
- "md5",
15
- "sha1",
16
- "ripemd160",
17
- "md4",
18
- "md2"
19
- ]);
20
-
21
- function validateNode(
22
- node: ESTree.Node,
23
- sourceFile: SourceFile
24
- ): [boolean, any?] {
25
- const { tracer } = sourceFile;
26
-
27
- const id = getCallExpressionIdentifier(node);
28
- if (id === null || !tracer.importedModules.has("crypto")) {
29
- return [false];
30
- }
31
-
32
- const data = tracer.getDataFromIdentifier(id);
33
-
34
- return [
35
- data !== null && data.identifierOrMemberExpr === "crypto.createHash"
36
- ];
37
- }
38
-
39
- function initialize(
40
- sourceFile: SourceFile
41
- ) {
42
- sourceFile.tracer.trace("crypto.createHash", {
43
- followConsecutiveAssignment: true,
44
- moduleName: "crypto"
45
- });
46
- }
47
-
48
- function main(
49
- node: ESTree.CallExpression,
50
- { sourceFile }: { sourceFile: SourceFile; }
51
- ) {
52
- const arg = node.arguments.at(0);
53
-
54
- if (isLiteral(arg) && kWeakAlgorithms.has(arg.value)) {
55
- const warning = generateWarning(
56
- "weak-crypto",
57
- { value: arg.value, location: node.loc }
58
- );
59
- sourceFile.warnings.push(warning);
60
- }
61
- }
62
-
63
- export default {
64
- name: "isWeakCrypto",
65
- validateNode,
66
- main,
67
- initialize,
68
- breakOnMatch: false
69
- };
@@ -1,35 +0,0 @@
1
- // Import Third-party Dependencies
2
- import type { ESTree } from "meriyah";
3
-
4
- export type Literal<T> = ESTree.Literal & {
5
- value: T;
6
- };
7
-
8
- export type RegExpLiteral<T> = ESTree.RegExpLiteral & {
9
- value: T;
10
- };
11
-
12
- export function isNode(
13
- value: any
14
- ): value is ESTree.Node {
15
- return (
16
- value !== null &&
17
- typeof value === "object" &&
18
- "type" in value &&
19
- typeof value.type === "string"
20
- );
21
- }
22
-
23
- export function isLiteral(
24
- node: any
25
- ): node is Literal<string> {
26
- return isNode(node) &&
27
- node.type === "Literal" &&
28
- typeof node.value === "string";
29
- }
30
-
31
- export function isCallExpression(
32
- node: any
33
- ): node is ESTree.CallExpression {
34
- return isNode(node) && node.type === "CallExpression";
35
- }
@@ -1,22 +0,0 @@
1
- // Import Third-party Dependencies
2
- import type { ESTree } from "meriyah";
3
-
4
- // Import Internal Dependencies
5
- import { isNode } from "../types/estree.js";
6
-
7
- export type NodeExtractorCallback<T> = (node: T) => void;
8
- export type NodeOrNull = ESTree.Node | null;
9
-
10
- export function extractNode<T extends ESTree.Node>(
11
- expectedType: T["type"]
12
- ) {
13
- return (callback: NodeExtractorCallback<T>, nodes: NodeOrNull | NodeOrNull[]) => {
14
- const finalNodes = Array.isArray(nodes) ? nodes : [nodes];
15
-
16
- for (const node of finalNodes) {
17
- if (isNode(node) && node.type === expectedType) {
18
- callback(node as T);
19
- }
20
- }
21
- };
22
- }