cognium-dev 3.47.0 → 3.49.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 +452 -99
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -3391,11 +3391,14 @@ function disposeTree(tree) {
|
|
|
3391
3391
|
} catch {}
|
|
3392
3392
|
}
|
|
3393
3393
|
function walkTree(node, visitor) {
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
const
|
|
3397
|
-
|
|
3398
|
-
|
|
3394
|
+
const stack = [node];
|
|
3395
|
+
while (stack.length > 0) {
|
|
3396
|
+
const current = stack.pop();
|
|
3397
|
+
visitor(current);
|
|
3398
|
+
for (let i2 = current.childCount - 1;i2 >= 0; i2--) {
|
|
3399
|
+
const child = current.child(i2);
|
|
3400
|
+
if (child)
|
|
3401
|
+
stack.push(child);
|
|
3399
3402
|
}
|
|
3400
3403
|
}
|
|
3401
3404
|
}
|
|
@@ -4032,15 +4035,54 @@ function extractJSClassInfo(node) {
|
|
|
4032
4035
|
end_line: node.endPosition.row + 1
|
|
4033
4036
|
};
|
|
4034
4037
|
}
|
|
4038
|
+
function extractDecoratorName(node) {
|
|
4039
|
+
const child = node.namedChildCount > 0 ? node.namedChild(0) : null;
|
|
4040
|
+
if (!child)
|
|
4041
|
+
return null;
|
|
4042
|
+
if (child.type === "identifier")
|
|
4043
|
+
return getNodeText(child);
|
|
4044
|
+
if (child.type === "call_expression") {
|
|
4045
|
+
const fn = child.childForFieldName("function");
|
|
4046
|
+
if (fn) {
|
|
4047
|
+
if (fn.type === "identifier")
|
|
4048
|
+
return getNodeText(fn);
|
|
4049
|
+
if (fn.type === "member_expression") {
|
|
4050
|
+
const propNode = fn.childForFieldName("property");
|
|
4051
|
+
if (propNode)
|
|
4052
|
+
return getNodeText(propNode);
|
|
4053
|
+
}
|
|
4054
|
+
}
|
|
4055
|
+
}
|
|
4056
|
+
if (child.type === "member_expression") {
|
|
4057
|
+
const propNode = child.childForFieldName("property");
|
|
4058
|
+
if (propNode)
|
|
4059
|
+
return getNodeText(propNode);
|
|
4060
|
+
}
|
|
4061
|
+
return null;
|
|
4062
|
+
}
|
|
4035
4063
|
function extractJSMethods(body2) {
|
|
4036
4064
|
const methods = [];
|
|
4065
|
+
let pendingDecorators = [];
|
|
4037
4066
|
for (let i2 = 0;i2 < body2.childCount; i2++) {
|
|
4038
4067
|
const child = body2.child(i2);
|
|
4039
4068
|
if (!child)
|
|
4040
4069
|
continue;
|
|
4070
|
+
if (child.type === "decorator") {
|
|
4071
|
+
const name2 = extractDecoratorName(child);
|
|
4072
|
+
if (name2)
|
|
4073
|
+
pendingDecorators.push(name2);
|
|
4074
|
+
continue;
|
|
4075
|
+
}
|
|
4076
|
+
if (child.type === "comment")
|
|
4077
|
+
continue;
|
|
4041
4078
|
if (child.type === "method_definition") {
|
|
4042
|
-
|
|
4079
|
+
const m = extractJSMethodInfo(child);
|
|
4080
|
+
if (pendingDecorators.length > 0) {
|
|
4081
|
+
m.annotations = pendingDecorators;
|
|
4082
|
+
}
|
|
4083
|
+
methods.push(m);
|
|
4043
4084
|
}
|
|
4085
|
+
pendingDecorators = [];
|
|
4044
4086
|
}
|
|
4045
4087
|
return methods;
|
|
4046
4088
|
}
|
|
@@ -4211,10 +4253,19 @@ function extractJSParameters(params) {
|
|
|
4211
4253
|
if (typeNode) {
|
|
4212
4254
|
paramType = getNodeText(typeNode).replace(/^:\s*/, "");
|
|
4213
4255
|
}
|
|
4256
|
+
const decorators = [];
|
|
4257
|
+
for (let j = 0;j < child.childCount; j++) {
|
|
4258
|
+
const c = child.child(j);
|
|
4259
|
+
if (c && c.type === "decorator") {
|
|
4260
|
+
const name2 = extractDecoratorName(c);
|
|
4261
|
+
if (name2)
|
|
4262
|
+
decorators.push(name2);
|
|
4263
|
+
}
|
|
4264
|
+
}
|
|
4214
4265
|
parameters.push({
|
|
4215
4266
|
name: paramName,
|
|
4216
4267
|
type: paramType,
|
|
4217
|
-
annotations:
|
|
4268
|
+
annotations: decorators,
|
|
4218
4269
|
line: child.startPosition.row + 1
|
|
4219
4270
|
});
|
|
4220
4271
|
}
|
|
@@ -10795,6 +10846,18 @@ var DEFAULT_SINKS = [
|
|
|
10795
10846
|
{ method: "getExecutionPreamble", class: "Shell", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [] },
|
|
10796
10847
|
{ method: "setQuotedArgumentsEnabled", class: "Shell", type: "command_injection", cwe: "CWE-78", severity: "high", arg_positions: [0] },
|
|
10797
10848
|
{ method: "onNewInstance", class: "SandboxInterceptor", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10849
|
+
{ method: "info", class: "Logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3], languages: ["java"] },
|
|
10850
|
+
{ method: "warn", class: "Logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3], languages: ["java"] },
|
|
10851
|
+
{ method: "error", class: "Logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3], languages: ["java"] },
|
|
10852
|
+
{ method: "debug", class: "Logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3], languages: ["java"] },
|
|
10853
|
+
{ method: "trace", class: "Logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3], languages: ["java"] },
|
|
10854
|
+
{ method: "severe", class: "Logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0], languages: ["java"] },
|
|
10855
|
+
{ method: "warning", class: "Logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0], languages: ["java"] },
|
|
10856
|
+
{ method: "config", class: "Logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0], languages: ["java"] },
|
|
10857
|
+
{ method: "fine", class: "Logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0], languages: ["java"] },
|
|
10858
|
+
{ method: "finer", class: "Logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0], languages: ["java"] },
|
|
10859
|
+
{ method: "finest", class: "Logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0], languages: ["java"] },
|
|
10860
|
+
{ method: "log", class: "Logger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [1, 2, 3], languages: ["java"] },
|
|
10798
10861
|
{ method: "exec", class: "child_process", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10799
10862
|
{ method: "execSync", class: "child_process", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10800
10863
|
{ method: "spawn", class: "child_process", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
@@ -10835,6 +10898,29 @@ var DEFAULT_SINKS = [
|
|
|
10835
10898
|
{ method: "updateMany", class: "Collection", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0] },
|
|
10836
10899
|
{ method: "deleteOne", class: "Collection", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0] },
|
|
10837
10900
|
{ method: "deleteMany", class: "Collection", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0] },
|
|
10901
|
+
{ method: "find", class: "Model", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["javascript", "typescript"] },
|
|
10902
|
+
{ method: "findOne", class: "Model", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["javascript", "typescript"] },
|
|
10903
|
+
{ method: "findById", class: "Model", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["javascript", "typescript"] },
|
|
10904
|
+
{ method: "findOneAndUpdate", class: "Model", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0, 1], languages: ["javascript", "typescript"] },
|
|
10905
|
+
{ method: "findOneAndDelete", class: "Model", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["javascript", "typescript"] },
|
|
10906
|
+
{ method: "findOneAndReplace", class: "Model", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0, 1], languages: ["javascript", "typescript"] },
|
|
10907
|
+
{ method: "updateOne", class: "Model", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0, 1], languages: ["javascript", "typescript"] },
|
|
10908
|
+
{ method: "updateMany", class: "Model", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0, 1], languages: ["javascript", "typescript"] },
|
|
10909
|
+
{ method: "deleteOne", class: "Model", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["javascript", "typescript"] },
|
|
10910
|
+
{ method: "deleteMany", class: "Model", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["javascript", "typescript"] },
|
|
10911
|
+
{ method: "countDocuments", class: "Model", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["javascript", "typescript"] },
|
|
10912
|
+
{ method: "aggregate", class: "Model", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["javascript", "typescript"] },
|
|
10913
|
+
{ method: "where", class: "Query", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["javascript", "typescript"] },
|
|
10914
|
+
{ method: "equals", class: "Query", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["javascript", "typescript"] },
|
|
10915
|
+
{ method: "findOne", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["javascript", "typescript"] },
|
|
10916
|
+
{ method: "findOneAndUpdate", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0, 1], languages: ["javascript", "typescript"] },
|
|
10917
|
+
{ method: "findOneAndDelete", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["javascript", "typescript"] },
|
|
10918
|
+
{ method: "findOneAndReplace", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0, 1], languages: ["javascript", "typescript"] },
|
|
10919
|
+
{ method: "updateOne", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0, 1], languages: ["javascript", "typescript"] },
|
|
10920
|
+
{ method: "updateMany", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0, 1], languages: ["javascript", "typescript"] },
|
|
10921
|
+
{ method: "deleteOne", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["javascript", "typescript"] },
|
|
10922
|
+
{ method: "deleteMany", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["javascript", "typescript"] },
|
|
10923
|
+
{ method: "aggregate", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["javascript", "typescript"] },
|
|
10838
10924
|
{ method: "get", class: "axios", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0] },
|
|
10839
10925
|
{ method: "post", class: "axios", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0] },
|
|
10840
10926
|
{ method: "request", class: "axios", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0] },
|
|
@@ -10851,6 +10937,13 @@ var DEFAULT_SINKS = [
|
|
|
10851
10937
|
{ method: "get", class: "superagent", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0] },
|
|
10852
10938
|
{ method: "post", class: "superagent", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0] },
|
|
10853
10939
|
{ method: "default", class: "node-fetch", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0] },
|
|
10940
|
+
{ method: "log", class: "console", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3], languages: ["javascript", "typescript"] },
|
|
10941
|
+
{ method: "warn", class: "console", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3], languages: ["javascript", "typescript"] },
|
|
10942
|
+
{ method: "error", class: "console", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3], languages: ["javascript", "typescript"] },
|
|
10943
|
+
{ method: "info", class: "console", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3], languages: ["javascript", "typescript"] },
|
|
10944
|
+
{ method: "debug", class: "console", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3], languages: ["javascript", "typescript"] },
|
|
10945
|
+
{ method: "trace", class: "console", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3], languages: ["javascript", "typescript"] },
|
|
10946
|
+
{ method: "redirect", type: "open_redirect", cwe: "CWE-601", severity: "medium", arg_positions: [0], languages: ["javascript", "typescript"] },
|
|
10854
10947
|
{ method: "system", class: "os", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10855
10948
|
{ method: "popen", class: "os", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
10856
10949
|
{ method: "run", class: "subprocess", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
@@ -10877,7 +10970,7 @@ var DEFAULT_SINKS = [
|
|
|
10877
10970
|
{ method: "rmdir", class: "os", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
|
|
10878
10971
|
{ method: "rmtree", class: "shutil", type: "path_traversal", cwe: "CWE-22", severity: "critical", arg_positions: [0] },
|
|
10879
10972
|
{ method: "send_file", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["python"] },
|
|
10880
|
-
{ method: "render_template_string", type: "
|
|
10973
|
+
{ method: "render_template_string", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["python"] },
|
|
10881
10974
|
{ method: "Markup", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0], languages: ["python"] },
|
|
10882
10975
|
{ method: "mark_safe", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0], languages: ["python"] },
|
|
10883
10976
|
{ method: "get", class: "requests", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0] },
|
|
@@ -11139,6 +11232,10 @@ var DEFAULT_SANITIZERS = [
|
|
|
11139
11232
|
{ method: "secure_filename", class: "werkzeug.utils", removes: ["path_traversal"] },
|
|
11140
11233
|
{ method: "basename", class: "os.path", removes: ["path_traversal"] },
|
|
11141
11234
|
{ method: "normpath", class: "os.path", removes: ["path_traversal"] },
|
|
11235
|
+
{ method: "realpath", class: "os.path", removes: ["path_traversal"] },
|
|
11236
|
+
{ method: "abspath", class: "os.path", removes: ["path_traversal"] },
|
|
11237
|
+
{ method: "realpath", class: "path", removes: ["path_traversal"] },
|
|
11238
|
+
{ method: "abspath", class: "path", removes: ["path_traversal"] },
|
|
11142
11239
|
{ method: "int", removes: ["sql_injection", "command_injection", "xss"] },
|
|
11143
11240
|
{ method: "float", removes: ["sql_injection", "command_injection"] },
|
|
11144
11241
|
{ method: "query!", removes: ["sql_injection"] },
|
|
@@ -11267,7 +11364,7 @@ var PYTHON_TAINTED_PATTERNS = [
|
|
|
11267
11364
|
function analyzeTaint(calls, types, config = getDefaultConfig(), typeHierarchy, language, code) {
|
|
11268
11365
|
const sourceLines = code !== undefined ? code.split(`
|
|
11269
11366
|
`) : undefined;
|
|
11270
|
-
const sources = findSources(calls, types, config.sources, sourceLines);
|
|
11367
|
+
const sources = findSources(calls, types, config.sources, sourceLines, language);
|
|
11271
11368
|
const sinks = findSinks(calls, config.sinks, typeHierarchy, language, sourceLines);
|
|
11272
11369
|
const sanitizers = findSanitizers(calls, types, config.sanitizers);
|
|
11273
11370
|
return { sources, sinks, sanitizers };
|
|
@@ -11286,7 +11383,7 @@ function attachSourceLineCode(sources, sinks, code) {
|
|
|
11286
11383
|
}
|
|
11287
11384
|
}
|
|
11288
11385
|
}
|
|
11289
|
-
function findSources(calls, types, patterns, sourceLines) {
|
|
11386
|
+
function findSources(calls, types, patterns, sourceLines, language) {
|
|
11290
11387
|
const sources = [];
|
|
11291
11388
|
for (const call of calls) {
|
|
11292
11389
|
for (const pattern of patterns) {
|
|
@@ -11341,23 +11438,31 @@ function findSources(calls, types, patterns, sourceLines) {
|
|
|
11341
11438
|
}
|
|
11342
11439
|
}
|
|
11343
11440
|
}
|
|
11344
|
-
const
|
|
11441
|
+
const RUST_EXTRACTOR_KIND = /(?:^|::)(Json|Form|Query|Path|Extension|Multipart|Body|Bytes)(?:<|$)/;
|
|
11345
11442
|
for (const type of types) {
|
|
11346
11443
|
for (const method of type.methods) {
|
|
11347
11444
|
for (const param of method.parameters) {
|
|
11348
|
-
if (param.type
|
|
11349
|
-
|
|
11350
|
-
|
|
11351
|
-
|
|
11352
|
-
|
|
11353
|
-
|
|
11354
|
-
|
|
11355
|
-
|
|
11356
|
-
|
|
11357
|
-
|
|
11358
|
-
|
|
11359
|
-
|
|
11360
|
-
|
|
11445
|
+
if (!param.type)
|
|
11446
|
+
continue;
|
|
11447
|
+
const kindMatch = RUST_EXTRACTOR_KIND.exec(param.type);
|
|
11448
|
+
if (!kindMatch)
|
|
11449
|
+
continue;
|
|
11450
|
+
const kind = kindMatch[1];
|
|
11451
|
+
if (kind === "Extension")
|
|
11452
|
+
continue;
|
|
11453
|
+
const sourceType = kind === "Form" || kind === "Query" || kind === "Path" ? "http_param" : "http_body";
|
|
11454
|
+
const paramLine = param.line ?? method.start_line;
|
|
11455
|
+
const alreadyExists = sources.some((s) => s.line === paramLine && s.variable === param.name);
|
|
11456
|
+
if (alreadyExists)
|
|
11457
|
+
continue;
|
|
11458
|
+
sources.push({
|
|
11459
|
+
type: sourceType,
|
|
11460
|
+
location: `${param.type} ${param.name} in ${method.name}`,
|
|
11461
|
+
severity: "high",
|
|
11462
|
+
line: paramLine,
|
|
11463
|
+
confidence: 1,
|
|
11464
|
+
variable: param.name
|
|
11465
|
+
});
|
|
11361
11466
|
}
|
|
11362
11467
|
}
|
|
11363
11468
|
}
|
|
@@ -11439,6 +11544,17 @@ function findSources(calls, types, patterns, sourceLines) {
|
|
|
11439
11544
|
s.code = sourceLines[s.line - 1]?.trim();
|
|
11440
11545
|
}
|
|
11441
11546
|
}
|
|
11547
|
+
if (language === "rust" && sourceLines) {
|
|
11548
|
+
const LET_BINDING = /^\s*let\s+(?:mut\s+)?([A-Za-z_]\w*)\s*(?::\s*[^=]+)?=/;
|
|
11549
|
+
for (const s of result) {
|
|
11550
|
+
if (s.variable && s.variable.length > 0)
|
|
11551
|
+
continue;
|
|
11552
|
+
const lineText = sourceLines[s.line - 1] ?? "";
|
|
11553
|
+
const m = LET_BINDING.exec(lineText);
|
|
11554
|
+
if (m)
|
|
11555
|
+
s.variable = m[1];
|
|
11556
|
+
}
|
|
11557
|
+
}
|
|
11442
11558
|
return result;
|
|
11443
11559
|
}
|
|
11444
11560
|
function isInterproceduralTaintableType(typeName) {
|
|
@@ -11535,6 +11651,26 @@ function isParameterizedQueryCall(call, pattern) {
|
|
|
11535
11651
|
}
|
|
11536
11652
|
return false;
|
|
11537
11653
|
}
|
|
11654
|
+
function isSafePythonSubprocessCall(call, pattern, language) {
|
|
11655
|
+
if (language !== "python")
|
|
11656
|
+
return false;
|
|
11657
|
+
if (pattern.type !== "command_injection")
|
|
11658
|
+
return false;
|
|
11659
|
+
if (pattern.class !== "subprocess")
|
|
11660
|
+
return false;
|
|
11661
|
+
const arg0 = call.arguments.find((a) => a.position === 0);
|
|
11662
|
+
if (!arg0)
|
|
11663
|
+
return false;
|
|
11664
|
+
const expr0 = (arg0.literal ?? arg0.expression ?? "").trim();
|
|
11665
|
+
if (!expr0.startsWith("["))
|
|
11666
|
+
return false;
|
|
11667
|
+
for (const a of call.arguments) {
|
|
11668
|
+
const e = (a.expression ?? "").trim();
|
|
11669
|
+
if (/^shell\s*=\s*True\b/.test(e))
|
|
11670
|
+
return false;
|
|
11671
|
+
}
|
|
11672
|
+
return true;
|
|
11673
|
+
}
|
|
11538
11674
|
var CLASS_LITERAL_RE = /^(?:[A-Za-z_][\w]*\.)*[A-Z][\w]*(?:\[\])*\.class$/;
|
|
11539
11675
|
function argIsClassLiteral(call, position) {
|
|
11540
11676
|
const arg = call.arguments.find((a) => a.position === position);
|
|
@@ -11553,6 +11689,9 @@ function findSinks(calls, patterns, typeHierarchy, language, sourceLines) {
|
|
|
11553
11689
|
if (isParameterizedQueryCall(call, pattern)) {
|
|
11554
11690
|
continue;
|
|
11555
11691
|
}
|
|
11692
|
+
if (isSafePythonSubprocessCall(call, pattern, language)) {
|
|
11693
|
+
continue;
|
|
11694
|
+
}
|
|
11556
11695
|
if (pattern.safe_if_class_literal_at !== undefined && argIsClassLiteral(call, pattern.safe_if_class_literal_at)) {
|
|
11557
11696
|
continue;
|
|
11558
11697
|
}
|
|
@@ -11947,7 +12086,8 @@ function receiverMightBeClass(receiver, className) {
|
|
|
11947
12086
|
"controller",
|
|
11948
12087
|
"task",
|
|
11949
12088
|
"thread",
|
|
11950
|
-
"job"
|
|
12089
|
+
"job",
|
|
12090
|
+
"cur"
|
|
11951
12091
|
]);
|
|
11952
12092
|
const isAmbiguous = ambiguousIdentifiers.has(lowerReceiver);
|
|
11953
12093
|
if (!isAmbiguous && lowerReceiver.length >= 3 && lowerClass.includes(lowerReceiver)) {
|
|
@@ -11957,7 +12097,9 @@ function receiverMightBeClass(receiver, className) {
|
|
|
11957
12097
|
}
|
|
11958
12098
|
if (!isAmbiguous && lowerReceiver.length >= 2) {
|
|
11959
12099
|
if (lowerClass.startsWith(lowerReceiver) || lowerClass.endsWith(lowerReceiver)) {
|
|
11960
|
-
|
|
12100
|
+
if (lowerReceiver.length / lowerClass.length >= 0.4) {
|
|
12101
|
+
return true;
|
|
12102
|
+
}
|
|
11961
12103
|
}
|
|
11962
12104
|
}
|
|
11963
12105
|
if (!isAmbiguous && lowerReceiver.length >= 3) {
|
|
@@ -11978,6 +12120,8 @@ function receiverMightBeClass(receiver, className) {
|
|
|
11978
12120
|
ps: ["PreparedStatement"],
|
|
11979
12121
|
rs: ["ResultSet"],
|
|
11980
12122
|
template: ["JdbcTemplate"],
|
|
12123
|
+
cur: ["Cursor"],
|
|
12124
|
+
cursor: ["Cursor"],
|
|
11981
12125
|
writer: ["PrintWriter"],
|
|
11982
12126
|
out: ["PrintWriter", "OutputStream"],
|
|
11983
12127
|
reader: ["BufferedReader"],
|
|
@@ -13202,9 +13346,11 @@ class ConstantPropagator {
|
|
|
13202
13346
|
return findAssignments(methodBody);
|
|
13203
13347
|
}
|
|
13204
13348
|
collectClassFields(root) {
|
|
13205
|
-
const
|
|
13349
|
+
const stack = [root];
|
|
13350
|
+
while (stack.length > 0) {
|
|
13351
|
+
const n = stack.pop();
|
|
13206
13352
|
if (!n)
|
|
13207
|
-
|
|
13353
|
+
continue;
|
|
13208
13354
|
if (n.type === "class_body") {
|
|
13209
13355
|
for (const child of n.children) {
|
|
13210
13356
|
if (child.type === "field_declaration") {
|
|
@@ -13218,34 +13364,30 @@ class ConstantPropagator {
|
|
|
13218
13364
|
}
|
|
13219
13365
|
}
|
|
13220
13366
|
}
|
|
13221
|
-
|
|
13222
|
-
traverse(child, true, true);
|
|
13223
|
-
} else {
|
|
13224
|
-
traverse(child, true, false);
|
|
13225
|
-
}
|
|
13367
|
+
stack.push(child);
|
|
13226
13368
|
}
|
|
13227
|
-
|
|
13369
|
+
continue;
|
|
13228
13370
|
}
|
|
13229
13371
|
for (const child of n.children) {
|
|
13230
|
-
|
|
13372
|
+
stack.push(child);
|
|
13231
13373
|
}
|
|
13232
|
-
}
|
|
13233
|
-
traverse(root, false, false);
|
|
13374
|
+
}
|
|
13234
13375
|
}
|
|
13235
13376
|
findAllMethods(node) {
|
|
13236
13377
|
const methods = [];
|
|
13237
|
-
const
|
|
13378
|
+
const stack = [node];
|
|
13379
|
+
while (stack.length > 0) {
|
|
13380
|
+
const n = stack.pop();
|
|
13238
13381
|
if (!n)
|
|
13239
|
-
|
|
13382
|
+
continue;
|
|
13240
13383
|
if (n.type === "method_declaration" || n.type === "function_declaration") {
|
|
13241
13384
|
methods.push(n);
|
|
13242
13385
|
}
|
|
13243
13386
|
for (const child of n.children) {
|
|
13244
13387
|
if (child)
|
|
13245
|
-
|
|
13388
|
+
stack.push(child);
|
|
13246
13389
|
}
|
|
13247
|
-
}
|
|
13248
|
-
traverse(node);
|
|
13390
|
+
}
|
|
13249
13391
|
return methods;
|
|
13250
13392
|
}
|
|
13251
13393
|
getMethodName(method) {
|
|
@@ -13290,9 +13432,20 @@ class ConstantPropagator {
|
|
|
13290
13432
|
}
|
|
13291
13433
|
}
|
|
13292
13434
|
visit(node) {
|
|
13435
|
+
const stack = [node];
|
|
13436
|
+
while (stack.length > 0) {
|
|
13437
|
+
const current = stack.pop();
|
|
13438
|
+
if (this.visitOne(current))
|
|
13439
|
+
continue;
|
|
13440
|
+
for (let i2 = current.children.length - 1;i2 >= 0; i2--) {
|
|
13441
|
+
stack.push(current.children[i2]);
|
|
13442
|
+
}
|
|
13443
|
+
}
|
|
13444
|
+
}
|
|
13445
|
+
visitOne(node) {
|
|
13293
13446
|
const line = getNodeLine(node);
|
|
13294
13447
|
if (this.unreachableLines.has(line)) {
|
|
13295
|
-
return;
|
|
13448
|
+
return true;
|
|
13296
13449
|
}
|
|
13297
13450
|
if (this.conditionStack.length > 0 && !this.lineConditions.has(line)) {
|
|
13298
13451
|
this.lineConditions.set(line, this.conditionStack[this.conditionStack.length - 1]);
|
|
@@ -13301,42 +13454,40 @@ class ConstantPropagator {
|
|
|
13301
13454
|
case "method_declaration":
|
|
13302
13455
|
case "constructor_declaration":
|
|
13303
13456
|
this.handleMethodDeclaration(node);
|
|
13304
|
-
return;
|
|
13457
|
+
return true;
|
|
13305
13458
|
case "local_variable_declaration":
|
|
13306
13459
|
this.handleVariableDeclaration(node);
|
|
13307
|
-
|
|
13460
|
+
return false;
|
|
13308
13461
|
case "assignment_expression":
|
|
13309
13462
|
this.handleAssignment(node);
|
|
13310
|
-
|
|
13463
|
+
return false;
|
|
13311
13464
|
case "update_expression":
|
|
13312
13465
|
this.handleUpdateExpression(node);
|
|
13313
|
-
|
|
13466
|
+
return false;
|
|
13314
13467
|
case "if_statement":
|
|
13315
13468
|
this.handleIfStatement(node);
|
|
13316
|
-
return;
|
|
13469
|
+
return true;
|
|
13317
13470
|
case "switch_expression":
|
|
13318
13471
|
case "switch_statement":
|
|
13319
13472
|
this.handleSwitch(node);
|
|
13320
|
-
return;
|
|
13473
|
+
return true;
|
|
13321
13474
|
case "ternary_expression":
|
|
13322
13475
|
this.handleTernary(node);
|
|
13323
|
-
|
|
13476
|
+
return false;
|
|
13324
13477
|
case "expression_statement":
|
|
13325
13478
|
this.handleExpressionStatement(node);
|
|
13326
|
-
|
|
13479
|
+
return false;
|
|
13327
13480
|
case "for_statement":
|
|
13328
13481
|
case "enhanced_for_statement":
|
|
13329
13482
|
case "while_statement":
|
|
13330
13483
|
case "do_statement":
|
|
13331
13484
|
this.handleLoopStatement(node);
|
|
13332
|
-
return;
|
|
13485
|
+
return true;
|
|
13333
13486
|
case "synchronized_statement":
|
|
13334
13487
|
this.handleSynchronizedStatement(node);
|
|
13335
|
-
return;
|
|
13488
|
+
return true;
|
|
13336
13489
|
default:
|
|
13337
|
-
|
|
13338
|
-
this.visit(child);
|
|
13339
|
-
}
|
|
13490
|
+
return false;
|
|
13340
13491
|
}
|
|
13341
13492
|
}
|
|
13342
13493
|
handleMethodDeclaration(node) {
|
|
@@ -14038,6 +14189,21 @@ class ConstantPropagator {
|
|
|
14038
14189
|
return null;
|
|
14039
14190
|
}
|
|
14040
14191
|
isTaintedExpression(node) {
|
|
14192
|
+
const stack = [node];
|
|
14193
|
+
while (stack.length > 0) {
|
|
14194
|
+
const current = stack.pop();
|
|
14195
|
+
const result = this.isTaintedExpressionStep(current);
|
|
14196
|
+
if (result === true)
|
|
14197
|
+
return true;
|
|
14198
|
+
if (result === false)
|
|
14199
|
+
continue;
|
|
14200
|
+
for (let i2 = current.children.length - 1;i2 >= 0; i2--) {
|
|
14201
|
+
stack.push(current.children[i2]);
|
|
14202
|
+
}
|
|
14203
|
+
}
|
|
14204
|
+
return false;
|
|
14205
|
+
}
|
|
14206
|
+
isTaintedExpressionStep(node) {
|
|
14041
14207
|
const text = getNodeText2(node, this.source);
|
|
14042
14208
|
if (node.type === "method_invocation") {
|
|
14043
14209
|
const nameNode = node.childForFieldName("name");
|
|
@@ -14290,12 +14456,7 @@ class ConstantPropagator {
|
|
|
14290
14456
|
}
|
|
14291
14457
|
return isTainted;
|
|
14292
14458
|
}
|
|
14293
|
-
|
|
14294
|
-
if (this.isTaintedExpression(child)) {
|
|
14295
|
-
return true;
|
|
14296
|
-
}
|
|
14297
|
-
}
|
|
14298
|
-
return false;
|
|
14459
|
+
return;
|
|
14299
14460
|
}
|
|
14300
14461
|
checkCollectionTaint(node) {
|
|
14301
14462
|
const objectNode = node.childForFieldName("object");
|
|
@@ -14448,7 +14609,7 @@ function isFalsePositive(result, sinkLine, taintedVar) {
|
|
|
14448
14609
|
if (varValue && varValue.type !== "unknown" && !result.tainted.has(taintedVar)) {
|
|
14449
14610
|
return { isFalsePositive: true, reason: `variable_is_constant: ${varValue.value}` };
|
|
14450
14611
|
}
|
|
14451
|
-
if (result.symbols.
|
|
14612
|
+
if (result.symbols.has(taintedVar) && !result.tainted.has(taintedVar)) {
|
|
14452
14613
|
return { isFalsePositive: true, reason: "variable_not_tainted" };
|
|
14453
14614
|
}
|
|
14454
14615
|
return { isFalsePositive: false, reason: null };
|
|
@@ -14597,19 +14758,18 @@ class BaseLanguagePlugin {
|
|
|
14597
14758
|
}
|
|
14598
14759
|
findNodes(root, type) {
|
|
14599
14760
|
const nodes = [];
|
|
14600
|
-
const
|
|
14601
|
-
|
|
14602
|
-
|
|
14603
|
-
|
|
14761
|
+
const stack = [root];
|
|
14762
|
+
while (stack.length > 0) {
|
|
14763
|
+
const node = stack.pop();
|
|
14764
|
+
if (node.type === type) {
|
|
14765
|
+
nodes.push(node);
|
|
14604
14766
|
}
|
|
14605
|
-
|
|
14606
|
-
|
|
14607
|
-
|
|
14608
|
-
|
|
14609
|
-
cursor.gotoParent();
|
|
14767
|
+
for (let i2 = node.childCount - 1;i2 >= 0; i2--) {
|
|
14768
|
+
const child = node.child(i2);
|
|
14769
|
+
if (child)
|
|
14770
|
+
stack.push(child);
|
|
14610
14771
|
}
|
|
14611
|
-
}
|
|
14612
|
-
visit();
|
|
14772
|
+
}
|
|
14613
14773
|
return nodes;
|
|
14614
14774
|
}
|
|
14615
14775
|
findChildByType(node, type) {
|
|
@@ -14930,17 +15090,18 @@ class JavaPlugin extends BaseLanguagePlugin {
|
|
|
14930
15090
|
}
|
|
14931
15091
|
}
|
|
14932
15092
|
};
|
|
14933
|
-
const
|
|
15093
|
+
const stack = [tree.rootNode];
|
|
15094
|
+
while (stack.length > 0) {
|
|
15095
|
+
const node = stack.pop();
|
|
14934
15096
|
if (node.type === "field_declaration" || node.type === "local_variable_declaration") {
|
|
14935
15097
|
collectDecl(node);
|
|
14936
15098
|
}
|
|
14937
15099
|
for (let i2 = 0;i2 < node.childCount; i2++) {
|
|
14938
15100
|
const child = node.child(i2);
|
|
14939
15101
|
if (child)
|
|
14940
|
-
|
|
15102
|
+
stack.push(child);
|
|
14941
15103
|
}
|
|
14942
|
-
}
|
|
14943
|
-
walk(tree.rootNode);
|
|
15104
|
+
}
|
|
14944
15105
|
this._typeMapCache.set(tree, map);
|
|
14945
15106
|
return map;
|
|
14946
15107
|
}
|
|
@@ -19455,16 +19616,19 @@ function extractHtmlContent(rootNode) {
|
|
|
19455
19616
|
return { scriptBlocks, eventHandlers };
|
|
19456
19617
|
}
|
|
19457
19618
|
function walkNode(node, scriptBlocks, eventHandlers) {
|
|
19458
|
-
|
|
19459
|
-
|
|
19460
|
-
|
|
19461
|
-
|
|
19462
|
-
|
|
19463
|
-
|
|
19464
|
-
|
|
19465
|
-
|
|
19466
|
-
|
|
19467
|
-
|
|
19619
|
+
const stack = [node];
|
|
19620
|
+
while (stack.length > 0) {
|
|
19621
|
+
const current = stack.pop();
|
|
19622
|
+
if (current.type === "script_element") {
|
|
19623
|
+
extractScriptBlock(current, scriptBlocks);
|
|
19624
|
+
}
|
|
19625
|
+
if (current.type === "element" || current.type === "self_closing_tag") {
|
|
19626
|
+
extractEventHandlers(current, eventHandlers);
|
|
19627
|
+
}
|
|
19628
|
+
for (let i2 = current.childCount - 1;i2 >= 0; i2--) {
|
|
19629
|
+
const child = current.child(i2);
|
|
19630
|
+
if (child)
|
|
19631
|
+
stack.push(child);
|
|
19468
19632
|
}
|
|
19469
19633
|
}
|
|
19470
19634
|
}
|
|
@@ -19569,13 +19733,16 @@ function runHtmlAttributeSecurityChecks(rootNode, filePath) {
|
|
|
19569
19733
|
return findings;
|
|
19570
19734
|
}
|
|
19571
19735
|
function walkForSecurityChecks(node, filePath, findings) {
|
|
19572
|
-
|
|
19573
|
-
|
|
19574
|
-
|
|
19575
|
-
|
|
19576
|
-
|
|
19577
|
-
|
|
19578
|
-
|
|
19736
|
+
const stack = [node];
|
|
19737
|
+
while (stack.length > 0) {
|
|
19738
|
+
const current = stack.pop();
|
|
19739
|
+
if (current.type === "element" || current.type === "self_closing_tag" || current.type === "script_element" || current.type === "style_element") {
|
|
19740
|
+
checkElement(current, filePath, findings);
|
|
19741
|
+
}
|
|
19742
|
+
for (let i2 = current.childCount - 1;i2 >= 0; i2--) {
|
|
19743
|
+
const child = current.child(i2);
|
|
19744
|
+
if (child)
|
|
19745
|
+
stack.push(child);
|
|
19579
19746
|
}
|
|
19580
19747
|
}
|
|
19581
19748
|
}
|
|
@@ -20514,6 +20681,40 @@ function buildJavaScriptTaintedVars(sourceCode, language) {
|
|
|
20514
20681
|
}
|
|
20515
20682
|
return tainted;
|
|
20516
20683
|
}
|
|
20684
|
+
function buildRustTaintedVars(sourceCode, seedVars) {
|
|
20685
|
+
const derived = new Map;
|
|
20686
|
+
const knownTainted = new Set(seedVars);
|
|
20687
|
+
const lines = sourceCode.split(`
|
|
20688
|
+
`);
|
|
20689
|
+
let changed = true;
|
|
20690
|
+
while (changed) {
|
|
20691
|
+
changed = false;
|
|
20692
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
20693
|
+
const line = lines[i2];
|
|
20694
|
+
const trimmed = line.trimStart();
|
|
20695
|
+
if (trimmed.startsWith("//"))
|
|
20696
|
+
continue;
|
|
20697
|
+
const letMatch = line.match(/^\s*let\s+(?:mut\s+)?([A-Za-z_]\w*)\s*(?::\s*[^=]+)?=\s*(.+?)(?:;|$)/);
|
|
20698
|
+
const assignMatch = !letMatch ? line.match(/^\s*([A-Za-z_]\w*)\s*=\s*(.+?)(?:;|$)/) : null;
|
|
20699
|
+
const m = letMatch ?? assignMatch;
|
|
20700
|
+
if (!m)
|
|
20701
|
+
continue;
|
|
20702
|
+
const lhs = m[1];
|
|
20703
|
+
const rhs = m[2];
|
|
20704
|
+
if (lhs === "if" || lhs === "while" || lhs === "for" || lhs === "match" || lhs === "return")
|
|
20705
|
+
continue;
|
|
20706
|
+
if (knownTainted.has(lhs))
|
|
20707
|
+
continue;
|
|
20708
|
+
const ref = [...knownTainted].some((v) => new RegExp(`\\b${v}\\b`).test(rhs));
|
|
20709
|
+
if (ref) {
|
|
20710
|
+
derived.set(lhs, i2 + 1);
|
|
20711
|
+
knownTainted.add(lhs);
|
|
20712
|
+
changed = true;
|
|
20713
|
+
}
|
|
20714
|
+
}
|
|
20715
|
+
}
|
|
20716
|
+
return derived;
|
|
20717
|
+
}
|
|
20517
20718
|
var BASH_POSITIONAL_PARAMS = new Set(["1", "2", "3", "4", "5", "6", "7", "8", "9", "@", "*"]);
|
|
20518
20719
|
var BASH_UNTRUSTED_ENV_PATTERNS = [
|
|
20519
20720
|
/^USER_INPUT$/i,
|
|
@@ -20936,7 +21137,23 @@ function evaluateSimpleExpression(expr, symbols) {
|
|
|
20936
21137
|
}
|
|
20937
21138
|
function isStringLiteralExpression(expr) {
|
|
20938
21139
|
const trimmed = expr.trim();
|
|
20939
|
-
|
|
21140
|
+
if (trimmed.length < 2)
|
|
21141
|
+
return false;
|
|
21142
|
+
const quote = trimmed[0];
|
|
21143
|
+
if (quote !== '"' && quote !== "'")
|
|
21144
|
+
return false;
|
|
21145
|
+
let i2 = 1;
|
|
21146
|
+
while (i2 < trimmed.length) {
|
|
21147
|
+
const c = trimmed[i2];
|
|
21148
|
+
if (c === "\\") {
|
|
21149
|
+
i2 += 2;
|
|
21150
|
+
continue;
|
|
21151
|
+
}
|
|
21152
|
+
if (c === quote)
|
|
21153
|
+
return i2 === trimmed.length - 1;
|
|
21154
|
+
i2++;
|
|
21155
|
+
}
|
|
21156
|
+
return false;
|
|
20940
21157
|
}
|
|
20941
21158
|
function filterCleanArraySinks(sinks, calls, taintedArrayElements, symbols) {
|
|
20942
21159
|
const callsByLine = new Map;
|
|
@@ -21367,7 +21584,7 @@ class TaintPropagationPass {
|
|
|
21367
21584
|
flows.push(f);
|
|
21368
21585
|
}
|
|
21369
21586
|
}
|
|
21370
|
-
const exprScanFlows = detectExpressionScanFlows(calls, sources, sinks, constProp.unreachableLines, ctx.code, ctx.language) ?? [];
|
|
21587
|
+
const exprScanFlows = detectExpressionScanFlows(calls, sources, sinks, sanitizers, constProp.unreachableLines, ctx.code, ctx.language) ?? [];
|
|
21371
21588
|
for (const f of exprScanFlows) {
|
|
21372
21589
|
if (flows.some((x) => x.source_line === f.source_line && x.sink_line === f.sink_line && x.sink_type === f.sink_type))
|
|
21373
21590
|
continue;
|
|
@@ -21585,13 +21802,70 @@ function detectParameterSinkFlows(types, calls, sources, sinks, unreachableLines
|
|
|
21585
21802
|
}
|
|
21586
21803
|
return flows;
|
|
21587
21804
|
}
|
|
21588
|
-
function detectExpressionScanFlows(calls, sources, sinks, unreachableLines, code, language) {
|
|
21805
|
+
function detectExpressionScanFlows(calls, sources, sinks, sanitizers, unreachableLines, code, language) {
|
|
21589
21806
|
const flows = [];
|
|
21590
21807
|
const sourcesWithVar = sources.filter((s) => typeof s.variable === "string" && s.variable.length > 0);
|
|
21591
21808
|
if (sourcesWithVar.length === 0)
|
|
21592
21809
|
return flows;
|
|
21810
|
+
const aliasSanitizedFor = new Map;
|
|
21593
21811
|
if (language === "python" && typeof code === "string") {
|
|
21594
21812
|
const derived = buildPythonTaintedVars(code);
|
|
21813
|
+
if (derived.size > 0) {
|
|
21814
|
+
let anchor = sourcesWithVar[0];
|
|
21815
|
+
for (const s of sourcesWithVar) {
|
|
21816
|
+
if (s.line < anchor.line)
|
|
21817
|
+
anchor = s;
|
|
21818
|
+
}
|
|
21819
|
+
const existingVars = new Set(sourcesWithVar.map((s) => s.variable));
|
|
21820
|
+
for (const [varName] of derived) {
|
|
21821
|
+
if (!varName || existingVars.has(varName))
|
|
21822
|
+
continue;
|
|
21823
|
+
sourcesWithVar.push({
|
|
21824
|
+
...anchor,
|
|
21825
|
+
variable: varName
|
|
21826
|
+
});
|
|
21827
|
+
existingVars.add(varName);
|
|
21828
|
+
}
|
|
21829
|
+
if (sanitizers && sanitizers.length > 0) {
|
|
21830
|
+
const sanitizersByLine = new Map;
|
|
21831
|
+
for (const s of sanitizers) {
|
|
21832
|
+
const arr = sanitizersByLine.get(s.line) ?? [];
|
|
21833
|
+
arr.push(s);
|
|
21834
|
+
sanitizersByLine.set(s.line, arr);
|
|
21835
|
+
}
|
|
21836
|
+
const codeLines = code.split(`
|
|
21837
|
+
`);
|
|
21838
|
+
for (const [varName, originLine] of derived) {
|
|
21839
|
+
const lineSans = sanitizersByLine.get(originLine);
|
|
21840
|
+
if (!lineSans || lineSans.length === 0)
|
|
21841
|
+
continue;
|
|
21842
|
+
const lineText = codeLines[originLine - 1] ?? "";
|
|
21843
|
+
const rhsMatch = lineText.match(/^\s*\w+\s*=\s*(.+)$/);
|
|
21844
|
+
if (!rhsMatch)
|
|
21845
|
+
continue;
|
|
21846
|
+
const rhs = rhsMatch[1];
|
|
21847
|
+
for (const san of lineSans) {
|
|
21848
|
+
const sanMatch = san.method.match(/^(?:(\w+)\.)?(\w+)\(\)$/);
|
|
21849
|
+
if (!sanMatch)
|
|
21850
|
+
continue;
|
|
21851
|
+
const sanName = sanMatch[1] ? `${sanMatch[1]}.${sanMatch[2]}` : sanMatch[2];
|
|
21852
|
+
if (!rhs.includes(`${sanName}(`))
|
|
21853
|
+
continue;
|
|
21854
|
+
let set = aliasSanitizedFor.get(varName);
|
|
21855
|
+
if (!set) {
|
|
21856
|
+
set = new Set;
|
|
21857
|
+
aliasSanitizedFor.set(varName, set);
|
|
21858
|
+
}
|
|
21859
|
+
for (const t of san.sanitizes)
|
|
21860
|
+
set.add(t);
|
|
21861
|
+
}
|
|
21862
|
+
}
|
|
21863
|
+
}
|
|
21864
|
+
}
|
|
21865
|
+
}
|
|
21866
|
+
if (language === "rust" && typeof code === "string") {
|
|
21867
|
+
const seedVars = new Set(sourcesWithVar.map((s) => s.variable));
|
|
21868
|
+
const derived = buildRustTaintedVars(code, seedVars);
|
|
21595
21869
|
if (derived.size > 0) {
|
|
21596
21870
|
let anchor = sourcesWithVar[0];
|
|
21597
21871
|
for (const s of sourcesWithVar) {
|
|
@@ -21643,6 +21917,9 @@ function detectExpressionScanFlows(calls, sources, sinks, unreachableLines, code
|
|
|
21643
21917
|
continue;
|
|
21644
21918
|
if (flows.some((f) => f.source_line === source.line && f.sink_line === sink.line && f.sink_type === sink.type))
|
|
21645
21919
|
continue;
|
|
21920
|
+
if (aliasSanitizedFor.get(source.variable)?.has(sink.type)) {
|
|
21921
|
+
break;
|
|
21922
|
+
}
|
|
21646
21923
|
flows.push({
|
|
21647
21924
|
source_line: source.line,
|
|
21648
21925
|
sink_line: sink.line,
|
|
@@ -22216,6 +22493,9 @@ class InterproceduralPass {
|
|
|
22216
22493
|
}
|
|
22217
22494
|
}
|
|
22218
22495
|
}
|
|
22496
|
+
if (additionalSinks.length > 0) {
|
|
22497
|
+
attachSourceLineCode([], additionalSinks, ctx.code);
|
|
22498
|
+
}
|
|
22219
22499
|
return { additionalSinks, additionalFlows, interprocedural };
|
|
22220
22500
|
}
|
|
22221
22501
|
}
|
|
@@ -26755,6 +27035,77 @@ function isPotentialPojo(type) {
|
|
|
26755
27035
|
return first >= 65 && first <= 90;
|
|
26756
27036
|
}
|
|
26757
27037
|
|
|
27038
|
+
// ../circle-ir/dist/analysis/passes/insecure-cookie-pass.js
|
|
27039
|
+
var COOKIE_RESPONSE_RECEIVERS = new Set([
|
|
27040
|
+
"res",
|
|
27041
|
+
"response",
|
|
27042
|
+
"reply"
|
|
27043
|
+
]);
|
|
27044
|
+
var SECURE_TRUE_RE = /\bsecure\s*:\s*true\b/;
|
|
27045
|
+
var HTTPONLY_TRUE_RE = /\bhttpOnly\s*:\s*true\b/i;
|
|
27046
|
+
|
|
27047
|
+
class InsecureCookiePass {
|
|
27048
|
+
name = "insecure-cookie";
|
|
27049
|
+
category = "security";
|
|
27050
|
+
run(ctx) {
|
|
27051
|
+
const { graph, language } = ctx;
|
|
27052
|
+
if (language !== "javascript" && language !== "typescript") {
|
|
27053
|
+
return { insecureCookies: [] };
|
|
27054
|
+
}
|
|
27055
|
+
const file = graph.ir.meta.file;
|
|
27056
|
+
const insecureCookies = [];
|
|
27057
|
+
for (const call of graph.ir.calls) {
|
|
27058
|
+
if (call.method_name !== "cookie")
|
|
27059
|
+
continue;
|
|
27060
|
+
const receiver = call.receiver ?? "";
|
|
27061
|
+
if (!COOKIE_RESPONSE_RECEIVERS.has(receiver))
|
|
27062
|
+
continue;
|
|
27063
|
+
if (call.arguments.length < 2)
|
|
27064
|
+
continue;
|
|
27065
|
+
const opts = call.arguments.find((a) => a.position === 2);
|
|
27066
|
+
const optsExpr = (opts?.expression ?? "").trim();
|
|
27067
|
+
const optionsPresent = optsExpr.length > 0;
|
|
27068
|
+
const missingSecure = !SECURE_TRUE_RE.test(optsExpr);
|
|
27069
|
+
const missingHttpOnly = !HTTPONLY_TRUE_RE.test(optsExpr);
|
|
27070
|
+
if (!missingSecure && !missingHttpOnly)
|
|
27071
|
+
continue;
|
|
27072
|
+
const line = call.location.line;
|
|
27073
|
+
insecureCookies.push({
|
|
27074
|
+
line,
|
|
27075
|
+
receiver,
|
|
27076
|
+
missingSecure,
|
|
27077
|
+
missingHttpOnly,
|
|
27078
|
+
optionsPresent
|
|
27079
|
+
});
|
|
27080
|
+
const missing = [];
|
|
27081
|
+
if (missingSecure)
|
|
27082
|
+
missing.push("`secure: true`");
|
|
27083
|
+
if (missingHttpOnly)
|
|
27084
|
+
missing.push("`httpOnly: true`");
|
|
27085
|
+
ctx.addFinding({
|
|
27086
|
+
id: `${this.name}-${file}-${line}`,
|
|
27087
|
+
pass: this.name,
|
|
27088
|
+
category: this.category,
|
|
27089
|
+
rule_id: this.name,
|
|
27090
|
+
cwe: "CWE-614",
|
|
27091
|
+
severity: "medium",
|
|
27092
|
+
level: "warning",
|
|
27093
|
+
message: `Cookie set without ${missing.join(" and ")} — vulnerable to ` + `cleartext transmission (CWE-614) and client-side JS access ` + `(CWE-1004).`,
|
|
27094
|
+
file,
|
|
27095
|
+
line,
|
|
27096
|
+
fix: 'Pass `{ secure: true, httpOnly: true, sameSite: "lax" }` as the ' + "third argument to `res.cookie()`.",
|
|
27097
|
+
evidence: {
|
|
27098
|
+
receiver,
|
|
27099
|
+
options_present: optionsPresent,
|
|
27100
|
+
missing_secure: missingSecure,
|
|
27101
|
+
missing_http_only: missingHttpOnly
|
|
27102
|
+
}
|
|
27103
|
+
});
|
|
27104
|
+
}
|
|
27105
|
+
return { insecureCookies };
|
|
27106
|
+
}
|
|
27107
|
+
}
|
|
27108
|
+
|
|
26758
27109
|
// ../circle-ir/dist/graph/import-graph.js
|
|
26759
27110
|
function dirname(filePath) {
|
|
26760
27111
|
const idx = filePath.lastIndexOf("/");
|
|
@@ -27865,6 +28216,8 @@ async function analyze(code, filePath, language, options = {}) {
|
|
|
27865
28216
|
pipeline.add(new SecurityHeadersPass(passOpts.securityHeaders));
|
|
27866
28217
|
if (!disabledPasses.has("spring4shell"))
|
|
27867
28218
|
pipeline.add(new Spring4ShellPass);
|
|
28219
|
+
if (!disabledPasses.has("insecure-cookie"))
|
|
28220
|
+
pipeline.add(new InsecureCookiePass);
|
|
27868
28221
|
const { results, findings } = pipeline.run(graph, code, language, config);
|
|
27869
28222
|
const sinkFilter = results.get("sink-filter");
|
|
27870
28223
|
const interProc = results.get("interprocedural");
|
|
@@ -28058,7 +28411,7 @@ var colors = {
|
|
|
28058
28411
|
};
|
|
28059
28412
|
|
|
28060
28413
|
// src/version.ts
|
|
28061
|
-
var version = "3.
|
|
28414
|
+
var version = "3.49.0";
|
|
28062
28415
|
|
|
28063
28416
|
// src/formatters.ts
|
|
28064
28417
|
var SINK_SEVERITY = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cognium-dev",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.49.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.49.0"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@types/node": "^25.5.0",
|