cognium-dev 3.59.0 → 3.64.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.
- package/dist/cli.js +542 -64
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -3612,7 +3612,7 @@ function detectLanguage(tree) {
|
|
|
3612
3612
|
}
|
|
3613
3613
|
function extractTypes(tree, cache, language) {
|
|
3614
3614
|
const effectiveLanguage = language ?? detectLanguage(tree);
|
|
3615
|
-
const isJavaScript = effectiveLanguage === "javascript" || effectiveLanguage === "typescript";
|
|
3615
|
+
const isJavaScript = effectiveLanguage === "javascript" || effectiveLanguage === "typescript" || effectiveLanguage === "tsx";
|
|
3616
3616
|
const isPython = effectiveLanguage === "python";
|
|
3617
3617
|
const isRust = effectiveLanguage === "rust";
|
|
3618
3618
|
if (effectiveLanguage === "go") {
|
|
@@ -5041,7 +5041,7 @@ function detectLanguageFromTree(tree, cache) {
|
|
|
5041
5041
|
function extractCalls(tree, cache, language) {
|
|
5042
5042
|
const calls = [];
|
|
5043
5043
|
const detectedLanguage = language ?? detectLanguageFromTree(tree, cache);
|
|
5044
|
-
const isJavaScript = detectedLanguage === "javascript" || detectedLanguage === "typescript";
|
|
5044
|
+
const isJavaScript = detectedLanguage === "javascript" || detectedLanguage === "typescript" || detectedLanguage === "tsx";
|
|
5045
5045
|
const isPython = detectedLanguage === "python";
|
|
5046
5046
|
const isRust = detectedLanguage === "rust";
|
|
5047
5047
|
if (detectedLanguage === "go") {
|
|
@@ -5090,8 +5090,149 @@ function extractJavaScriptCalls(tree, cache) {
|
|
|
5090
5090
|
calls.push(callInfo);
|
|
5091
5091
|
}
|
|
5092
5092
|
}
|
|
5093
|
+
const jsxAttributes = getNodesFromCache(tree.rootNode, "jsx_attribute", cache);
|
|
5094
|
+
for (const attr of jsxAttributes) {
|
|
5095
|
+
const callInfo = extractJSXAttributeSink(attr);
|
|
5096
|
+
if (callInfo) {
|
|
5097
|
+
calls.push(callInfo);
|
|
5098
|
+
}
|
|
5099
|
+
}
|
|
5100
|
+
const assignments = getNodesFromCache(tree.rootNode, "assignment_expression", cache);
|
|
5101
|
+
for (const assign of assignments) {
|
|
5102
|
+
const callInfo = extractDomPropertyAssignmentSink(assign);
|
|
5103
|
+
if (callInfo) {
|
|
5104
|
+
calls.push(callInfo);
|
|
5105
|
+
}
|
|
5106
|
+
}
|
|
5093
5107
|
return calls;
|
|
5094
5108
|
}
|
|
5109
|
+
var DOM_XSS_ASSIGNMENT_PROPERTIES = new Set([
|
|
5110
|
+
"innerHTML",
|
|
5111
|
+
"outerHTML"
|
|
5112
|
+
]);
|
|
5113
|
+
function extractDomPropertyAssignmentSink(node) {
|
|
5114
|
+
const leftNode = node.childForFieldName("left");
|
|
5115
|
+
const rightNode = node.childForFieldName("right");
|
|
5116
|
+
if (!leftNode || !rightNode)
|
|
5117
|
+
return null;
|
|
5118
|
+
if (leftNode.type !== "member_expression")
|
|
5119
|
+
return null;
|
|
5120
|
+
const propertyNode = leftNode.childForFieldName("property");
|
|
5121
|
+
const objectNode = leftNode.childForFieldName("object");
|
|
5122
|
+
if (!propertyNode)
|
|
5123
|
+
return null;
|
|
5124
|
+
const propertyName = getNodeText(propertyNode);
|
|
5125
|
+
if (!DOM_XSS_ASSIGNMENT_PROPERTIES.has(propertyName))
|
|
5126
|
+
return null;
|
|
5127
|
+
const receiver = objectNode ? getNodeText(objectNode) : null;
|
|
5128
|
+
const expression = getNodeText(rightNode);
|
|
5129
|
+
const { variable, literal } = analyzeJSArgument(rightNode);
|
|
5130
|
+
const enclosingFunc = findJSEnclosingFunction(node);
|
|
5131
|
+
return {
|
|
5132
|
+
method_name: propertyName,
|
|
5133
|
+
receiver,
|
|
5134
|
+
arguments: [
|
|
5135
|
+
{
|
|
5136
|
+
position: 0,
|
|
5137
|
+
expression,
|
|
5138
|
+
variable,
|
|
5139
|
+
literal
|
|
5140
|
+
}
|
|
5141
|
+
],
|
|
5142
|
+
location: {
|
|
5143
|
+
line: node.startPosition.row + 1,
|
|
5144
|
+
column: node.startPosition.column
|
|
5145
|
+
},
|
|
5146
|
+
in_method: enclosingFunc,
|
|
5147
|
+
resolved: true,
|
|
5148
|
+
resolution: {
|
|
5149
|
+
status: "resolved",
|
|
5150
|
+
target: `DOM.${propertyName}`
|
|
5151
|
+
}
|
|
5152
|
+
};
|
|
5153
|
+
}
|
|
5154
|
+
function extractJSXAttributeSink(attr) {
|
|
5155
|
+
let nameNode = null;
|
|
5156
|
+
for (let i2 = 0;i2 < attr.childCount; i2++) {
|
|
5157
|
+
const child = attr.child(i2);
|
|
5158
|
+
if (child && child.type === "property_identifier") {
|
|
5159
|
+
nameNode = child;
|
|
5160
|
+
break;
|
|
5161
|
+
}
|
|
5162
|
+
}
|
|
5163
|
+
if (!nameNode)
|
|
5164
|
+
return null;
|
|
5165
|
+
const attrName = getNodeText(nameNode);
|
|
5166
|
+
if (attrName !== "dangerouslySetInnerHTML")
|
|
5167
|
+
return null;
|
|
5168
|
+
let valueExpr = null;
|
|
5169
|
+
for (let i2 = 0;i2 < attr.childCount; i2++) {
|
|
5170
|
+
const child = attr.child(i2);
|
|
5171
|
+
if (child && child.type === "jsx_expression") {
|
|
5172
|
+
valueExpr = child;
|
|
5173
|
+
break;
|
|
5174
|
+
}
|
|
5175
|
+
}
|
|
5176
|
+
if (!valueExpr)
|
|
5177
|
+
return null;
|
|
5178
|
+
let htmlValue = null;
|
|
5179
|
+
for (let i2 = 0;i2 < valueExpr.childCount; i2++) {
|
|
5180
|
+
const inner = valueExpr.child(i2);
|
|
5181
|
+
if (!inner || inner.type !== "object")
|
|
5182
|
+
continue;
|
|
5183
|
+
for (let j = 0;j < inner.childCount; j++) {
|
|
5184
|
+
const pair = inner.child(j);
|
|
5185
|
+
if (!pair || pair.type !== "pair")
|
|
5186
|
+
continue;
|
|
5187
|
+
const keyNode = pair.childForFieldName("key");
|
|
5188
|
+
if (!keyNode)
|
|
5189
|
+
continue;
|
|
5190
|
+
const keyText = getNodeText(keyNode).replace(/^["']|["']$/g, "");
|
|
5191
|
+
if (keyText === "__html") {
|
|
5192
|
+
htmlValue = pair.childForFieldName("value");
|
|
5193
|
+
break;
|
|
5194
|
+
}
|
|
5195
|
+
}
|
|
5196
|
+
if (htmlValue)
|
|
5197
|
+
break;
|
|
5198
|
+
}
|
|
5199
|
+
if (!htmlValue) {
|
|
5200
|
+
for (let i2 = 0;i2 < valueExpr.childCount; i2++) {
|
|
5201
|
+
const inner = valueExpr.child(i2);
|
|
5202
|
+
if (inner && inner.type !== "{" && inner.type !== "}") {
|
|
5203
|
+
htmlValue = inner;
|
|
5204
|
+
break;
|
|
5205
|
+
}
|
|
5206
|
+
}
|
|
5207
|
+
}
|
|
5208
|
+
if (!htmlValue)
|
|
5209
|
+
return null;
|
|
5210
|
+
const expression = getNodeText(htmlValue);
|
|
5211
|
+
const { variable, literal } = analyzeJSArgument(htmlValue);
|
|
5212
|
+
const enclosingFunc = findJSEnclosingFunction(attr);
|
|
5213
|
+
return {
|
|
5214
|
+
method_name: "dangerouslySetInnerHTML",
|
|
5215
|
+
receiver: null,
|
|
5216
|
+
arguments: [
|
|
5217
|
+
{
|
|
5218
|
+
position: 0,
|
|
5219
|
+
expression,
|
|
5220
|
+
variable,
|
|
5221
|
+
literal
|
|
5222
|
+
}
|
|
5223
|
+
],
|
|
5224
|
+
location: {
|
|
5225
|
+
line: attr.startPosition.row + 1,
|
|
5226
|
+
column: attr.startPosition.column
|
|
5227
|
+
},
|
|
5228
|
+
in_method: enclosingFunc,
|
|
5229
|
+
resolved: true,
|
|
5230
|
+
resolution: {
|
|
5231
|
+
status: "resolved",
|
|
5232
|
+
target: "react.dangerouslySetInnerHTML"
|
|
5233
|
+
}
|
|
5234
|
+
};
|
|
5235
|
+
}
|
|
5095
5236
|
function buildJSResolutionContext(tree, cache) {
|
|
5096
5237
|
const context = {
|
|
5097
5238
|
functionNames: new Set,
|
|
@@ -6632,7 +6773,7 @@ function detectLanguage2(tree) {
|
|
|
6632
6773
|
}
|
|
6633
6774
|
function extractImports(tree, language) {
|
|
6634
6775
|
const effectiveLanguage = language ?? detectLanguage2(tree);
|
|
6635
|
-
const isJavaScript = effectiveLanguage === "javascript" || effectiveLanguage === "typescript";
|
|
6776
|
+
const isJavaScript = effectiveLanguage === "javascript" || effectiveLanguage === "typescript" || effectiveLanguage === "tsx";
|
|
6636
6777
|
const isPython = effectiveLanguage === "python";
|
|
6637
6778
|
const isRust = effectiveLanguage === "rust";
|
|
6638
6779
|
if (effectiveLanguage === "go") {
|
|
@@ -7347,7 +7488,7 @@ function detectLanguage3(tree) {
|
|
|
7347
7488
|
}
|
|
7348
7489
|
function buildCFG(tree, language) {
|
|
7349
7490
|
const effectiveLanguage = language ?? detectLanguage3(tree);
|
|
7350
|
-
const isJavaScript = effectiveLanguage === "javascript" || effectiveLanguage === "typescript";
|
|
7491
|
+
const isJavaScript = effectiveLanguage === "javascript" || effectiveLanguage === "typescript" || effectiveLanguage === "tsx";
|
|
7351
7492
|
const allBlocks = [];
|
|
7352
7493
|
const allEdges = [];
|
|
7353
7494
|
let blockIdCounter = 0;
|
|
@@ -7928,7 +8069,7 @@ function detectLanguage4(tree) {
|
|
|
7928
8069
|
}
|
|
7929
8070
|
function buildDFG(tree, cache, language) {
|
|
7930
8071
|
const effectiveLanguage = language ?? detectLanguage4(tree);
|
|
7931
|
-
const isJavaScript = effectiveLanguage === "javascript" || effectiveLanguage === "typescript";
|
|
8072
|
+
const isJavaScript = effectiveLanguage === "javascript" || effectiveLanguage === "typescript" || effectiveLanguage === "tsx";
|
|
7932
8073
|
if (isJavaScript) {
|
|
7933
8074
|
return buildJavaScriptDFG(tree, cache);
|
|
7934
8075
|
}
|
|
@@ -8749,7 +8890,18 @@ function buildBashDFG(tree) {
|
|
|
8749
8890
|
if (varNameNode) {
|
|
8750
8891
|
const varName = getNodeText(varNameNode);
|
|
8751
8892
|
if (varName && !varName.startsWith("?") && !varName.startsWith("#")) {
|
|
8752
|
-
|
|
8893
|
+
let reachingDef = findReachingDef(varName, scopeStack);
|
|
8894
|
+
if (reachingDef === null && !positionalParams.includes(varName)) {
|
|
8895
|
+
const def = {
|
|
8896
|
+
id: defIdCounter++,
|
|
8897
|
+
variable: varName,
|
|
8898
|
+
line: 0,
|
|
8899
|
+
kind: "param"
|
|
8900
|
+
};
|
|
8901
|
+
defs.push(def);
|
|
8902
|
+
scopeStack[0].set(varName, def.id);
|
|
8903
|
+
reachingDef = def.id;
|
|
8904
|
+
}
|
|
8753
8905
|
uses.push({
|
|
8754
8906
|
id: useIdCounter++,
|
|
8755
8907
|
variable: varName,
|
|
@@ -8762,7 +8914,18 @@ function buildBashDFG(tree) {
|
|
|
8762
8914
|
const varNameNode = node.namedChildCount > 0 ? node.namedChild(0) : null;
|
|
8763
8915
|
if (varNameNode && varNameNode.type === "variable_name") {
|
|
8764
8916
|
const varName = getNodeText(varNameNode);
|
|
8765
|
-
|
|
8917
|
+
let reachingDef = findReachingDef(varName, scopeStack);
|
|
8918
|
+
if (reachingDef === null && !positionalParams.includes(varName)) {
|
|
8919
|
+
const def = {
|
|
8920
|
+
id: defIdCounter++,
|
|
8921
|
+
variable: varName,
|
|
8922
|
+
line: 0,
|
|
8923
|
+
kind: "param"
|
|
8924
|
+
};
|
|
8925
|
+
defs.push(def);
|
|
8926
|
+
scopeStack[0].set(varName, def.id);
|
|
8927
|
+
reachingDef = def.id;
|
|
8928
|
+
}
|
|
8766
8929
|
uses.push({
|
|
8767
8930
|
id: useIdCounter++,
|
|
8768
8931
|
variable: varName,
|
|
@@ -9234,7 +9397,7 @@ var FRAMEWORK_MODULE_PATTERNS = [
|
|
|
9234
9397
|
/^@nestjs\/core$/
|
|
9235
9398
|
];
|
|
9236
9399
|
function extractRuntimeRegistrations(tree, cache, language, imports) {
|
|
9237
|
-
if (language === "javascript" || language === "typescript") {
|
|
9400
|
+
if (language === "javascript" || language === "typescript" || language === "tsx") {
|
|
9238
9401
|
return extractJSRuntimeRegistrations(tree, cache, imports);
|
|
9239
9402
|
}
|
|
9240
9403
|
if (language === "python") {
|
|
@@ -10171,8 +10334,11 @@ var DEFAULT_SOURCES = [
|
|
|
10171
10334
|
{ method: "get", class: "cookies", type: "http_cookie", severity: "high", return_tainted: true },
|
|
10172
10335
|
{ property: "json", object: "request", type: "http_body", severity: "high", property_tainted: true },
|
|
10173
10336
|
{ property: "data", object: "request", type: "http_body", severity: "high", property_tainted: true },
|
|
10337
|
+
{ property: "stream", object: "request", type: "http_body", severity: "high", property_tainted: true },
|
|
10174
10338
|
{ property: "path", object: "request", type: "http_path", severity: "medium", property_tainted: true },
|
|
10175
10339
|
{ property: "query_string", object: "request", type: "http_query", severity: "high", property_tainted: true },
|
|
10340
|
+
{ method: "get_data", class: "request", type: "http_body", severity: "high", return_tainted: true },
|
|
10341
|
+
{ method: "get_json", class: "request", type: "http_body", severity: "high", return_tainted: true },
|
|
10176
10342
|
{ method: "get", class: "GET", type: "http_param", severity: "high", return_tainted: true },
|
|
10177
10343
|
{ method: "get", class: "POST", type: "http_param", severity: "high", return_tainted: true },
|
|
10178
10344
|
{ method: "get", class: "META", type: "http_header", severity: "high", return_tainted: true },
|
|
@@ -10335,13 +10501,13 @@ var DEFAULT_SINKS = [
|
|
|
10335
10501
|
{ method: "setExecutable", class: "ExecTask", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10336
10502
|
{ method: "setCommand", class: "ExecTask", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10337
10503
|
{ method: "execute", class: "Java", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10338
|
-
{ method: "bash", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10339
|
-
{ method: "shell", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10340
|
-
{ method: "sh", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10341
|
-
{ method: "spawn", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10342
|
-
{ method: "fork", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10343
|
-
{ method: "popen", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10344
|
-
{ method: "system", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10504
|
+
{ method: "bash", languages: ["java", "javascript", "typescript", "python", "go", "rust"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10505
|
+
{ method: "shell", languages: ["java", "javascript", "typescript", "python", "go", "rust"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10506
|
+
{ method: "sh", languages: ["java", "javascript", "typescript", "python", "go", "rust"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10507
|
+
{ method: "spawn", languages: ["java", "javascript", "typescript", "python", "go", "rust"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10508
|
+
{ method: "fork", languages: ["java", "javascript", "typescript", "python", "go", "rust"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10509
|
+
{ method: "popen", languages: ["java", "javascript", "typescript", "python", "go", "rust"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10510
|
+
{ method: "system", languages: ["java", "javascript", "typescript", "python", "go", "rust"], type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10345
10511
|
{ method: "setCommandline", class: "DefaultExecutor", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10346
10512
|
{ method: "parse", class: "CommandLine", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10347
10513
|
{ method: "addArgument", class: "CommandLine", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
@@ -10404,6 +10570,9 @@ var DEFAULT_SINKS = [
|
|
|
10404
10570
|
{ method: "unzip", type: "path_traversal", cwe: "CWE-22", severity: "critical", arg_positions: [0, 1] },
|
|
10405
10571
|
{ method: "extract", type: "path_traversal", cwe: "CWE-22", severity: "critical", arg_positions: [0, 1] },
|
|
10406
10572
|
{ method: "extractAll", type: "path_traversal", cwe: "CWE-22", severity: "critical", arg_positions: [0, 1] },
|
|
10573
|
+
{ method: "extractall", type: "path_traversal", cwe: "CWE-22", severity: "critical", arg_positions: [0], languages: ["python"] },
|
|
10574
|
+
{ method: "ZipFile", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["python"] },
|
|
10575
|
+
{ method: "send_from_directory", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [1], languages: ["python"] },
|
|
10407
10576
|
{ method: "unjar", type: "path_traversal", cwe: "CWE-22", severity: "critical", arg_positions: [0, 1] },
|
|
10408
10577
|
{ method: "PrintWriter", class: "constructor", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
|
|
10409
10578
|
{ method: "Scanner", class: "constructor", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
|
|
@@ -11171,10 +11340,22 @@ var DEFAULT_SINKS = [
|
|
|
11171
11340
|
{ method: "redirect", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [0], languages: ["javascript", "typescript"] },
|
|
11172
11341
|
{ method: "Set", class: "Header", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["go"] },
|
|
11173
11342
|
{ method: "Add", class: "Header", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["go"] },
|
|
11174
|
-
{ method: "assign", class: "Object", type: "mass_assignment", cwe: "CWE-
|
|
11175
|
-
{ method: "
|
|
11176
|
-
{ method: "
|
|
11177
|
-
{ method: "
|
|
11343
|
+
{ method: "assign", class: "Object", type: "mass_assignment", cwe: "CWE-1321", severity: "high", arg_positions: [1, 2, 3], languages: ["javascript", "typescript"] },
|
|
11344
|
+
{ method: "defineProperty", class: "Object", type: "mass_assignment", cwe: "CWE-1321", severity: "high", arg_positions: [1, 2], languages: ["javascript", "typescript"] },
|
|
11345
|
+
{ method: "defineProperties", class: "Object", type: "mass_assignment", cwe: "CWE-1321", severity: "high", arg_positions: [1], languages: ["javascript", "typescript"] },
|
|
11346
|
+
{ method: "merge", class: "_", type: "mass_assignment", cwe: "CWE-1321", severity: "high", arg_positions: [1, 2, 3], languages: ["javascript", "typescript"] },
|
|
11347
|
+
{ method: "merge", class: "lodash", type: "mass_assignment", cwe: "CWE-1321", severity: "high", arg_positions: [1, 2, 3], languages: ["javascript", "typescript"] },
|
|
11348
|
+
{ method: "extend", class: "_", type: "mass_assignment", cwe: "CWE-1321", severity: "high", arg_positions: [1, 2, 3], languages: ["javascript", "typescript"] },
|
|
11349
|
+
{ method: "extend", class: "lodash", type: "mass_assignment", cwe: "CWE-1321", severity: "high", arg_positions: [1, 2, 3], languages: ["javascript", "typescript"] },
|
|
11350
|
+
{ method: "defaultsDeep", class: "_", type: "mass_assignment", cwe: "CWE-1321", severity: "high", arg_positions: [1, 2, 3], languages: ["javascript", "typescript"] },
|
|
11351
|
+
{ method: "defaultsDeep", class: "lodash", type: "mass_assignment", cwe: "CWE-1321", severity: "high", arg_positions: [1, 2, 3], languages: ["javascript", "typescript"] },
|
|
11352
|
+
{ method: "extend", class: "$", type: "mass_assignment", cwe: "CWE-1321", severity: "high", arg_positions: [1, 2, 3], languages: ["javascript", "typescript"] },
|
|
11353
|
+
{ method: "extend", class: "jQuery", type: "mass_assignment", cwe: "CWE-1321", severity: "high", arg_positions: [1, 2, 3], languages: ["javascript", "typescript"] },
|
|
11354
|
+
{ method: "innerHTML", type: "xss", cwe: "CWE-79", severity: "critical", arg_positions: [0], languages: ["javascript", "typescript"] },
|
|
11355
|
+
{ method: "outerHTML", type: "xss", cwe: "CWE-79", severity: "critical", arg_positions: [0], languages: ["javascript", "typescript"] },
|
|
11356
|
+
{ method: "unserialize", class: "serialize", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0], languages: ["javascript", "typescript"] },
|
|
11357
|
+
{ method: "unserialize", class: "node-serialize", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0], languages: ["javascript", "typescript"] },
|
|
11358
|
+
{ method: "unserialize", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0], languages: ["javascript", "typescript"] }
|
|
11178
11359
|
];
|
|
11179
11360
|
var DEFAULT_SANITIZERS = [
|
|
11180
11361
|
{ method: "setString", class: "PreparedStatement", removes: ["sql_injection"] },
|
|
@@ -11452,7 +11633,8 @@ function findSources(calls, types, patterns, sourceLines, language) {
|
|
|
11452
11633
|
location: formatCallLocation(call),
|
|
11453
11634
|
severity: pattern.severity,
|
|
11454
11635
|
line: call.location.line,
|
|
11455
|
-
confidence: 1
|
|
11636
|
+
confidence: 1,
|
|
11637
|
+
in_method: call.in_method ?? undefined
|
|
11456
11638
|
});
|
|
11457
11639
|
}
|
|
11458
11640
|
}
|
|
@@ -11469,7 +11651,8 @@ function findSources(calls, types, patterns, sourceLines, language) {
|
|
|
11469
11651
|
location: `@${pattern.annotation} ${param.name} in ${method.name}`,
|
|
11470
11652
|
severity: pattern.severity,
|
|
11471
11653
|
line: paramLine,
|
|
11472
|
-
confidence: 1
|
|
11654
|
+
confidence: 1,
|
|
11655
|
+
in_method: method.name
|
|
11473
11656
|
});
|
|
11474
11657
|
}
|
|
11475
11658
|
}
|
|
@@ -11491,7 +11674,8 @@ function findSources(calls, types, patterns, sourceLines, language) {
|
|
|
11491
11674
|
location: `@${pattern.method_annotation} ${param.name} in ${method.name}`,
|
|
11492
11675
|
severity: pattern.severity,
|
|
11493
11676
|
line: paramLine,
|
|
11494
|
-
confidence: 1
|
|
11677
|
+
confidence: 1,
|
|
11678
|
+
in_method: method.name
|
|
11495
11679
|
});
|
|
11496
11680
|
}
|
|
11497
11681
|
}
|
|
@@ -11520,7 +11704,8 @@ function findSources(calls, types, patterns, sourceLines, language) {
|
|
|
11520
11704
|
severity: "high",
|
|
11521
11705
|
line: paramLine,
|
|
11522
11706
|
confidence: 1,
|
|
11523
|
-
variable: param.name
|
|
11707
|
+
variable: param.name,
|
|
11708
|
+
in_method: method.name
|
|
11524
11709
|
});
|
|
11525
11710
|
}
|
|
11526
11711
|
}
|
|
@@ -11541,7 +11726,8 @@ function findSources(calls, types, patterns, sourceLines, language) {
|
|
|
11541
11726
|
location: `${param.type || "any"} ${param.name} in ${method.name}`,
|
|
11542
11727
|
severity: "medium",
|
|
11543
11728
|
line: paramLine,
|
|
11544
|
-
confidence: param.type ? 0.7 : 0.5
|
|
11729
|
+
confidence: param.type ? 0.7 : 0.5,
|
|
11730
|
+
in_method: method.name
|
|
11545
11731
|
});
|
|
11546
11732
|
}
|
|
11547
11733
|
}
|
|
@@ -11561,7 +11747,8 @@ function findSources(calls, types, patterns, sourceLines, language) {
|
|
|
11561
11747
|
location: `${arg.expression} in ${call.in_method || "anonymous"}`,
|
|
11562
11748
|
severity: "high",
|
|
11563
11749
|
line: call.location.line,
|
|
11564
|
-
confidence: 1
|
|
11750
|
+
confidence: 1,
|
|
11751
|
+
in_method: call.in_method ?? undefined
|
|
11565
11752
|
});
|
|
11566
11753
|
}
|
|
11567
11754
|
}
|
|
@@ -11581,7 +11768,8 @@ function findSources(calls, types, patterns, sourceLines, language) {
|
|
|
11581
11768
|
location: `${arg.expression} in ${call.in_method || "anonymous"}`,
|
|
11582
11769
|
severity: "high",
|
|
11583
11770
|
line: call.location.line,
|
|
11584
|
-
confidence: 1
|
|
11771
|
+
confidence: 1,
|
|
11772
|
+
in_method: call.in_method ?? undefined
|
|
11585
11773
|
});
|
|
11586
11774
|
}
|
|
11587
11775
|
break;
|
|
@@ -11614,6 +11802,21 @@ function findSources(calls, types, patterns, sourceLines, language) {
|
|
|
11614
11802
|
s.variable = m[1];
|
|
11615
11803
|
}
|
|
11616
11804
|
}
|
|
11805
|
+
if (language === "java" && sourceLines) {
|
|
11806
|
+
const JAVA_ASSIGN_LHS = /^\s*(?:(?:final|public|private|protected|static|synchronized|volatile|transient)\s+)*(?:[A-Za-z_][\w.]*(?:\s*<[^=]*>)?(?:\s*\[\s*\])*\s+)?([A-Za-z_]\w*)\s*=(?!=)/;
|
|
11807
|
+
for (const s of result) {
|
|
11808
|
+
if (s.variable && s.variable.length > 0)
|
|
11809
|
+
continue;
|
|
11810
|
+
const lineText = sourceLines[s.line - 1] ?? "";
|
|
11811
|
+
const m = JAVA_ASSIGN_LHS.exec(lineText);
|
|
11812
|
+
if (!m)
|
|
11813
|
+
continue;
|
|
11814
|
+
const rhs = lineText.slice(m[0].length).trimStart();
|
|
11815
|
+
if (/^new\b/.test(rhs))
|
|
11816
|
+
continue;
|
|
11817
|
+
s.variable = m[1];
|
|
11818
|
+
}
|
|
11819
|
+
}
|
|
11617
11820
|
return result;
|
|
11618
11821
|
}
|
|
11619
11822
|
function isInterproceduralTaintableType(typeName) {
|
|
@@ -11787,7 +11990,11 @@ function matchesSourcePattern(call, pattern) {
|
|
|
11787
11990
|
}
|
|
11788
11991
|
if (pattern.class && pattern.class !== "constructor") {
|
|
11789
11992
|
if (call.receiver_type && call.receiver_type === pattern.class) {} else if (call.receiver_type_fqn && call.receiver_type_fqn.endsWith("." + pattern.class)) {} else if (!call.receiver) {
|
|
11790
|
-
|
|
11993
|
+
const target = call.resolution?.target;
|
|
11994
|
+
const expectedTail = `${pattern.class}.${pattern.method}`;
|
|
11995
|
+
if (target && (target === expectedTail || target.endsWith("." + expectedTail))) {} else {
|
|
11996
|
+
return false;
|
|
11997
|
+
}
|
|
11791
11998
|
} else if (!receiverMightBeClass(call.receiver, pattern.class)) {
|
|
11792
11999
|
return false;
|
|
11793
12000
|
}
|
|
@@ -12044,7 +12251,11 @@ function matchesSinkPattern(call, pattern, typeHierarchy, language) {
|
|
|
12044
12251
|
}
|
|
12045
12252
|
return false;
|
|
12046
12253
|
} else if (!call.receiver && !call.receiver_type) {
|
|
12047
|
-
|
|
12254
|
+
const target = call.resolution?.target;
|
|
12255
|
+
const expectedTail = `${pattern.class}.${pattern.method}`;
|
|
12256
|
+
if (target && (target === expectedTail || target.endsWith("." + expectedTail))) {} else {
|
|
12257
|
+
return false;
|
|
12258
|
+
}
|
|
12048
12259
|
}
|
|
12049
12260
|
}
|
|
12050
12261
|
if (!pattern.class && call.receiver) {
|
|
@@ -15051,6 +15262,9 @@ class DefaultLanguageRegistry {
|
|
|
15051
15262
|
}
|
|
15052
15263
|
}
|
|
15053
15264
|
get(language) {
|
|
15265
|
+
if (language === "tsx") {
|
|
15266
|
+
return this.plugins.get("javascript");
|
|
15267
|
+
}
|
|
15054
15268
|
return this.plugins.get(language);
|
|
15055
15269
|
}
|
|
15056
15270
|
getForFile(filePath) {
|
|
@@ -17244,6 +17458,20 @@ class BashPlugin extends BaseLanguagePlugin {
|
|
|
17244
17458
|
cwe: "CWE-918",
|
|
17245
17459
|
severity: "high",
|
|
17246
17460
|
argPositions: [0]
|
|
17461
|
+
},
|
|
17462
|
+
{
|
|
17463
|
+
method: "source",
|
|
17464
|
+
type: "path_traversal",
|
|
17465
|
+
cwe: "CWE-98",
|
|
17466
|
+
severity: "critical",
|
|
17467
|
+
argPositions: [0]
|
|
17468
|
+
},
|
|
17469
|
+
{
|
|
17470
|
+
method: ".",
|
|
17471
|
+
type: "path_traversal",
|
|
17472
|
+
cwe: "CWE-98",
|
|
17473
|
+
severity: "critical",
|
|
17474
|
+
argPositions: [0]
|
|
17247
17475
|
}
|
|
17248
17476
|
];
|
|
17249
17477
|
}
|
|
@@ -20337,6 +20565,7 @@ function mergeHtmlResults(htmlMeta, scriptResults, attributeFindings) {
|
|
|
20337
20565
|
const allSources = [];
|
|
20338
20566
|
const allSinks = [];
|
|
20339
20567
|
const allSanitizers = [];
|
|
20568
|
+
const allFlows = [];
|
|
20340
20569
|
const allImports = [];
|
|
20341
20570
|
const allExports = [];
|
|
20342
20571
|
const allFindings = [];
|
|
@@ -20422,6 +20651,14 @@ function mergeHtmlResults(htmlMeta, scriptResults, attributeFindings) {
|
|
|
20422
20651
|
line: sanitizer.line + lineShift
|
|
20423
20652
|
});
|
|
20424
20653
|
}
|
|
20654
|
+
for (const flow of ir.taint.flows ?? []) {
|
|
20655
|
+
allFlows.push({
|
|
20656
|
+
...flow,
|
|
20657
|
+
source_line: flow.source_line + lineShift,
|
|
20658
|
+
sink_line: flow.sink_line + lineShift,
|
|
20659
|
+
path: flow.path.map((step) => ({ ...step, line: step.line + lineShift }))
|
|
20660
|
+
});
|
|
20661
|
+
}
|
|
20425
20662
|
for (const imp of ir.imports) {
|
|
20426
20663
|
allImports.push({
|
|
20427
20664
|
...imp,
|
|
@@ -20441,7 +20678,8 @@ function mergeHtmlResults(htmlMeta, scriptResults, attributeFindings) {
|
|
|
20441
20678
|
const taint = {
|
|
20442
20679
|
sources: allSources,
|
|
20443
20680
|
sinks: allSinks,
|
|
20444
|
-
sanitizers: allSanitizers.length > 0 ? allSanitizers : undefined
|
|
20681
|
+
sanitizers: allSanitizers.length > 0 ? allSanitizers : undefined,
|
|
20682
|
+
flows: allFlows.length > 0 ? allFlows : undefined
|
|
20445
20683
|
};
|
|
20446
20684
|
const cfg = {
|
|
20447
20685
|
blocks: allCfgBlocks,
|
|
@@ -20637,6 +20875,7 @@ class LanguageSourcesPass {
|
|
|
20637
20875
|
const constProp = ctx.getResult("constant-propagation");
|
|
20638
20876
|
const additionalSources = [];
|
|
20639
20877
|
const additionalSinks = [];
|
|
20878
|
+
const additionalSanitizers = [];
|
|
20640
20879
|
additionalSources.push(...findGetterSources(types, constProp.instanceFieldTaint, code));
|
|
20641
20880
|
additionalSources.push(...findOopFieldReadSources(types, code, language));
|
|
20642
20881
|
additionalSources.push(...findJavaScriptAssignmentSources(code, language));
|
|
@@ -20690,9 +20929,10 @@ class LanguageSourcesPass {
|
|
|
20690
20929
|
for (const finding of bashFindings) {
|
|
20691
20930
|
ctx.addFinding(finding);
|
|
20692
20931
|
}
|
|
20932
|
+
additionalSanitizers.push(...findBashRegexAllowlistSanitizers(code));
|
|
20693
20933
|
}
|
|
20694
20934
|
attachSourceLineCode(additionalSources, additionalSinks, code);
|
|
20695
|
-
return { additionalSources, additionalSinks, pyTaintedVars, pySanitizedVars, jsTaintedVars };
|
|
20935
|
+
return { additionalSources, additionalSinks, additionalSanitizers, pyTaintedVars, pySanitizedVars, jsTaintedVars };
|
|
20696
20936
|
}
|
|
20697
20937
|
}
|
|
20698
20938
|
function findGetterSources(types, instanceFieldTaint, _sourceCode) {
|
|
@@ -20943,62 +21183,62 @@ function buildPythonTaintedVars(sourceCode) {
|
|
|
20943
21183
|
const line = lines[i2];
|
|
20944
21184
|
if (line.trimStart().startsWith("#"))
|
|
20945
21185
|
continue;
|
|
20946
|
-
const subscriptAssign = line.match(/^\s*(\
|
|
21186
|
+
const subscriptAssign = line.match(/^\s*([\p{L}\p{N}_]+)\[(['"])([^'"]+)\2\]\s*=\s*(.+)$/u);
|
|
20947
21187
|
if (subscriptAssign) {
|
|
20948
21188
|
const [, container, , key, rhs2] = subscriptAssign;
|
|
20949
|
-
const isTaintedRhs = [...tainted.keys()].some((v) => new RegExp(
|
|
21189
|
+
const isTaintedRhs = [...tainted.keys()].some((v) => new RegExp(`(?<![\\p{L}\\p{N}_])${v}(?![\\p{L}\\p{N}_])`, "u").test(rhs2));
|
|
20950
21190
|
if (isTaintedRhs)
|
|
20951
21191
|
containerTainted.set(`${container}['${key}']`, i2 + 1);
|
|
20952
21192
|
continue;
|
|
20953
21193
|
}
|
|
20954
|
-
const setCallMatch = line.match(/^\s*(\
|
|
21194
|
+
const setCallMatch = line.match(/^\s*([\p{L}\p{N}_]+)\.set\s*\(\s*(['"])([^'"]+)\2\s*,\s*(['"])([^'"]+)\4\s*,\s*(.+?)\s*\)$/u);
|
|
20955
21195
|
if (setCallMatch) {
|
|
20956
21196
|
const [, obj, , section, , key, rhs2] = setCallMatch;
|
|
20957
|
-
const isTaintedRhs = [...tainted.keys()].some((v) => new RegExp(
|
|
21197
|
+
const isTaintedRhs = [...tainted.keys()].some((v) => new RegExp(`(?<![\\p{L}\\p{N}_])${v}(?![\\p{L}\\p{N}_])`, "u").test(rhs2));
|
|
20958
21198
|
if (isTaintedRhs)
|
|
20959
21199
|
containerTainted.set(`${obj}['${section}']['${key}']`, i2 + 1);
|
|
20960
21200
|
continue;
|
|
20961
21201
|
}
|
|
20962
|
-
const containerAppendMatch = line.match(/^\s*(\
|
|
21202
|
+
const containerAppendMatch = line.match(/^\s*([\p{L}\p{N}_]+)\.(append|extend|insert|add|push|put|appendleft)\s*\(\s*(.+?)\s*\)\s*$/u);
|
|
20963
21203
|
if (containerAppendMatch) {
|
|
20964
21204
|
const [, receiver, , argExpr] = containerAppendMatch;
|
|
20965
|
-
const argIsTainted = [...tainted.keys()].some((v) => new RegExp(
|
|
21205
|
+
const argIsTainted = [...tainted.keys()].some((v) => new RegExp(`(?<![\\p{L}\\p{N}_])${v}(?![\\p{L}\\p{N}_])`, "u").test(argExpr));
|
|
20966
21206
|
const argIsDirectSource = PYTHON_TAINTED_PATTERNS2.some((p) => p.pattern.test(argExpr));
|
|
20967
21207
|
if (argIsTainted || argIsDirectSource)
|
|
20968
21208
|
tainted.set(receiver, tainted.get(receiver) ?? i2 + 1);
|
|
20969
21209
|
continue;
|
|
20970
21210
|
}
|
|
20971
|
-
const augAssign = line.match(/^\s*(\
|
|
21211
|
+
const augAssign = line.match(/^\s*([\p{L}\p{N}_]+)\s*\+=\s*(.+)$/u);
|
|
20972
21212
|
if (augAssign) {
|
|
20973
21213
|
const [, augLhs, augRhs] = augAssign;
|
|
20974
|
-
const rhsTainted = [...tainted.keys()].some((v) => new RegExp(
|
|
21214
|
+
const rhsTainted = [...tainted.keys()].some((v) => new RegExp(`(?<![\\p{L}\\p{N}_])${v}(?![\\p{L}\\p{N}_])`, "u").test(augRhs));
|
|
20975
21215
|
if (rhsTainted || tainted.has(augLhs))
|
|
20976
21216
|
tainted.set(augLhs, tainted.get(augLhs) ?? i2 + 1);
|
|
20977
21217
|
continue;
|
|
20978
21218
|
}
|
|
20979
|
-
const forLoopMatch = line.match(/^\s*for\s+(\
|
|
21219
|
+
const forLoopMatch = line.match(/^\s*for\s+([\p{L}\p{N}_]+)\s+in\s+(.+?)(?:\s*:\s*)?$/u);
|
|
20980
21220
|
if (forLoopMatch) {
|
|
20981
21221
|
const [, iterVar, iterExpr] = forLoopMatch;
|
|
20982
21222
|
const isDirectSource2 = PYTHON_TAINTED_PATTERNS2.some((p) => p.pattern.test(iterExpr));
|
|
20983
|
-
const isPropagated = [...tainted.keys()].some((v) => new RegExp(
|
|
21223
|
+
const isPropagated = [...tainted.keys()].some((v) => new RegExp(`(?<![\\p{L}\\p{N}_])${v}(?![\\p{L}\\p{N}_])`, "u").test(iterExpr));
|
|
20984
21224
|
if (isDirectSource2 || isPropagated)
|
|
20985
21225
|
tainted.set(iterVar, i2 + 1);
|
|
20986
21226
|
continue;
|
|
20987
21227
|
}
|
|
20988
|
-
const assignMatch = line.match(/^\s*(\
|
|
21228
|
+
const assignMatch = line.match(/^\s*([\p{L}\p{N}_]+)\s*=\s*(.+)$/u);
|
|
20989
21229
|
if (!assignMatch)
|
|
20990
21230
|
continue;
|
|
20991
21231
|
const [, lhs, rhs] = assignMatch;
|
|
20992
21232
|
const isDirectSource = PYTHON_TAINTED_PATTERNS2.some((p) => p.pattern.test(rhs));
|
|
20993
21233
|
let propagatedFrom;
|
|
20994
|
-
const dictAccessMatch = rhs.trim().match(/^(\
|
|
21234
|
+
const dictAccessMatch = rhs.trim().match(/^([\p{L}\p{N}_]+)\[(['"])([^'"]+)\2\]$/u);
|
|
20995
21235
|
if (dictAccessMatch) {
|
|
20996
21236
|
const [, container, , key] = dictAccessMatch;
|
|
20997
21237
|
if (containerTainted.has(`${container}['${key}']`))
|
|
20998
21238
|
propagatedFrom = `${container}['${key}']`;
|
|
20999
21239
|
}
|
|
21000
21240
|
if (!propagatedFrom) {
|
|
21001
|
-
const confGetMatch = rhs.trim().match(/^(\
|
|
21241
|
+
const confGetMatch = rhs.trim().match(/^([\p{L}\p{N}_]+)\.get\s*\(\s*(['"])([^'"]+)\2\s*,\s*(['"])([^'"]+)\4\s*\)$/u);
|
|
21002
21242
|
if (confGetMatch) {
|
|
21003
21243
|
const [, obj, , section, , key] = confGetMatch;
|
|
21004
21244
|
if (containerTainted.has(`${obj}['${section}']['${key}']`))
|
|
@@ -21008,7 +21248,7 @@ function buildPythonTaintedVars(sourceCode) {
|
|
|
21008
21248
|
if (!propagatedFrom) {
|
|
21009
21249
|
const isSafeEnvRead = /\bos\.environ\.get\s*\(/.test(rhs) || /\bos\.getenv\s*\(/.test(rhs);
|
|
21010
21250
|
if (!isSafeEnvRead)
|
|
21011
|
-
propagatedFrom = [...tainted.keys()].find((v) => new RegExp(
|
|
21251
|
+
propagatedFrom = [...tainted.keys()].find((v) => new RegExp(`(?<![\\p{L}\\p{N}_])${v}(?![\\p{L}\\p{N}_])`, "u").test(rhs));
|
|
21012
21252
|
}
|
|
21013
21253
|
if (isDirectSource) {
|
|
21014
21254
|
tainted.set(lhs, i2 + 1);
|
|
@@ -21413,6 +21653,61 @@ function findBashPatternFindings(sourceCode, file) {
|
|
|
21413
21653
|
}
|
|
21414
21654
|
return findings;
|
|
21415
21655
|
}
|
|
21656
|
+
function findBashRegexAllowlistSanitizers(code) {
|
|
21657
|
+
const sanitizers = [];
|
|
21658
|
+
const lines = code.split(`
|
|
21659
|
+
`);
|
|
21660
|
+
const guardRe = /^\s*if\s+\[\[\s*!\s*"?\$\{?(\w+)\}?"?\s*=~\s*(\S+)\s*\]\]\s*;\s*then\s+(exit|return|die)\b/;
|
|
21661
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
21662
|
+
const m = guardRe.exec(lines[i2]);
|
|
21663
|
+
if (!m)
|
|
21664
|
+
continue;
|
|
21665
|
+
const regexLiteral = m[2];
|
|
21666
|
+
if (!isSafeBashAllowlistRegex(regexLiteral))
|
|
21667
|
+
continue;
|
|
21668
|
+
const ifLine1Indexed = i2 + 1;
|
|
21669
|
+
for (let l = ifLine1Indexed + 1;l <= lines.length; l++) {
|
|
21670
|
+
sanitizers.push({
|
|
21671
|
+
type: "regex_allowlist",
|
|
21672
|
+
method: "=~",
|
|
21673
|
+
line: l,
|
|
21674
|
+
sanitizes: [
|
|
21675
|
+
"command_injection",
|
|
21676
|
+
"path_traversal",
|
|
21677
|
+
"sql_injection",
|
|
21678
|
+
"code_injection",
|
|
21679
|
+
"ssrf",
|
|
21680
|
+
"xss",
|
|
21681
|
+
"open_redirect",
|
|
21682
|
+
"log_injection"
|
|
21683
|
+
]
|
|
21684
|
+
});
|
|
21685
|
+
}
|
|
21686
|
+
}
|
|
21687
|
+
return sanitizers;
|
|
21688
|
+
}
|
|
21689
|
+
function isSafeBashAllowlistRegex(literal) {
|
|
21690
|
+
if (!literal.startsWith("^") || !literal.endsWith("$"))
|
|
21691
|
+
return false;
|
|
21692
|
+
const body2 = literal.slice(1, -1);
|
|
21693
|
+
if (body2.length === 0)
|
|
21694
|
+
return false;
|
|
21695
|
+
if (body2.includes(".*") || body2.includes(".+"))
|
|
21696
|
+
return false;
|
|
21697
|
+
if (body2.includes("|"))
|
|
21698
|
+
return false;
|
|
21699
|
+
if (/\\\d/.test(body2))
|
|
21700
|
+
return false;
|
|
21701
|
+
const safeToken = /\[[^\]]+\][+*?]?|\\.|[A-Za-z0-9_\-./]|[+*?]/g;
|
|
21702
|
+
let consumed = 0;
|
|
21703
|
+
let match;
|
|
21704
|
+
while ((match = safeToken.exec(body2)) !== null) {
|
|
21705
|
+
if (match.index !== consumed)
|
|
21706
|
+
return false;
|
|
21707
|
+
consumed += match[0].length;
|
|
21708
|
+
}
|
|
21709
|
+
return consumed === body2.length;
|
|
21710
|
+
}
|
|
21416
21711
|
|
|
21417
21712
|
// ../circle-ir/dist/analysis/passes/sink-filter-pass.js
|
|
21418
21713
|
var JS_XSS_SANITIZERS = [
|
|
@@ -21449,7 +21744,10 @@ class SinkFilterPass {
|
|
|
21449
21744
|
sinks.push(s);
|
|
21450
21745
|
}
|
|
21451
21746
|
}
|
|
21452
|
-
const sanitizers =
|
|
21747
|
+
const sanitizers = [
|
|
21748
|
+
...taintMatcher.sanitizers,
|
|
21749
|
+
...langSources.additionalSanitizers ?? []
|
|
21750
|
+
];
|
|
21453
21751
|
let filtered = sinks.filter((sink) => !constProp.unreachableLines.has(sink.line));
|
|
21454
21752
|
filtered = filterCleanArraySinks(filtered, calls, constProp.taintedArrayElements, constProp.symbols);
|
|
21455
21753
|
filtered = filterCleanVariableSinks(filtered, calls, constProp.tainted, constProp.symbols, dfg, constProp.sanitizedVars, constProp.synchronizedLines, language);
|
|
@@ -21924,6 +22222,8 @@ function findInitialTaint(sources, callsByLine, defsByLine) {
|
|
|
21924
22222
|
for (const def of defsNextLine) {
|
|
21925
22223
|
const callsOnSourceLine = callsByLine.get(source.line) ?? [];
|
|
21926
22224
|
if (callsOnSourceLine.length > 0) {
|
|
22225
|
+
if (source.variable && def.variable !== source.variable)
|
|
22226
|
+
continue;
|
|
21927
22227
|
tainted.push({
|
|
21928
22228
|
variable: def.variable,
|
|
21929
22229
|
defId: def.id,
|
|
@@ -21934,6 +22234,21 @@ function findInitialTaint(sources, callsByLine, defsByLine) {
|
|
|
21934
22234
|
});
|
|
21935
22235
|
}
|
|
21936
22236
|
}
|
|
22237
|
+
if (source.variable) {
|
|
22238
|
+
const paramDefs = defsByLine.get(0) ?? [];
|
|
22239
|
+
for (const def of paramDefs) {
|
|
22240
|
+
if (def.kind === "param" && def.variable === source.variable) {
|
|
22241
|
+
tainted.push({
|
|
22242
|
+
variable: def.variable,
|
|
22243
|
+
defId: def.id,
|
|
22244
|
+
line: def.line,
|
|
22245
|
+
sourceType: source.type,
|
|
22246
|
+
sourceLine: source.line,
|
|
22247
|
+
confidence: source.confidence
|
|
22248
|
+
});
|
|
22249
|
+
}
|
|
22250
|
+
}
|
|
22251
|
+
}
|
|
21937
22252
|
}
|
|
21938
22253
|
return tainted;
|
|
21939
22254
|
}
|
|
@@ -22111,13 +22426,13 @@ class TaintPropagationPass {
|
|
|
22111
22426
|
confidence: flow.confidence,
|
|
22112
22427
|
sanitized: flow.sanitized
|
|
22113
22428
|
}));
|
|
22114
|
-
const arrayFlows = detectArrayElementFlows(calls, sources, sinks, constProp.taintedArrayElements, constProp.unreachableLines) ?? [];
|
|
22429
|
+
const arrayFlows = detectArrayElementFlows(calls, sources, sinks, constProp.taintedArrayElements, constProp.unreachableLines, types) ?? [];
|
|
22115
22430
|
for (const f of arrayFlows) {
|
|
22116
22431
|
if (!flows.some((x) => x.source_line === f.source_line && x.sink_line === f.sink_line)) {
|
|
22117
22432
|
flows.push(f);
|
|
22118
22433
|
}
|
|
22119
22434
|
}
|
|
22120
|
-
const collectionFlows = detectCollectionFlows(calls, sources, sinks, constProp.tainted, constProp.unreachableLines, ctx.code) ?? [];
|
|
22435
|
+
const collectionFlows = detectCollectionFlows(calls, sources, sinks, constProp.tainted, constProp.unreachableLines, ctx.code, types) ?? [];
|
|
22121
22436
|
for (const f of collectionFlows) {
|
|
22122
22437
|
if (flows.some((x) => x.source_line === f.source_line && x.sink_line === f.sink_line))
|
|
22123
22438
|
continue;
|
|
@@ -22168,7 +22483,7 @@ class TaintPropagationPass {
|
|
|
22168
22483
|
flows.push(f);
|
|
22169
22484
|
}
|
|
22170
22485
|
const sanitizedNames = constProp.sanitizedVars;
|
|
22171
|
-
|
|
22486
|
+
let finalFlows = sanitizedNames.size === 0 ? flows : flows.filter((f) => {
|
|
22172
22487
|
if (f.path.length === 0)
|
|
22173
22488
|
return true;
|
|
22174
22489
|
const sourceVar = f.path[0].variable;
|
|
@@ -22182,10 +22497,60 @@ class TaintPropagationPass {
|
|
|
22182
22497
|
}
|
|
22183
22498
|
return true;
|
|
22184
22499
|
});
|
|
22500
|
+
if (ctx.language === "java" && typeof ctx.code === "string") {
|
|
22501
|
+
finalFlows = finalFlows.filter((f) => {
|
|
22502
|
+
if (f.sink_type !== "path_traversal" && f.sink_type !== "xxe")
|
|
22503
|
+
return true;
|
|
22504
|
+
if (!isInJavaSanitizedMethod(ctx.code, types, f.sink_line, f.sink_type))
|
|
22505
|
+
return true;
|
|
22506
|
+
return false;
|
|
22507
|
+
});
|
|
22508
|
+
}
|
|
22185
22509
|
return { flows: finalFlows };
|
|
22186
22510
|
}
|
|
22187
22511
|
}
|
|
22188
|
-
function
|
|
22512
|
+
function isInJavaSanitizedMethod(code, types, sinkLine, sinkType) {
|
|
22513
|
+
if (!types || types.length === 0)
|
|
22514
|
+
return false;
|
|
22515
|
+
let methodStart = -1;
|
|
22516
|
+
let methodEnd = -1;
|
|
22517
|
+
for (const t of types) {
|
|
22518
|
+
for (const m of t.methods) {
|
|
22519
|
+
if (sinkLine >= m.start_line && sinkLine <= m.end_line) {
|
|
22520
|
+
methodStart = m.start_line;
|
|
22521
|
+
methodEnd = m.end_line;
|
|
22522
|
+
break;
|
|
22523
|
+
}
|
|
22524
|
+
}
|
|
22525
|
+
if (methodStart > 0)
|
|
22526
|
+
break;
|
|
22527
|
+
}
|
|
22528
|
+
if (methodStart < 0)
|
|
22529
|
+
return false;
|
|
22530
|
+
const lines = code.split(`
|
|
22531
|
+
`);
|
|
22532
|
+
const body2 = lines.slice(methodStart - 1, methodEnd).join(`
|
|
22533
|
+
`);
|
|
22534
|
+
if (sinkType === "path_traversal") {
|
|
22535
|
+
if (!/\.getCanonicalPath\s*\(/.test(body2))
|
|
22536
|
+
return false;
|
|
22537
|
+
if (!/\.startsWith\s*\([^)]*getCanonicalPath/.test(body2))
|
|
22538
|
+
return false;
|
|
22539
|
+
if (!/\bthrow\s+new\b/.test(body2))
|
|
22540
|
+
return false;
|
|
22541
|
+
return true;
|
|
22542
|
+
}
|
|
22543
|
+
if (sinkType === "xxe") {
|
|
22544
|
+
const setFeatureRe = /\.setFeature\s*\(\s*"(?:[^"]*disallow-doctype-decl|[^"]*external-general-entities|[^"]*external-parameter-entities|[^"]*load-external-dtd)"/;
|
|
22545
|
+
if (setFeatureRe.test(body2))
|
|
22546
|
+
return true;
|
|
22547
|
+
if (/\.setProperty\s*\([^,]*SUPPORT_DTD[^,]*,\s*false\s*\)/.test(body2))
|
|
22548
|
+
return true;
|
|
22549
|
+
return false;
|
|
22550
|
+
}
|
|
22551
|
+
return false;
|
|
22552
|
+
}
|
|
22553
|
+
function detectCollectionFlows(calls, sources, sinks, taintedVars, unreachableLines, code, types) {
|
|
22189
22554
|
const flows = [];
|
|
22190
22555
|
const callsByLine = new Map;
|
|
22191
22556
|
for (const call of calls) {
|
|
@@ -22206,8 +22571,11 @@ function detectCollectionFlows(calls, sources, sinks, taintedVars, unreachableLi
|
|
|
22206
22571
|
const varName = arg.variable;
|
|
22207
22572
|
const scopedName = call.in_method ? `${call.in_method}:${varName}` : varName;
|
|
22208
22573
|
if (taintedVars.has(varName) || taintedVars.has(scopedName)) {
|
|
22209
|
-
const source = sources
|
|
22574
|
+
const source = pickScopedSource(sources, sink.line, call.in_method ?? null, types, varName);
|
|
22210
22575
|
if (source) {
|
|
22576
|
+
if (source.variable && source.variable !== varName && source.in_method && call.in_method && source.in_method !== call.in_method) {
|
|
22577
|
+
continue;
|
|
22578
|
+
}
|
|
22211
22579
|
if (typeof code === "string" && isReassignedToLiteralBetween(code, varName, source.line, sink.line)) {
|
|
22212
22580
|
continue;
|
|
22213
22581
|
}
|
|
@@ -22243,8 +22611,11 @@ function detectCollectionFlows(calls, sources, sinks, taintedVars, unreachableLi
|
|
|
22243
22611
|
const collectionVar = match[1];
|
|
22244
22612
|
const scopedCollection = call.in_method ? `${call.in_method}:${collectionVar}` : collectionVar;
|
|
22245
22613
|
if (taintedVars.has(collectionVar) || taintedVars.has(scopedCollection)) {
|
|
22246
|
-
const source = sources
|
|
22614
|
+
const source = pickScopedSource(sources, sink.line, call.in_method ?? null, types, collectionVar);
|
|
22247
22615
|
if (source) {
|
|
22616
|
+
if (source.variable && source.variable !== collectionVar && source.in_method && call.in_method && source.in_method !== call.in_method) {
|
|
22617
|
+
continue;
|
|
22618
|
+
}
|
|
22248
22619
|
if (typeof code === "string" && isReassignedToLiteralBetween(code, collectionVar, source.line, sink.line)) {
|
|
22249
22620
|
continue;
|
|
22250
22621
|
}
|
|
@@ -22270,7 +22641,7 @@ function detectCollectionFlows(calls, sources, sinks, taintedVars, unreachableLi
|
|
|
22270
22641
|
}
|
|
22271
22642
|
return flows;
|
|
22272
22643
|
}
|
|
22273
|
-
function detectArrayElementFlows(calls, sources, sinks, taintedArrayElements, unreachableLines) {
|
|
22644
|
+
function detectArrayElementFlows(calls, sources, sinks, taintedArrayElements, unreachableLines, types) {
|
|
22274
22645
|
const flows = [];
|
|
22275
22646
|
const callsByLine = new Map;
|
|
22276
22647
|
for (const call of calls) {
|
|
@@ -22295,7 +22666,7 @@ function detectArrayElementFlows(calls, sources, sinks, taintedArrayElements, un
|
|
|
22295
22666
|
if (taintedIndices) {
|
|
22296
22667
|
const isTainted = taintedIndices.has(indexStr) || taintedIndices.has("*");
|
|
22297
22668
|
if (isTainted) {
|
|
22298
|
-
const source = sources
|
|
22669
|
+
const source = pickScopedSource(sources, sink.line, call.in_method ?? null, types, arrayName);
|
|
22299
22670
|
if (source) {
|
|
22300
22671
|
flows.push({
|
|
22301
22672
|
source_line: source.line,
|
|
@@ -22399,11 +22770,12 @@ function isReassignedToLiteralBetween(code, variable, srcLine, sinkLine) {
|
|
|
22399
22770
|
const strLit = `(?:"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"|'[^'\\\\]*(?:\\\\.[^'\\\\]*)*'|\`[^\`\\\\]*(?:\\\\.[^\`\\\\]*)*\`)`;
|
|
22400
22771
|
const reNaked = new RegExp(`^\\s*${variable}\\s*(?::?=)\\s*${strLit}\\s*;?\\s*$`);
|
|
22401
22772
|
const reGuarded = new RegExp(`^\\s*if\\b.*\\b${variable}\\s*=\\s*${strLit}\\s*;?\\s*$`);
|
|
22773
|
+
const reSwitchCase = new RegExp(`^\\s*(?:case\\b.*?|default\\s*):\\s*${variable}\\s*=\\s*${strLit}\\s*;?\\s*(?:break\\s*;?)?\\s*$`);
|
|
22402
22774
|
for (let i2 = lo;i2 < hi; i2++) {
|
|
22403
22775
|
const line = lines[i2];
|
|
22404
22776
|
if (!line)
|
|
22405
22777
|
continue;
|
|
22406
|
-
if (reNaked.test(line) || reGuarded.test(line))
|
|
22778
|
+
if (reNaked.test(line) || reGuarded.test(line) || reSwitchCase.test(line))
|
|
22407
22779
|
return true;
|
|
22408
22780
|
}
|
|
22409
22781
|
return false;
|
|
@@ -22507,7 +22879,7 @@ function detectExpressionScanFlows(calls, sources, sinks, sanitizers, unreachabl
|
|
|
22507
22879
|
if (reCache.has(s.variable))
|
|
22508
22880
|
continue;
|
|
22509
22881
|
const escaped = s.variable.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
22510
|
-
reCache.set(s.variable, new RegExp(
|
|
22882
|
+
reCache.set(s.variable, new RegExp(`(?<![\\p{L}\\p{N}_])${escaped}(?![\\p{L}\\p{N}_])`, "u"));
|
|
22511
22883
|
}
|
|
22512
22884
|
const callsByLine = new Map;
|
|
22513
22885
|
for (const call of calls) {
|
|
@@ -22530,6 +22902,9 @@ function detectExpressionScanFlows(calls, sources, sinks, sanitizers, unreachabl
|
|
|
22530
22902
|
for (const source of sourcesWithVar) {
|
|
22531
22903
|
if (source.line >= sink.line)
|
|
22532
22904
|
continue;
|
|
22905
|
+
if (source.in_method && call.in_method && source.in_method !== call.in_method) {
|
|
22906
|
+
continue;
|
|
22907
|
+
}
|
|
22533
22908
|
const re = reCache.get(source.variable);
|
|
22534
22909
|
if (!re || !re.test(expr))
|
|
22535
22910
|
continue;
|
|
@@ -22596,6 +22971,51 @@ function detectExpressionScanFlows(calls, sources, sinks, sanitizers, unreachabl
|
|
|
22596
22971
|
}
|
|
22597
22972
|
return flows;
|
|
22598
22973
|
}
|
|
22974
|
+
function pickScopedSource(sources, sinkLine, methodName, types, taintedVar) {
|
|
22975
|
+
if (sources.length === 0)
|
|
22976
|
+
return;
|
|
22977
|
+
const closestPreceding = (cands) => {
|
|
22978
|
+
let best;
|
|
22979
|
+
for (const s of cands) {
|
|
22980
|
+
if (s.line >= sinkLine)
|
|
22981
|
+
continue;
|
|
22982
|
+
if (!best || s.line > best.line)
|
|
22983
|
+
best = s;
|
|
22984
|
+
}
|
|
22985
|
+
return best;
|
|
22986
|
+
};
|
|
22987
|
+
if (taintedVar) {
|
|
22988
|
+
const byVar = sources.filter((s) => s.variable === taintedVar);
|
|
22989
|
+
const pick = closestPreceding(byVar);
|
|
22990
|
+
if (pick)
|
|
22991
|
+
return pick;
|
|
22992
|
+
}
|
|
22993
|
+
if (methodName && types && types.length > 0) {
|
|
22994
|
+
let methodStart = -1;
|
|
22995
|
+
let methodEnd = -1;
|
|
22996
|
+
for (const t of types) {
|
|
22997
|
+
for (const m of t.methods) {
|
|
22998
|
+
if (m.name === methodName) {
|
|
22999
|
+
methodStart = m.start_line;
|
|
23000
|
+
methodEnd = m.end_line;
|
|
23001
|
+
break;
|
|
23002
|
+
}
|
|
23003
|
+
}
|
|
23004
|
+
if (methodStart > 0)
|
|
23005
|
+
break;
|
|
23006
|
+
}
|
|
23007
|
+
if (methodStart > 0 && methodEnd >= methodStart) {
|
|
23008
|
+
const inScope = sources.filter((s) => s.line >= methodStart && s.line <= methodEnd);
|
|
23009
|
+
const pick = closestPreceding(inScope);
|
|
23010
|
+
if (pick)
|
|
23011
|
+
return pick;
|
|
23012
|
+
}
|
|
23013
|
+
}
|
|
23014
|
+
const globalPick = closestPreceding(sources);
|
|
23015
|
+
if (globalPick)
|
|
23016
|
+
return globalPick;
|
|
23017
|
+
return sources[0];
|
|
23018
|
+
}
|
|
22599
23019
|
|
|
22600
23020
|
// ../circle-ir/dist/analysis/interprocedural.js
|
|
22601
23021
|
function analyzeInterprocedural2(graphOrTypes, callsOrSources, dfgOrSinks, sourcesOrSanitizers, sinksOrOptions, sanitizersArg, optionsArg = {}) {
|
|
@@ -22649,6 +23069,13 @@ function analyzeInterprocedural2(graphOrTypes, callsOrSources, dfgOrSinks, sourc
|
|
|
22649
23069
|
for (const def of graph.defsAtLine(source.line)) {
|
|
22650
23070
|
seedIds.add(def.id);
|
|
22651
23071
|
}
|
|
23072
|
+
if (source.variable) {
|
|
23073
|
+
for (const def of graph.defsAtLine(0)) {
|
|
23074
|
+
if (def.kind === "param" && def.variable === source.variable) {
|
|
23075
|
+
seedIds.add(def.id);
|
|
23076
|
+
}
|
|
23077
|
+
}
|
|
23078
|
+
}
|
|
22652
23079
|
}
|
|
22653
23080
|
const taintedDefIds = graph.propagateTaintedDefIds(seedIds);
|
|
22654
23081
|
const taintedVarsFromCP = options.taintedVariables ?? new Set;
|
|
@@ -22789,7 +23216,34 @@ function analyzeInterprocedural2(graphOrTypes, callsOrSources, dfgOrSinks, sourc
|
|
|
22789
23216
|
const targetMethod = getMethodNode(methodNodes, call.method_name);
|
|
22790
23217
|
if (!targetMethod) {
|
|
22791
23218
|
if (taintedArgPositions.length > 0 && !collectionMethods.has(call.method_name) && !sanitizerMethods.has(call.method_name) && !safeUtilityMethods.has(call.method_name)) {
|
|
22792
|
-
const
|
|
23219
|
+
const isBash = graph.ir.meta.language === "bash";
|
|
23220
|
+
const bashSafeBuiltins = new Set([
|
|
23221
|
+
"echo",
|
|
23222
|
+
"printf",
|
|
23223
|
+
"test",
|
|
23224
|
+
"[",
|
|
23225
|
+
"[[",
|
|
23226
|
+
"true",
|
|
23227
|
+
"false",
|
|
23228
|
+
":",
|
|
23229
|
+
"declare",
|
|
23230
|
+
"local",
|
|
23231
|
+
"export",
|
|
23232
|
+
"readonly",
|
|
23233
|
+
"typeset"
|
|
23234
|
+
]);
|
|
23235
|
+
if (isBash && bashSafeBuiltins.has(call.method_name)) {
|
|
23236
|
+
continue;
|
|
23237
|
+
}
|
|
23238
|
+
const sink = isBash ? {
|
|
23239
|
+
type: "command_injection",
|
|
23240
|
+
cwe: "CWE-78",
|
|
23241
|
+
location: `Tainted data (${taintedArgVars.join(", ")}) passed unquoted to shell utility ${call.method_name}`,
|
|
23242
|
+
line: call.location.line,
|
|
23243
|
+
confidence: 0.6,
|
|
23244
|
+
method: call.method_name,
|
|
23245
|
+
argPositions: taintedArgPositions
|
|
23246
|
+
} : {
|
|
22793
23247
|
type: "external_taint_escape",
|
|
22794
23248
|
cwe: "CWE-668",
|
|
22795
23249
|
location: `Tainted data (${taintedArgVars.join(", ")}) passed to external method ${call.receiver ? call.receiver + "." : ""}${call.method_name}()`,
|
|
@@ -23469,6 +23923,7 @@ function isPublicMethod(method, language) {
|
|
|
23469
23923
|
return method.modifiers.includes("public");
|
|
23470
23924
|
case "javascript":
|
|
23471
23925
|
case "typescript":
|
|
23926
|
+
case "tsx":
|
|
23472
23927
|
return !method.modifiers.includes("private") && !method.modifiers.includes("protected");
|
|
23473
23928
|
case "python":
|
|
23474
23929
|
return !method.name.startsWith("_");
|
|
@@ -23488,7 +23943,7 @@ class MissingPublicDocPass {
|
|
|
23488
23943
|
if (UTIL_DIR_RE.test(graph.ir.meta.file)) {
|
|
23489
23944
|
return { missingDocMethods: [], missingDocTypes: [] };
|
|
23490
23945
|
}
|
|
23491
|
-
if (!["java", "javascript", "typescript", "python"].includes(language)) {
|
|
23946
|
+
if (!["java", "javascript", "typescript", "tsx", "python"].includes(language)) {
|
|
23492
23947
|
return { missingDocMethods: [], missingDocTypes: [] };
|
|
23493
23948
|
}
|
|
23494
23949
|
const lines = code.split(`
|
|
@@ -24012,6 +24467,7 @@ function hasDeclKeyword(lineText, language) {
|
|
|
24012
24467
|
return /\b(?:int|long|float|double|boolean|byte|char|short|var|final)\b/.test(lineText) || /\b[A-Z]\w*(?:<[^>]*>)?\s+\w/.test(lineText);
|
|
24013
24468
|
case "javascript":
|
|
24014
24469
|
case "typescript":
|
|
24470
|
+
case "tsx":
|
|
24015
24471
|
return /\b(?:let|const|var)\s+[\w{[]/.test(lineText);
|
|
24016
24472
|
case "rust":
|
|
24017
24473
|
return /\blet\s+(?:mut\s+)?\w/.test(lineText);
|
|
@@ -28518,6 +28974,7 @@ class WeakRandomPass {
|
|
|
28518
28974
|
return "Use the `secrets` module (`secrets.token_bytes`, " + "`secrets.token_hex`, `secrets.choice`, `secrets.randbelow`).";
|
|
28519
28975
|
case "javascript":
|
|
28520
28976
|
case "typescript":
|
|
28977
|
+
case "tsx":
|
|
28521
28978
|
return "Use `crypto.randomBytes(n)` (Node.js) or " + "`crypto.getRandomValues(typedArray)` (browser).";
|
|
28522
28979
|
case "go":
|
|
28523
28980
|
return "Use `crypto/rand` instead of `math/rand`. Example: " + "`b := make([]byte, 32); _, _ = rand.Read(b)` (where `rand` is `crypto/rand`).";
|
|
@@ -28556,7 +29013,7 @@ class WeakRandomPass {
|
|
|
28556
29013
|
}
|
|
28557
29014
|
return null;
|
|
28558
29015
|
}
|
|
28559
|
-
if (language === "javascript" || language === "typescript") {
|
|
29016
|
+
if (language === "javascript" || language === "typescript" || language === "tsx") {
|
|
28560
29017
|
if (method === "random" && (receiver === "Math" || receiver.endsWith(".Math"))) {
|
|
28561
29018
|
return "Math.random";
|
|
28562
29019
|
}
|
|
@@ -30158,6 +30615,7 @@ function getNodeTypesForLanguage(language) {
|
|
|
30158
30615
|
]);
|
|
30159
30616
|
case "javascript":
|
|
30160
30617
|
case "typescript":
|
|
30618
|
+
case "tsx":
|
|
30161
30619
|
return new Set([
|
|
30162
30620
|
"call_expression",
|
|
30163
30621
|
"new_expression",
|
|
@@ -30170,7 +30628,12 @@ function getNodeTypesForLanguage(language) {
|
|
|
30170
30628
|
"import_statement",
|
|
30171
30629
|
"export_statement",
|
|
30172
30630
|
"member_expression",
|
|
30173
|
-
"assignment_expression"
|
|
30631
|
+
"assignment_expression",
|
|
30632
|
+
"jsx_element",
|
|
30633
|
+
"jsx_self_closing_element",
|
|
30634
|
+
"jsx_opening_element",
|
|
30635
|
+
"jsx_attribute",
|
|
30636
|
+
"jsx_expression"
|
|
30174
30637
|
]);
|
|
30175
30638
|
case "bash":
|
|
30176
30639
|
return new Set([
|
|
@@ -30234,8 +30697,15 @@ async function analyze(code, filePath, language, options = {}) {
|
|
|
30234
30697
|
if (language === "html") {
|
|
30235
30698
|
return analyzeHtmlFile(code, filePath, options);
|
|
30236
30699
|
}
|
|
30237
|
-
|
|
30238
|
-
|
|
30700
|
+
let parseGrammar = language;
|
|
30701
|
+
if (language === "javascript" || language === "typescript") {
|
|
30702
|
+
const lower = filePath.toLowerCase();
|
|
30703
|
+
if (lower.endsWith(".tsx") || lower.endsWith(".jsx")) {
|
|
30704
|
+
parseGrammar = "tsx";
|
|
30705
|
+
}
|
|
30706
|
+
}
|
|
30707
|
+
logger.debug("Analyzing file", { filePath, language, parseGrammar, codeLength: code.length });
|
|
30708
|
+
const tree = await parse(code, parseGrammar);
|
|
30239
30709
|
try {
|
|
30240
30710
|
logger.trace("Parsed AST", { rootNodeType: tree.rootNode.type });
|
|
30241
30711
|
const parseStatus = extractParseStatus(tree);
|
|
@@ -30563,7 +31033,7 @@ var colors = {
|
|
|
30563
31033
|
};
|
|
30564
31034
|
|
|
30565
31035
|
// src/version.ts
|
|
30566
|
-
var version = "3.
|
|
31036
|
+
var version = "3.64.0";
|
|
30567
31037
|
|
|
30568
31038
|
// src/formatters.ts
|
|
30569
31039
|
var SINK_SEVERITY = {
|
|
@@ -30586,7 +31056,11 @@ var SINK_SEVERITY = {
|
|
|
30586
31056
|
insecure_cookie: "low",
|
|
30587
31057
|
trust_boundary: "medium",
|
|
30588
31058
|
external_taint_escape: "medium",
|
|
30589
|
-
mybatis_mapper_call: "medium"
|
|
31059
|
+
mybatis_mapper_call: "medium",
|
|
31060
|
+
redos: "medium",
|
|
31061
|
+
format_string: "high",
|
|
31062
|
+
crlf: "medium",
|
|
31063
|
+
mass_assignment: "high"
|
|
30590
31064
|
};
|
|
30591
31065
|
var SINK_CWE = {
|
|
30592
31066
|
sql_injection: "CWE-89",
|
|
@@ -30608,7 +31082,11 @@ var SINK_CWE = {
|
|
|
30608
31082
|
insecure_cookie: "CWE-614",
|
|
30609
31083
|
trust_boundary: "CWE-501",
|
|
30610
31084
|
external_taint_escape: "CWE-20",
|
|
30611
|
-
mybatis_mapper_call: "CWE-89"
|
|
31085
|
+
mybatis_mapper_call: "CWE-89",
|
|
31086
|
+
redos: "CWE-1333",
|
|
31087
|
+
format_string: "CWE-134",
|
|
31088
|
+
crlf: "CWE-113",
|
|
31089
|
+
mass_assignment: "CWE-915"
|
|
30612
31090
|
};
|
|
30613
31091
|
var VULNERABILITY_HELP = {
|
|
30614
31092
|
sql_injection: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cognium-dev",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.64.0",
|
|
4
4
|
"description": "Static Application Security Testing CLI for detecting security vulnerabilities via taint tracking",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"registry": "https://registry.npmjs.org/"
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
|
-
"circle-ir": "^3.
|
|
68
|
+
"circle-ir": "^3.64.0"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@types/node": "^25.5.0",
|