cognium-dev 3.59.0 → 3.62.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 +397 -48
- 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"] },
|
|
@@ -11787,7 +11968,11 @@ function matchesSourcePattern(call, pattern) {
|
|
|
11787
11968
|
}
|
|
11788
11969
|
if (pattern.class && pattern.class !== "constructor") {
|
|
11789
11970
|
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
|
-
|
|
11971
|
+
const target = call.resolution?.target;
|
|
11972
|
+
const expectedTail = `${pattern.class}.${pattern.method}`;
|
|
11973
|
+
if (target && (target === expectedTail || target.endsWith("." + expectedTail))) {} else {
|
|
11974
|
+
return false;
|
|
11975
|
+
}
|
|
11791
11976
|
} else if (!receiverMightBeClass(call.receiver, pattern.class)) {
|
|
11792
11977
|
return false;
|
|
11793
11978
|
}
|
|
@@ -12044,7 +12229,11 @@ function matchesSinkPattern(call, pattern, typeHierarchy, language) {
|
|
|
12044
12229
|
}
|
|
12045
12230
|
return false;
|
|
12046
12231
|
} else if (!call.receiver && !call.receiver_type) {
|
|
12047
|
-
|
|
12232
|
+
const target = call.resolution?.target;
|
|
12233
|
+
const expectedTail = `${pattern.class}.${pattern.method}`;
|
|
12234
|
+
if (target && (target === expectedTail || target.endsWith("." + expectedTail))) {} else {
|
|
12235
|
+
return false;
|
|
12236
|
+
}
|
|
12048
12237
|
}
|
|
12049
12238
|
}
|
|
12050
12239
|
if (!pattern.class && call.receiver) {
|
|
@@ -15051,6 +15240,9 @@ class DefaultLanguageRegistry {
|
|
|
15051
15240
|
}
|
|
15052
15241
|
}
|
|
15053
15242
|
get(language) {
|
|
15243
|
+
if (language === "tsx") {
|
|
15244
|
+
return this.plugins.get("javascript");
|
|
15245
|
+
}
|
|
15054
15246
|
return this.plugins.get(language);
|
|
15055
15247
|
}
|
|
15056
15248
|
getForFile(filePath) {
|
|
@@ -17244,6 +17436,20 @@ class BashPlugin extends BaseLanguagePlugin {
|
|
|
17244
17436
|
cwe: "CWE-918",
|
|
17245
17437
|
severity: "high",
|
|
17246
17438
|
argPositions: [0]
|
|
17439
|
+
},
|
|
17440
|
+
{
|
|
17441
|
+
method: "source",
|
|
17442
|
+
type: "path_traversal",
|
|
17443
|
+
cwe: "CWE-98",
|
|
17444
|
+
severity: "critical",
|
|
17445
|
+
argPositions: [0]
|
|
17446
|
+
},
|
|
17447
|
+
{
|
|
17448
|
+
method: ".",
|
|
17449
|
+
type: "path_traversal",
|
|
17450
|
+
cwe: "CWE-98",
|
|
17451
|
+
severity: "critical",
|
|
17452
|
+
argPositions: [0]
|
|
17247
17453
|
}
|
|
17248
17454
|
];
|
|
17249
17455
|
}
|
|
@@ -20337,6 +20543,7 @@ function mergeHtmlResults(htmlMeta, scriptResults, attributeFindings) {
|
|
|
20337
20543
|
const allSources = [];
|
|
20338
20544
|
const allSinks = [];
|
|
20339
20545
|
const allSanitizers = [];
|
|
20546
|
+
const allFlows = [];
|
|
20340
20547
|
const allImports = [];
|
|
20341
20548
|
const allExports = [];
|
|
20342
20549
|
const allFindings = [];
|
|
@@ -20422,6 +20629,14 @@ function mergeHtmlResults(htmlMeta, scriptResults, attributeFindings) {
|
|
|
20422
20629
|
line: sanitizer.line + lineShift
|
|
20423
20630
|
});
|
|
20424
20631
|
}
|
|
20632
|
+
for (const flow of ir.taint.flows ?? []) {
|
|
20633
|
+
allFlows.push({
|
|
20634
|
+
...flow,
|
|
20635
|
+
source_line: flow.source_line + lineShift,
|
|
20636
|
+
sink_line: flow.sink_line + lineShift,
|
|
20637
|
+
path: flow.path.map((step) => ({ ...step, line: step.line + lineShift }))
|
|
20638
|
+
});
|
|
20639
|
+
}
|
|
20425
20640
|
for (const imp of ir.imports) {
|
|
20426
20641
|
allImports.push({
|
|
20427
20642
|
...imp,
|
|
@@ -20441,7 +20656,8 @@ function mergeHtmlResults(htmlMeta, scriptResults, attributeFindings) {
|
|
|
20441
20656
|
const taint = {
|
|
20442
20657
|
sources: allSources,
|
|
20443
20658
|
sinks: allSinks,
|
|
20444
|
-
sanitizers: allSanitizers.length > 0 ? allSanitizers : undefined
|
|
20659
|
+
sanitizers: allSanitizers.length > 0 ? allSanitizers : undefined,
|
|
20660
|
+
flows: allFlows.length > 0 ? allFlows : undefined
|
|
20445
20661
|
};
|
|
20446
20662
|
const cfg = {
|
|
20447
20663
|
blocks: allCfgBlocks,
|
|
@@ -20637,6 +20853,7 @@ class LanguageSourcesPass {
|
|
|
20637
20853
|
const constProp = ctx.getResult("constant-propagation");
|
|
20638
20854
|
const additionalSources = [];
|
|
20639
20855
|
const additionalSinks = [];
|
|
20856
|
+
const additionalSanitizers = [];
|
|
20640
20857
|
additionalSources.push(...findGetterSources(types, constProp.instanceFieldTaint, code));
|
|
20641
20858
|
additionalSources.push(...findOopFieldReadSources(types, code, language));
|
|
20642
20859
|
additionalSources.push(...findJavaScriptAssignmentSources(code, language));
|
|
@@ -20690,9 +20907,10 @@ class LanguageSourcesPass {
|
|
|
20690
20907
|
for (const finding of bashFindings) {
|
|
20691
20908
|
ctx.addFinding(finding);
|
|
20692
20909
|
}
|
|
20910
|
+
additionalSanitizers.push(...findBashRegexAllowlistSanitizers(code));
|
|
20693
20911
|
}
|
|
20694
20912
|
attachSourceLineCode(additionalSources, additionalSinks, code);
|
|
20695
|
-
return { additionalSources, additionalSinks, pyTaintedVars, pySanitizedVars, jsTaintedVars };
|
|
20913
|
+
return { additionalSources, additionalSinks, additionalSanitizers, pyTaintedVars, pySanitizedVars, jsTaintedVars };
|
|
20696
20914
|
}
|
|
20697
20915
|
}
|
|
20698
20916
|
function findGetterSources(types, instanceFieldTaint, _sourceCode) {
|
|
@@ -20943,62 +21161,62 @@ function buildPythonTaintedVars(sourceCode) {
|
|
|
20943
21161
|
const line = lines[i2];
|
|
20944
21162
|
if (line.trimStart().startsWith("#"))
|
|
20945
21163
|
continue;
|
|
20946
|
-
const subscriptAssign = line.match(/^\s*(\
|
|
21164
|
+
const subscriptAssign = line.match(/^\s*([\p{L}\p{N}_]+)\[(['"])([^'"]+)\2\]\s*=\s*(.+)$/u);
|
|
20947
21165
|
if (subscriptAssign) {
|
|
20948
21166
|
const [, container, , key, rhs2] = subscriptAssign;
|
|
20949
|
-
const isTaintedRhs = [...tainted.keys()].some((v) => new RegExp(
|
|
21167
|
+
const isTaintedRhs = [...tainted.keys()].some((v) => new RegExp(`(?<![\\p{L}\\p{N}_])${v}(?![\\p{L}\\p{N}_])`, "u").test(rhs2));
|
|
20950
21168
|
if (isTaintedRhs)
|
|
20951
21169
|
containerTainted.set(`${container}['${key}']`, i2 + 1);
|
|
20952
21170
|
continue;
|
|
20953
21171
|
}
|
|
20954
|
-
const setCallMatch = line.match(/^\s*(\
|
|
21172
|
+
const setCallMatch = line.match(/^\s*([\p{L}\p{N}_]+)\.set\s*\(\s*(['"])([^'"]+)\2\s*,\s*(['"])([^'"]+)\4\s*,\s*(.+?)\s*\)$/u);
|
|
20955
21173
|
if (setCallMatch) {
|
|
20956
21174
|
const [, obj, , section, , key, rhs2] = setCallMatch;
|
|
20957
|
-
const isTaintedRhs = [...tainted.keys()].some((v) => new RegExp(
|
|
21175
|
+
const isTaintedRhs = [...tainted.keys()].some((v) => new RegExp(`(?<![\\p{L}\\p{N}_])${v}(?![\\p{L}\\p{N}_])`, "u").test(rhs2));
|
|
20958
21176
|
if (isTaintedRhs)
|
|
20959
21177
|
containerTainted.set(`${obj}['${section}']['${key}']`, i2 + 1);
|
|
20960
21178
|
continue;
|
|
20961
21179
|
}
|
|
20962
|
-
const containerAppendMatch = line.match(/^\s*(\
|
|
21180
|
+
const containerAppendMatch = line.match(/^\s*([\p{L}\p{N}_]+)\.(append|extend|insert|add|push|put|appendleft)\s*\(\s*(.+?)\s*\)\s*$/u);
|
|
20963
21181
|
if (containerAppendMatch) {
|
|
20964
21182
|
const [, receiver, , argExpr] = containerAppendMatch;
|
|
20965
|
-
const argIsTainted = [...tainted.keys()].some((v) => new RegExp(
|
|
21183
|
+
const argIsTainted = [...tainted.keys()].some((v) => new RegExp(`(?<![\\p{L}\\p{N}_])${v}(?![\\p{L}\\p{N}_])`, "u").test(argExpr));
|
|
20966
21184
|
const argIsDirectSource = PYTHON_TAINTED_PATTERNS2.some((p) => p.pattern.test(argExpr));
|
|
20967
21185
|
if (argIsTainted || argIsDirectSource)
|
|
20968
21186
|
tainted.set(receiver, tainted.get(receiver) ?? i2 + 1);
|
|
20969
21187
|
continue;
|
|
20970
21188
|
}
|
|
20971
|
-
const augAssign = line.match(/^\s*(\
|
|
21189
|
+
const augAssign = line.match(/^\s*([\p{L}\p{N}_]+)\s*\+=\s*(.+)$/u);
|
|
20972
21190
|
if (augAssign) {
|
|
20973
21191
|
const [, augLhs, augRhs] = augAssign;
|
|
20974
|
-
const rhsTainted = [...tainted.keys()].some((v) => new RegExp(
|
|
21192
|
+
const rhsTainted = [...tainted.keys()].some((v) => new RegExp(`(?<![\\p{L}\\p{N}_])${v}(?![\\p{L}\\p{N}_])`, "u").test(augRhs));
|
|
20975
21193
|
if (rhsTainted || tainted.has(augLhs))
|
|
20976
21194
|
tainted.set(augLhs, tainted.get(augLhs) ?? i2 + 1);
|
|
20977
21195
|
continue;
|
|
20978
21196
|
}
|
|
20979
|
-
const forLoopMatch = line.match(/^\s*for\s+(\
|
|
21197
|
+
const forLoopMatch = line.match(/^\s*for\s+([\p{L}\p{N}_]+)\s+in\s+(.+?)(?:\s*:\s*)?$/u);
|
|
20980
21198
|
if (forLoopMatch) {
|
|
20981
21199
|
const [, iterVar, iterExpr] = forLoopMatch;
|
|
20982
21200
|
const isDirectSource2 = PYTHON_TAINTED_PATTERNS2.some((p) => p.pattern.test(iterExpr));
|
|
20983
|
-
const isPropagated = [...tainted.keys()].some((v) => new RegExp(
|
|
21201
|
+
const isPropagated = [...tainted.keys()].some((v) => new RegExp(`(?<![\\p{L}\\p{N}_])${v}(?![\\p{L}\\p{N}_])`, "u").test(iterExpr));
|
|
20984
21202
|
if (isDirectSource2 || isPropagated)
|
|
20985
21203
|
tainted.set(iterVar, i2 + 1);
|
|
20986
21204
|
continue;
|
|
20987
21205
|
}
|
|
20988
|
-
const assignMatch = line.match(/^\s*(\
|
|
21206
|
+
const assignMatch = line.match(/^\s*([\p{L}\p{N}_]+)\s*=\s*(.+)$/u);
|
|
20989
21207
|
if (!assignMatch)
|
|
20990
21208
|
continue;
|
|
20991
21209
|
const [, lhs, rhs] = assignMatch;
|
|
20992
21210
|
const isDirectSource = PYTHON_TAINTED_PATTERNS2.some((p) => p.pattern.test(rhs));
|
|
20993
21211
|
let propagatedFrom;
|
|
20994
|
-
const dictAccessMatch = rhs.trim().match(/^(\
|
|
21212
|
+
const dictAccessMatch = rhs.trim().match(/^([\p{L}\p{N}_]+)\[(['"])([^'"]+)\2\]$/u);
|
|
20995
21213
|
if (dictAccessMatch) {
|
|
20996
21214
|
const [, container, , key] = dictAccessMatch;
|
|
20997
21215
|
if (containerTainted.has(`${container}['${key}']`))
|
|
20998
21216
|
propagatedFrom = `${container}['${key}']`;
|
|
20999
21217
|
}
|
|
21000
21218
|
if (!propagatedFrom) {
|
|
21001
|
-
const confGetMatch = rhs.trim().match(/^(\
|
|
21219
|
+
const confGetMatch = rhs.trim().match(/^([\p{L}\p{N}_]+)\.get\s*\(\s*(['"])([^'"]+)\2\s*,\s*(['"])([^'"]+)\4\s*\)$/u);
|
|
21002
21220
|
if (confGetMatch) {
|
|
21003
21221
|
const [, obj, , section, , key] = confGetMatch;
|
|
21004
21222
|
if (containerTainted.has(`${obj}['${section}']['${key}']`))
|
|
@@ -21008,7 +21226,7 @@ function buildPythonTaintedVars(sourceCode) {
|
|
|
21008
21226
|
if (!propagatedFrom) {
|
|
21009
21227
|
const isSafeEnvRead = /\bos\.environ\.get\s*\(/.test(rhs) || /\bos\.getenv\s*\(/.test(rhs);
|
|
21010
21228
|
if (!isSafeEnvRead)
|
|
21011
|
-
propagatedFrom = [...tainted.keys()].find((v) => new RegExp(
|
|
21229
|
+
propagatedFrom = [...tainted.keys()].find((v) => new RegExp(`(?<![\\p{L}\\p{N}_])${v}(?![\\p{L}\\p{N}_])`, "u").test(rhs));
|
|
21012
21230
|
}
|
|
21013
21231
|
if (isDirectSource) {
|
|
21014
21232
|
tainted.set(lhs, i2 + 1);
|
|
@@ -21413,6 +21631,61 @@ function findBashPatternFindings(sourceCode, file) {
|
|
|
21413
21631
|
}
|
|
21414
21632
|
return findings;
|
|
21415
21633
|
}
|
|
21634
|
+
function findBashRegexAllowlistSanitizers(code) {
|
|
21635
|
+
const sanitizers = [];
|
|
21636
|
+
const lines = code.split(`
|
|
21637
|
+
`);
|
|
21638
|
+
const guardRe = /^\s*if\s+\[\[\s*!\s*"?\$\{?(\w+)\}?"?\s*=~\s*(\S+)\s*\]\]\s*;\s*then\s+(exit|return|die)\b/;
|
|
21639
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
21640
|
+
const m = guardRe.exec(lines[i2]);
|
|
21641
|
+
if (!m)
|
|
21642
|
+
continue;
|
|
21643
|
+
const regexLiteral = m[2];
|
|
21644
|
+
if (!isSafeBashAllowlistRegex(regexLiteral))
|
|
21645
|
+
continue;
|
|
21646
|
+
const ifLine1Indexed = i2 + 1;
|
|
21647
|
+
for (let l = ifLine1Indexed + 1;l <= lines.length; l++) {
|
|
21648
|
+
sanitizers.push({
|
|
21649
|
+
type: "regex_allowlist",
|
|
21650
|
+
method: "=~",
|
|
21651
|
+
line: l,
|
|
21652
|
+
sanitizes: [
|
|
21653
|
+
"command_injection",
|
|
21654
|
+
"path_traversal",
|
|
21655
|
+
"sql_injection",
|
|
21656
|
+
"code_injection",
|
|
21657
|
+
"ssrf",
|
|
21658
|
+
"xss",
|
|
21659
|
+
"open_redirect",
|
|
21660
|
+
"log_injection"
|
|
21661
|
+
]
|
|
21662
|
+
});
|
|
21663
|
+
}
|
|
21664
|
+
}
|
|
21665
|
+
return sanitizers;
|
|
21666
|
+
}
|
|
21667
|
+
function isSafeBashAllowlistRegex(literal) {
|
|
21668
|
+
if (!literal.startsWith("^") || !literal.endsWith("$"))
|
|
21669
|
+
return false;
|
|
21670
|
+
const body2 = literal.slice(1, -1);
|
|
21671
|
+
if (body2.length === 0)
|
|
21672
|
+
return false;
|
|
21673
|
+
if (body2.includes(".*") || body2.includes(".+"))
|
|
21674
|
+
return false;
|
|
21675
|
+
if (body2.includes("|"))
|
|
21676
|
+
return false;
|
|
21677
|
+
if (/\\\d/.test(body2))
|
|
21678
|
+
return false;
|
|
21679
|
+
const safeToken = /\[[^\]]+\][+*?]?|\\.|[A-Za-z0-9_\-./]|[+*?]/g;
|
|
21680
|
+
let consumed = 0;
|
|
21681
|
+
let match;
|
|
21682
|
+
while ((match = safeToken.exec(body2)) !== null) {
|
|
21683
|
+
if (match.index !== consumed)
|
|
21684
|
+
return false;
|
|
21685
|
+
consumed += match[0].length;
|
|
21686
|
+
}
|
|
21687
|
+
return consumed === body2.length;
|
|
21688
|
+
}
|
|
21416
21689
|
|
|
21417
21690
|
// ../circle-ir/dist/analysis/passes/sink-filter-pass.js
|
|
21418
21691
|
var JS_XSS_SANITIZERS = [
|
|
@@ -21449,7 +21722,10 @@ class SinkFilterPass {
|
|
|
21449
21722
|
sinks.push(s);
|
|
21450
21723
|
}
|
|
21451
21724
|
}
|
|
21452
|
-
const sanitizers =
|
|
21725
|
+
const sanitizers = [
|
|
21726
|
+
...taintMatcher.sanitizers,
|
|
21727
|
+
...langSources.additionalSanitizers ?? []
|
|
21728
|
+
];
|
|
21453
21729
|
let filtered = sinks.filter((sink) => !constProp.unreachableLines.has(sink.line));
|
|
21454
21730
|
filtered = filterCleanArraySinks(filtered, calls, constProp.taintedArrayElements, constProp.symbols);
|
|
21455
21731
|
filtered = filterCleanVariableSinks(filtered, calls, constProp.tainted, constProp.symbols, dfg, constProp.sanitizedVars, constProp.synchronizedLines, language);
|
|
@@ -21934,6 +22210,21 @@ function findInitialTaint(sources, callsByLine, defsByLine) {
|
|
|
21934
22210
|
});
|
|
21935
22211
|
}
|
|
21936
22212
|
}
|
|
22213
|
+
if (source.variable) {
|
|
22214
|
+
const paramDefs = defsByLine.get(0) ?? [];
|
|
22215
|
+
for (const def of paramDefs) {
|
|
22216
|
+
if (def.kind === "param" && def.variable === source.variable) {
|
|
22217
|
+
tainted.push({
|
|
22218
|
+
variable: def.variable,
|
|
22219
|
+
defId: def.id,
|
|
22220
|
+
line: def.line,
|
|
22221
|
+
sourceType: source.type,
|
|
22222
|
+
sourceLine: source.line,
|
|
22223
|
+
confidence: source.confidence
|
|
22224
|
+
});
|
|
22225
|
+
}
|
|
22226
|
+
}
|
|
22227
|
+
}
|
|
21937
22228
|
}
|
|
21938
22229
|
return tainted;
|
|
21939
22230
|
}
|
|
@@ -22507,7 +22798,7 @@ function detectExpressionScanFlows(calls, sources, sinks, sanitizers, unreachabl
|
|
|
22507
22798
|
if (reCache.has(s.variable))
|
|
22508
22799
|
continue;
|
|
22509
22800
|
const escaped = s.variable.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
22510
|
-
reCache.set(s.variable, new RegExp(
|
|
22801
|
+
reCache.set(s.variable, new RegExp(`(?<![\\p{L}\\p{N}_])${escaped}(?![\\p{L}\\p{N}_])`, "u"));
|
|
22511
22802
|
}
|
|
22512
22803
|
const callsByLine = new Map;
|
|
22513
22804
|
for (const call of calls) {
|
|
@@ -22649,6 +22940,13 @@ function analyzeInterprocedural2(graphOrTypes, callsOrSources, dfgOrSinks, sourc
|
|
|
22649
22940
|
for (const def of graph.defsAtLine(source.line)) {
|
|
22650
22941
|
seedIds.add(def.id);
|
|
22651
22942
|
}
|
|
22943
|
+
if (source.variable) {
|
|
22944
|
+
for (const def of graph.defsAtLine(0)) {
|
|
22945
|
+
if (def.kind === "param" && def.variable === source.variable) {
|
|
22946
|
+
seedIds.add(def.id);
|
|
22947
|
+
}
|
|
22948
|
+
}
|
|
22949
|
+
}
|
|
22652
22950
|
}
|
|
22653
22951
|
const taintedDefIds = graph.propagateTaintedDefIds(seedIds);
|
|
22654
22952
|
const taintedVarsFromCP = options.taintedVariables ?? new Set;
|
|
@@ -22789,7 +23087,34 @@ function analyzeInterprocedural2(graphOrTypes, callsOrSources, dfgOrSinks, sourc
|
|
|
22789
23087
|
const targetMethod = getMethodNode(methodNodes, call.method_name);
|
|
22790
23088
|
if (!targetMethod) {
|
|
22791
23089
|
if (taintedArgPositions.length > 0 && !collectionMethods.has(call.method_name) && !sanitizerMethods.has(call.method_name) && !safeUtilityMethods.has(call.method_name)) {
|
|
22792
|
-
const
|
|
23090
|
+
const isBash = graph.ir.meta.language === "bash";
|
|
23091
|
+
const bashSafeBuiltins = new Set([
|
|
23092
|
+
"echo",
|
|
23093
|
+
"printf",
|
|
23094
|
+
"test",
|
|
23095
|
+
"[",
|
|
23096
|
+
"[[",
|
|
23097
|
+
"true",
|
|
23098
|
+
"false",
|
|
23099
|
+
":",
|
|
23100
|
+
"declare",
|
|
23101
|
+
"local",
|
|
23102
|
+
"export",
|
|
23103
|
+
"readonly",
|
|
23104
|
+
"typeset"
|
|
23105
|
+
]);
|
|
23106
|
+
if (isBash && bashSafeBuiltins.has(call.method_name)) {
|
|
23107
|
+
continue;
|
|
23108
|
+
}
|
|
23109
|
+
const sink = isBash ? {
|
|
23110
|
+
type: "command_injection",
|
|
23111
|
+
cwe: "CWE-78",
|
|
23112
|
+
location: `Tainted data (${taintedArgVars.join(", ")}) passed unquoted to shell utility ${call.method_name}`,
|
|
23113
|
+
line: call.location.line,
|
|
23114
|
+
confidence: 0.6,
|
|
23115
|
+
method: call.method_name,
|
|
23116
|
+
argPositions: taintedArgPositions
|
|
23117
|
+
} : {
|
|
22793
23118
|
type: "external_taint_escape",
|
|
22794
23119
|
cwe: "CWE-668",
|
|
22795
23120
|
location: `Tainted data (${taintedArgVars.join(", ")}) passed to external method ${call.receiver ? call.receiver + "." : ""}${call.method_name}()`,
|
|
@@ -23469,6 +23794,7 @@ function isPublicMethod(method, language) {
|
|
|
23469
23794
|
return method.modifiers.includes("public");
|
|
23470
23795
|
case "javascript":
|
|
23471
23796
|
case "typescript":
|
|
23797
|
+
case "tsx":
|
|
23472
23798
|
return !method.modifiers.includes("private") && !method.modifiers.includes("protected");
|
|
23473
23799
|
case "python":
|
|
23474
23800
|
return !method.name.startsWith("_");
|
|
@@ -23488,7 +23814,7 @@ class MissingPublicDocPass {
|
|
|
23488
23814
|
if (UTIL_DIR_RE.test(graph.ir.meta.file)) {
|
|
23489
23815
|
return { missingDocMethods: [], missingDocTypes: [] };
|
|
23490
23816
|
}
|
|
23491
|
-
if (!["java", "javascript", "typescript", "python"].includes(language)) {
|
|
23817
|
+
if (!["java", "javascript", "typescript", "tsx", "python"].includes(language)) {
|
|
23492
23818
|
return { missingDocMethods: [], missingDocTypes: [] };
|
|
23493
23819
|
}
|
|
23494
23820
|
const lines = code.split(`
|
|
@@ -24012,6 +24338,7 @@ function hasDeclKeyword(lineText, language) {
|
|
|
24012
24338
|
return /\b(?:int|long|float|double|boolean|byte|char|short|var|final)\b/.test(lineText) || /\b[A-Z]\w*(?:<[^>]*>)?\s+\w/.test(lineText);
|
|
24013
24339
|
case "javascript":
|
|
24014
24340
|
case "typescript":
|
|
24341
|
+
case "tsx":
|
|
24015
24342
|
return /\b(?:let|const|var)\s+[\w{[]/.test(lineText);
|
|
24016
24343
|
case "rust":
|
|
24017
24344
|
return /\blet\s+(?:mut\s+)?\w/.test(lineText);
|
|
@@ -28518,6 +28845,7 @@ class WeakRandomPass {
|
|
|
28518
28845
|
return "Use the `secrets` module (`secrets.token_bytes`, " + "`secrets.token_hex`, `secrets.choice`, `secrets.randbelow`).";
|
|
28519
28846
|
case "javascript":
|
|
28520
28847
|
case "typescript":
|
|
28848
|
+
case "tsx":
|
|
28521
28849
|
return "Use `crypto.randomBytes(n)` (Node.js) or " + "`crypto.getRandomValues(typedArray)` (browser).";
|
|
28522
28850
|
case "go":
|
|
28523
28851
|
return "Use `crypto/rand` instead of `math/rand`. Example: " + "`b := make([]byte, 32); _, _ = rand.Read(b)` (where `rand` is `crypto/rand`).";
|
|
@@ -28556,7 +28884,7 @@ class WeakRandomPass {
|
|
|
28556
28884
|
}
|
|
28557
28885
|
return null;
|
|
28558
28886
|
}
|
|
28559
|
-
if (language === "javascript" || language === "typescript") {
|
|
28887
|
+
if (language === "javascript" || language === "typescript" || language === "tsx") {
|
|
28560
28888
|
if (method === "random" && (receiver === "Math" || receiver.endsWith(".Math"))) {
|
|
28561
28889
|
return "Math.random";
|
|
28562
28890
|
}
|
|
@@ -30158,6 +30486,7 @@ function getNodeTypesForLanguage(language) {
|
|
|
30158
30486
|
]);
|
|
30159
30487
|
case "javascript":
|
|
30160
30488
|
case "typescript":
|
|
30489
|
+
case "tsx":
|
|
30161
30490
|
return new Set([
|
|
30162
30491
|
"call_expression",
|
|
30163
30492
|
"new_expression",
|
|
@@ -30170,7 +30499,12 @@ function getNodeTypesForLanguage(language) {
|
|
|
30170
30499
|
"import_statement",
|
|
30171
30500
|
"export_statement",
|
|
30172
30501
|
"member_expression",
|
|
30173
|
-
"assignment_expression"
|
|
30502
|
+
"assignment_expression",
|
|
30503
|
+
"jsx_element",
|
|
30504
|
+
"jsx_self_closing_element",
|
|
30505
|
+
"jsx_opening_element",
|
|
30506
|
+
"jsx_attribute",
|
|
30507
|
+
"jsx_expression"
|
|
30174
30508
|
]);
|
|
30175
30509
|
case "bash":
|
|
30176
30510
|
return new Set([
|
|
@@ -30234,8 +30568,15 @@ async function analyze(code, filePath, language, options = {}) {
|
|
|
30234
30568
|
if (language === "html") {
|
|
30235
30569
|
return analyzeHtmlFile(code, filePath, options);
|
|
30236
30570
|
}
|
|
30237
|
-
|
|
30238
|
-
|
|
30571
|
+
let parseGrammar = language;
|
|
30572
|
+
if (language === "javascript" || language === "typescript") {
|
|
30573
|
+
const lower = filePath.toLowerCase();
|
|
30574
|
+
if (lower.endsWith(".tsx") || lower.endsWith(".jsx")) {
|
|
30575
|
+
parseGrammar = "tsx";
|
|
30576
|
+
}
|
|
30577
|
+
}
|
|
30578
|
+
logger.debug("Analyzing file", { filePath, language, parseGrammar, codeLength: code.length });
|
|
30579
|
+
const tree = await parse(code, parseGrammar);
|
|
30239
30580
|
try {
|
|
30240
30581
|
logger.trace("Parsed AST", { rootNodeType: tree.rootNode.type });
|
|
30241
30582
|
const parseStatus = extractParseStatus(tree);
|
|
@@ -30563,7 +30904,7 @@ var colors = {
|
|
|
30563
30904
|
};
|
|
30564
30905
|
|
|
30565
30906
|
// src/version.ts
|
|
30566
|
-
var version = "3.
|
|
30907
|
+
var version = "3.62.0";
|
|
30567
30908
|
|
|
30568
30909
|
// src/formatters.ts
|
|
30569
30910
|
var SINK_SEVERITY = {
|
|
@@ -30586,7 +30927,11 @@ var SINK_SEVERITY = {
|
|
|
30586
30927
|
insecure_cookie: "low",
|
|
30587
30928
|
trust_boundary: "medium",
|
|
30588
30929
|
external_taint_escape: "medium",
|
|
30589
|
-
mybatis_mapper_call: "medium"
|
|
30930
|
+
mybatis_mapper_call: "medium",
|
|
30931
|
+
redos: "medium",
|
|
30932
|
+
format_string: "high",
|
|
30933
|
+
crlf: "medium",
|
|
30934
|
+
mass_assignment: "high"
|
|
30590
30935
|
};
|
|
30591
30936
|
var SINK_CWE = {
|
|
30592
30937
|
sql_injection: "CWE-89",
|
|
@@ -30608,7 +30953,11 @@ var SINK_CWE = {
|
|
|
30608
30953
|
insecure_cookie: "CWE-614",
|
|
30609
30954
|
trust_boundary: "CWE-501",
|
|
30610
30955
|
external_taint_escape: "CWE-20",
|
|
30611
|
-
mybatis_mapper_call: "CWE-89"
|
|
30956
|
+
mybatis_mapper_call: "CWE-89",
|
|
30957
|
+
redos: "CWE-1333",
|
|
30958
|
+
format_string: "CWE-134",
|
|
30959
|
+
crlf: "CWE-113",
|
|
30960
|
+
mass_assignment: "CWE-915"
|
|
30612
30961
|
};
|
|
30613
30962
|
var VULNERABILITY_HELP = {
|
|
30614
30963
|
sql_injection: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cognium-dev",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.62.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.62.0"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@types/node": "^25.5.0",
|