cognium-dev 4.9.10 → 4.9.12
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 +238 -31
- package/package.json +4 -4
package/dist/cli.js
CHANGED
|
@@ -5338,6 +5338,27 @@ var CSHARP_COMMAND_EXECUTE_METHODS = new Set([
|
|
|
5338
5338
|
"ExecuteReaderAsync",
|
|
5339
5339
|
"ExecuteNonQueryAsync"
|
|
5340
5340
|
]);
|
|
5341
|
+
var CSHARP_RECEIVER_URL_METHODS = new Set([
|
|
5342
|
+
"GetAsync",
|
|
5343
|
+
"PostAsync",
|
|
5344
|
+
"PutAsync",
|
|
5345
|
+
"PatchAsync",
|
|
5346
|
+
"DeleteAsync",
|
|
5347
|
+
"HeadAsync",
|
|
5348
|
+
"GetStringAsync",
|
|
5349
|
+
"GetByteArrayAsync",
|
|
5350
|
+
"GetStreamAsync",
|
|
5351
|
+
"GetJsonAsync"
|
|
5352
|
+
]);
|
|
5353
|
+
var CSHARP_HEADER_RECEIVER_RE = /(^|\.)Headers$/;
|
|
5354
|
+
function csharpBareName(node) {
|
|
5355
|
+
if (node.type === "generic_name") {
|
|
5356
|
+
const id = node.childForFieldName("name") ?? node.namedChild(0);
|
|
5357
|
+
if (id)
|
|
5358
|
+
return getNodeText(id);
|
|
5359
|
+
}
|
|
5360
|
+
return getNodeText(node);
|
|
5361
|
+
}
|
|
5341
5362
|
function extractCSharpCalls(tree, cache) {
|
|
5342
5363
|
const calls = [];
|
|
5343
5364
|
const typeMap = buildCSharpReceiverTypeMap(tree, cache);
|
|
@@ -5349,16 +5370,22 @@ function extractCSharpCalls(tree, cache) {
|
|
|
5349
5370
|
if (fn?.type === "member_access_expression") {
|
|
5350
5371
|
const nameNode = fn.childForFieldName("name");
|
|
5351
5372
|
const exprNode = fn.childForFieldName("expression");
|
|
5352
|
-
methodName = nameNode ?
|
|
5373
|
+
methodName = nameNode ? csharpBareName(nameNode) : "unknown";
|
|
5353
5374
|
receiver = exprNode ? getNodeText(exprNode) : null;
|
|
5354
5375
|
} else if (fn) {
|
|
5355
|
-
methodName =
|
|
5376
|
+
methodName = csharpBareName(fn);
|
|
5356
5377
|
}
|
|
5357
5378
|
const argsNode = inv.childForFieldName("arguments");
|
|
5358
5379
|
let args2 = argsNode ? extractCSharpArguments(argsNode) : [];
|
|
5359
5380
|
if (receiver && CSHARP_COMMAND_EXECUTE_METHODS.has(methodName)) {
|
|
5360
5381
|
args2 = [{ position: 0, expression: receiver, variable: receiver, literal: null, value: null }, ...args2];
|
|
5361
5382
|
}
|
|
5383
|
+
if (methodName === "Add" && receiver && CSHARP_HEADER_RECEIVER_RE.test(receiver)) {
|
|
5384
|
+
methodName = "AddHeader";
|
|
5385
|
+
}
|
|
5386
|
+
if (receiver && args2.length === 0 && CSHARP_RECEIVER_URL_METHODS.has(methodName)) {
|
|
5387
|
+
args2 = [{ position: 0, expression: receiver, variable: receiver, literal: null, value: null }];
|
|
5388
|
+
}
|
|
5362
5389
|
calls.push({
|
|
5363
5390
|
method_name: methodName,
|
|
5364
5391
|
receiver,
|
|
@@ -5374,7 +5401,7 @@ function extractCSharpCalls(tree, cache) {
|
|
|
5374
5401
|
const typeNode = creation.childForFieldName("type");
|
|
5375
5402
|
const argsNode = creation.childForFieldName("arguments");
|
|
5376
5403
|
calls.push({
|
|
5377
|
-
method_name: typeNode ?
|
|
5404
|
+
method_name: typeNode ? csharpBareName(typeNode) : "unknown",
|
|
5378
5405
|
receiver: null,
|
|
5379
5406
|
receiver_type: null,
|
|
5380
5407
|
receiver_type_fqn: null,
|
|
@@ -5387,6 +5414,41 @@ function extractCSharpCalls(tree, cache) {
|
|
|
5387
5414
|
const assignments = getNodesFromCache(tree.rootNode, "assignment_expression", cache);
|
|
5388
5415
|
for (const asn of assignments) {
|
|
5389
5416
|
const left = asn.childForFieldName("left");
|
|
5417
|
+
if (left?.type === "element_access_expression") {
|
|
5418
|
+
const target = left.childForFieldName("expression");
|
|
5419
|
+
const right2 = asn.childForFieldName("right");
|
|
5420
|
+
if (!target || !right2)
|
|
5421
|
+
continue;
|
|
5422
|
+
if (!CSHARP_HEADER_RECEIVER_RE.test(getNodeText(target)))
|
|
5423
|
+
continue;
|
|
5424
|
+
const subscript = left.childForFieldName("subscript") ?? left.namedChild(1);
|
|
5425
|
+
const rhsText2 = getNodeText(right2);
|
|
5426
|
+
calls.push({
|
|
5427
|
+
method_name: "AddHeader",
|
|
5428
|
+
receiver: getNodeText(target),
|
|
5429
|
+
receiver_type: null,
|
|
5430
|
+
receiver_type_fqn: null,
|
|
5431
|
+
arguments: [
|
|
5432
|
+
{
|
|
5433
|
+
position: 0,
|
|
5434
|
+
expression: subscript ? getNodeText(subscript) : "",
|
|
5435
|
+
variable: null,
|
|
5436
|
+
literal: subscript ? getNodeText(subscript) : null,
|
|
5437
|
+
value: null
|
|
5438
|
+
},
|
|
5439
|
+
{
|
|
5440
|
+
position: 1,
|
|
5441
|
+
expression: rhsText2,
|
|
5442
|
+
variable: right2.type === "identifier" ? rhsText2 : null,
|
|
5443
|
+
literal: right2.type === "string_literal" ? rhsText2 : null,
|
|
5444
|
+
value: null
|
|
5445
|
+
}
|
|
5446
|
+
],
|
|
5447
|
+
location: { line: asn.startPosition.row + 1, column: asn.startPosition.column },
|
|
5448
|
+
in_method: findEnclosingMethod(asn)
|
|
5449
|
+
});
|
|
5450
|
+
continue;
|
|
5451
|
+
}
|
|
5390
5452
|
if (left?.type !== "member_access_expression")
|
|
5391
5453
|
continue;
|
|
5392
5454
|
const nameNode = left.childForFieldName("name");
|
|
@@ -12474,6 +12536,17 @@ var DEFAULT_SINKS = [
|
|
|
12474
12536
|
{ method: "ExecuteSqlRawAsync", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
12475
12537
|
{ method: "FromSqlRaw", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
12476
12538
|
{ method: "FromSqlRawAsync", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
12539
|
+
{ method: "Query", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
12540
|
+
{ method: "QueryAsync", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
12541
|
+
{ method: "QueryFirst", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
12542
|
+
{ method: "QueryFirstAsync", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
12543
|
+
{ method: "QueryFirstOrDefault", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
12544
|
+
{ method: "QueryFirstOrDefaultAsync", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
12545
|
+
{ method: "QuerySingle", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
12546
|
+
{ method: "QuerySingleOrDefault", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
12547
|
+
{ method: "QueryMultiple", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
12548
|
+
{ method: "Execute", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
12549
|
+
{ method: "ExecuteAsync", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
12477
12550
|
{ method: "CommandText", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
12478
12551
|
{ method: "Filter", type: "ldap_injection", cwe: "CWE-90", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12479
12552
|
{ method: "ExecuteScalar", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
@@ -12515,12 +12588,16 @@ var DEFAULT_SINKS = [
|
|
|
12515
12588
|
{ method: "DeleteAsync", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12516
12589
|
{ method: "GetStringAsync", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12517
12590
|
{ method: "GetByteArrayAsync", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12591
|
+
{ method: "GetJsonAsync", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12592
|
+
{ method: "PatchAsync", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12593
|
+
{ method: "HeadAsync", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12518
12594
|
{ method: "GetStreamAsync", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12519
12595
|
{ method: "SendAsync", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12520
12596
|
{ method: "DownloadString", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12521
12597
|
{ method: "DownloadData", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12522
12598
|
{ method: "DownloadFile", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [1], languages: ["csharp"] },
|
|
12523
12599
|
{ method: "Create", class: "WebRequest", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12600
|
+
{ method: "RestClient", class: "constructor", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12524
12601
|
{ method: "EvaluateAsync", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
12525
12602
|
{ method: "RunAsync", class: "CSharpScript", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
12526
12603
|
{ method: "Load", class: "Assembly", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
@@ -12538,6 +12615,7 @@ var DEFAULT_SINKS = [
|
|
|
12538
12615
|
{ method: "Write", class: "Response", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12539
12616
|
{ method: "HtmlString", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12540
12617
|
{ method: "MarkupString", class: "constructor", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12618
|
+
{ method: "Content", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12541
12619
|
{ method: "Format", class: "String", type: "format_string", cwe: "CWE-134", severity: "medium", arg_positions: [0], languages: ["csharp"] },
|
|
12542
12620
|
{ method: "DirectorySearcher", type: "ldap_injection", cwe: "CWE-90", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12543
12621
|
{ method: "DirectoryEntry", type: "ldap_injection", cwe: "CWE-90", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
@@ -12546,12 +12624,18 @@ var DEFAULT_SINKS = [
|
|
|
12546
12624
|
{ method: "AddHeader", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["csharp"] },
|
|
12547
12625
|
{ method: "AppendHeader", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["csharp"] },
|
|
12548
12626
|
{ method: "Parse", class: "BsonDocument", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12627
|
+
{ method: "BsonJavaScript", class: "constructor", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12549
12628
|
{ method: "LogInformation", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0], languages: ["csharp"] },
|
|
12550
12629
|
{ method: "LogWarning", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0], languages: ["csharp"] },
|
|
12551
12630
|
{ method: "LogError", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0], languages: ["csharp"] },
|
|
12552
12631
|
{ method: "LogDebug", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0], languages: ["csharp"] },
|
|
12553
12632
|
{ method: "LogCritical", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0], languages: ["csharp"] },
|
|
12554
12633
|
{ method: "LogTrace", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0], languages: ["csharp"] },
|
|
12634
|
+
{ method: "IsMatch", class: "Regex", type: "redos", cwe: "CWE-1333", severity: "medium", arg_positions: [1], languages: ["csharp"] },
|
|
12635
|
+
{ method: "Match", class: "Regex", type: "redos", cwe: "CWE-1333", severity: "medium", arg_positions: [1], languages: ["csharp"] },
|
|
12636
|
+
{ method: "Matches", class: "Regex", type: "redos", cwe: "CWE-1333", severity: "medium", arg_positions: [1], languages: ["csharp"] },
|
|
12637
|
+
{ method: "Replace", class: "Regex", type: "redos", cwe: "CWE-1333", severity: "medium", arg_positions: [1], languages: ["csharp"] },
|
|
12638
|
+
{ method: "Regex", class: "constructor", type: "redos", cwe: "CWE-1333", severity: "medium", arg_positions: [0], languages: ["csharp"] },
|
|
12555
12639
|
{ method: "Log", class: "ILogger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [1], languages: ["csharp"] },
|
|
12556
12640
|
{ method: "SelectSingleNode", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12557
12641
|
{ method: "SelectNodes", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
@@ -12691,6 +12775,8 @@ var DEFAULT_SANITIZERS = [
|
|
|
12691
12775
|
{ method: "encodeToString", removes: ["sql_injection", "command_injection", "xss", "path_traversal", "code_injection"] },
|
|
12692
12776
|
{ method: "encodeHexString", removes: ["sql_injection", "command_injection", "xss", "path_traversal", "code_injection"] },
|
|
12693
12777
|
{ method: "encodeForURL", removes: ["xss", "ssrf", "open_redirect"] },
|
|
12778
|
+
{ method: "IsLocalUrl", removes: ["open_redirect"] },
|
|
12779
|
+
{ method: "LocalRedirect", removes: ["open_redirect"] },
|
|
12694
12780
|
{ method: "encodeURL", removes: ["xss", "ssrf", "open_redirect"] },
|
|
12695
12781
|
{ method: "urlEncode", removes: ["xss", "ssrf", "open_redirect"] },
|
|
12696
12782
|
{ method: "escapeUrl", removes: ["xss", "ssrf", "open_redirect"] },
|
|
@@ -13106,6 +13192,22 @@ var PYTHON_TAINTED_PATTERNS = [
|
|
|
13106
13192
|
{ pattern: /\brequest\.path_params\b/, sourceType: "http_param" },
|
|
13107
13193
|
{ pattern: /\binput\s*\(/, sourceType: "io_input" }
|
|
13108
13194
|
];
|
|
13195
|
+
function dropCSharpObjectCarriedWaypoints(sinks, calls) {
|
|
13196
|
+
const zeroArgCtors = new Set;
|
|
13197
|
+
for (const call of calls) {
|
|
13198
|
+
if (call.is_constructor && call.arguments.length === 0) {
|
|
13199
|
+
zeroArgCtors.add(`${call.location.line}:${call.method_name}`);
|
|
13200
|
+
}
|
|
13201
|
+
}
|
|
13202
|
+
return sinks.filter((sink) => {
|
|
13203
|
+
if (sink.type !== "sql_injection")
|
|
13204
|
+
return true;
|
|
13205
|
+
if (sink.method && zeroArgCtors.has(`${sink.line}:${sink.method}`)) {
|
|
13206
|
+
return false;
|
|
13207
|
+
}
|
|
13208
|
+
return true;
|
|
13209
|
+
});
|
|
13210
|
+
}
|
|
13109
13211
|
function analyzeTaint(calls, types, config = getDefaultConfig(), typeHierarchy, language, code) {
|
|
13110
13212
|
const sourceLines = code !== undefined ? code.split(`
|
|
13111
13213
|
`) : undefined;
|
|
@@ -13113,8 +13215,9 @@ function analyzeTaint(calls, types, config = getDefaultConfig(), typeHierarchy,
|
|
|
13113
13215
|
let sinkPatterns = expandPromisifyAliases(config.sinks, sourceLines, language);
|
|
13114
13216
|
sinkPatterns = expandIndirectEvalAliases(sinkPatterns, sourceLines, language);
|
|
13115
13217
|
const sinks = findSinks(calls, sinkPatterns, typeHierarchy, language, sourceLines, types);
|
|
13218
|
+
const gatedSinks = language === "csharp" ? dropCSharpObjectCarriedWaypoints(sinks, calls) : sinks;
|
|
13116
13219
|
const sanitizers = findSanitizers(calls, types, config.sanitizers, sourceLines);
|
|
13117
|
-
return { sources, sinks, sanitizers };
|
|
13220
|
+
return { sources, sinks: gatedSinks, sanitizers };
|
|
13118
13221
|
}
|
|
13119
13222
|
function sinkPatternAppliesTo(pattern, language) {
|
|
13120
13223
|
if (language === undefined)
|
|
@@ -13399,7 +13502,7 @@ function findSources(calls, types, patterns, sourceLines, language) {
|
|
|
13399
13502
|
}
|
|
13400
13503
|
const sourceMap = new Map;
|
|
13401
13504
|
for (const source of sources) {
|
|
13402
|
-
const key = `${source.line}:${source.type}`;
|
|
13505
|
+
const key = source.type === "interprocedural_param" && source.variable ? `${source.line}:${source.type}:${source.variable}` : `${source.line}:${source.type}`;
|
|
13403
13506
|
const existing = sourceMap.get(key);
|
|
13404
13507
|
if (!existing || source.confidence > existing.confidence) {
|
|
13405
13508
|
sourceMap.set(key, source);
|
|
@@ -14077,6 +14180,19 @@ var CWE_78_RECEIVER_ALLOWLIST = new Set([
|
|
|
14077
14180
|
"ProcessExecutor",
|
|
14078
14181
|
"RuntimeUtil"
|
|
14079
14182
|
]);
|
|
14183
|
+
function isRegexReceiver(receiver, sourceLines) {
|
|
14184
|
+
const r = (receiver ?? "").trim();
|
|
14185
|
+
if (r.length === 0)
|
|
14186
|
+
return false;
|
|
14187
|
+
if (r.startsWith("/") && /\/[a-z]*$/.test(r))
|
|
14188
|
+
return true;
|
|
14189
|
+
if (/^(?:new\s+)?RegExp\s*\(/.test(r))
|
|
14190
|
+
return true;
|
|
14191
|
+
if (!/^[A-Za-z_$][\w$]*$/.test(r) || !sourceLines)
|
|
14192
|
+
return false;
|
|
14193
|
+
const decl = new RegExp(`(?:const|let|var)\\s+${escapeRe(r)}\\s*=\\s*(?:/|(?:new\\s+)?RegExp\\s*\\()`);
|
|
14194
|
+
return sourceLines.some((l) => decl.test(l));
|
|
14195
|
+
}
|
|
14080
14196
|
function isFunctionCallbackArgument(arg) {
|
|
14081
14197
|
if (arg.literal !== null && arg.literal !== undefined)
|
|
14082
14198
|
return false;
|
|
@@ -14284,6 +14400,12 @@ function findSinks(calls, patterns, typeHierarchy, language, sourceLines, types)
|
|
|
14284
14400
|
continue;
|
|
14285
14401
|
}
|
|
14286
14402
|
}
|
|
14403
|
+
if (pattern.type === "command_injection" && call.method_name === "exec" && (language === "javascript" || language === "typescript") && isRegexReceiver(call.receiver, sourceLines)) {
|
|
14404
|
+
continue;
|
|
14405
|
+
}
|
|
14406
|
+
if (pattern.type === "code_injection" && language === "python" && call.method_name === "compile" && call.receiver && call.receiver !== "builtins") {
|
|
14407
|
+
continue;
|
|
14408
|
+
}
|
|
14287
14409
|
if (isSafeGoJsonUnmarshalCall(call, pattern, language, sourceLines)) {
|
|
14288
14410
|
continue;
|
|
14289
14411
|
}
|
|
@@ -15388,12 +15510,12 @@ function walkBackwardDefs(startDefId, chainsByToDef, defById, options = {}) {
|
|
|
15388
15510
|
// node_modules/circle-ir/dist/analysis/findings.js
|
|
15389
15511
|
function canSourceReachSink(sourceType, sinkType) {
|
|
15390
15512
|
const sourceToSinkMapping = {
|
|
15391
|
-
http_param: ["sql_injection", "command_injection", "path_traversal", "xss", "xpath_injection", "ldap_injection", "ssrf", "mybatis_mapper_call", "code_injection", "crlf", "mass_assignment", "open_redirect", "trust_boundary", "deserialization", "log_injection", "format_string", "nosql_injection", "prompt_injection"],
|
|
15513
|
+
http_param: ["sql_injection", "command_injection", "path_traversal", "xss", "xpath_injection", "ldap_injection", "ssrf", "mybatis_mapper_call", "code_injection", "crlf", "mass_assignment", "open_redirect", "trust_boundary", "deserialization", "xxe", "log_injection", "format_string", "nosql_injection", "prompt_injection"],
|
|
15392
15514
|
http_body: ["sql_injection", "command_injection", "deserialization", "xxe", "xss", "code_injection", "mybatis_mapper_call", "crlf", "mass_assignment", "open_redirect", "trust_boundary", "log_injection", "format_string", "nosql_injection", "prompt_injection"],
|
|
15393
15515
|
http_header: ["sql_injection", "xss", "ssrf", "mybatis_mapper_call", "code_injection", "crlf", "open_redirect", "trust_boundary", "log_injection", "format_string", "nosql_injection", "prompt_injection"],
|
|
15394
15516
|
http_cookie: ["sql_injection", "xss", "mybatis_mapper_call", "code_injection", "crlf", "open_redirect", "trust_boundary", "log_injection", "format_string", "nosql_injection", "prompt_injection"],
|
|
15395
15517
|
http_path: ["path_traversal", "sql_injection", "ssrf", "mybatis_mapper_call", "open_redirect", "trust_boundary", "xss", "log_injection", "format_string", "prompt_injection"],
|
|
15396
|
-
http_query: ["sql_injection", "command_injection", "xss", "ssrf", "mybatis_mapper_call", "code_injection", "crlf", "mass_assignment", "open_redirect", "trust_boundary", "deserialization", "log_injection", "format_string", "nosql_injection", "prompt_injection"],
|
|
15518
|
+
http_query: ["sql_injection", "command_injection", "xss", "ssrf", "mybatis_mapper_call", "code_injection", "crlf", "mass_assignment", "open_redirect", "trust_boundary", "deserialization", "xxe", "log_injection", "format_string", "nosql_injection", "prompt_injection"],
|
|
15397
15519
|
io_input: ["command_injection", "path_traversal", "deserialization", "xxe", "code_injection", "xss", "ssrf", "log_injection", "format_string", "prompt_injection"],
|
|
15398
15520
|
env_input: ["command_injection", "path_traversal"],
|
|
15399
15521
|
db_input: ["xss", "sql_injection", "log_injection"],
|
|
@@ -17801,6 +17923,9 @@ function findInitialTaint(sources, callsByLine, defsByLine) {
|
|
|
17801
17923
|
for (const source of sources) {
|
|
17802
17924
|
const defsOnLine = defsByLine.get(source.line) ?? [];
|
|
17803
17925
|
for (const def of defsOnLine) {
|
|
17926
|
+
if (source.type === "interprocedural_param" && source.variable && def.kind === "param" && def.variable !== source.variable) {
|
|
17927
|
+
continue;
|
|
17928
|
+
}
|
|
17804
17929
|
tainted.push({
|
|
17805
17930
|
variable: def.variable,
|
|
17806
17931
|
defId: def.id,
|
|
@@ -23170,13 +23295,6 @@ class RustPlugin extends BaseLanguagePlugin {
|
|
|
23170
23295
|
severity: "high",
|
|
23171
23296
|
argPositions: [0]
|
|
23172
23297
|
},
|
|
23173
|
-
{
|
|
23174
|
-
method: "format!",
|
|
23175
|
-
type: "format_string",
|
|
23176
|
-
cwe: "CWE-134",
|
|
23177
|
-
severity: "medium",
|
|
23178
|
-
argPositions: [0]
|
|
23179
|
-
},
|
|
23180
23298
|
{
|
|
23181
23299
|
method: "from_raw_parts",
|
|
23182
23300
|
type: "unsafe_memory",
|
|
@@ -26134,12 +26252,21 @@ function findCSharpRequestSources(sourceCode, language) {
|
|
|
26134
26252
|
const requestReadRe = /\bRequest\s*\.\s*(?:Query|Form|Headers|Cookies|QueryString|RouteValues|Body|Files|Params)\b/;
|
|
26135
26253
|
const consoleReadRe = /\bConsole\s*\.\s*ReadLine\s*\(/;
|
|
26136
26254
|
const envReadRe = /\bEnvironment\s*\.\s*GetEnvironmentVariables?\s*(?:\(|\[)/;
|
|
26255
|
+
const formFileParams = new Set;
|
|
26256
|
+
const formFileDeclRe = /\bIFormFile\s+([A-Za-z_]\w*)/g;
|
|
26257
|
+
for (const line of lines) {
|
|
26258
|
+
const re = new RegExp(formFileDeclRe.source, "g");
|
|
26259
|
+
let d;
|
|
26260
|
+
while ((d = re.exec(line)) !== null)
|
|
26261
|
+
formFileParams.add(d[1]);
|
|
26262
|
+
}
|
|
26263
|
+
const formFileReadRe = formFileParams.size > 0 ? new RegExp(`\\b(?:${[...formFileParams].join("|")})\\s*\\.\\s*(?:FileName|ContentType)\\b`) : null;
|
|
26137
26264
|
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
26138
26265
|
const m = assignRe.exec(lines[i2]);
|
|
26139
26266
|
if (!m)
|
|
26140
26267
|
continue;
|
|
26141
26268
|
const [, varName, rhs] = m;
|
|
26142
|
-
const type = requestReadRe.test(rhs) ? "http_param" : consoleReadRe.test(rhs) ? "io_input" : envReadRe.test(rhs) ? "env_input" : null;
|
|
26269
|
+
const type = requestReadRe.test(rhs) ? "http_param" : formFileReadRe?.test(rhs) ? "http_param" : consoleReadRe.test(rhs) ? "io_input" : envReadRe.test(rhs) ? "env_input" : null;
|
|
26143
26270
|
if (!type)
|
|
26144
26271
|
continue;
|
|
26145
26272
|
const lineNumber = i2 + 1;
|
|
@@ -35729,7 +35856,7 @@ class TaintPropagationPass {
|
|
|
35729
35856
|
for (const f of paramFlows) {
|
|
35730
35857
|
pushIfNew(f);
|
|
35731
35858
|
}
|
|
35732
|
-
const exprScanFlows = detectExpressionScanFlows(calls, sources, sinks, sanitizers, constProp.unreachableLines, constProp.tainted, ctx.code, ctx.language) ?? [];
|
|
35859
|
+
const exprScanFlows = detectExpressionScanFlows(calls, sources, sinks, sanitizers, constProp.unreachableLines, constProp.tainted, ctx.code, ctx.language, types) ?? [];
|
|
35733
35860
|
for (const f of exprScanFlows) {
|
|
35734
35861
|
if (flowKeys.has(flowKey(f)))
|
|
35735
35862
|
continue;
|
|
@@ -35893,6 +36020,35 @@ class TaintPropagationPass {
|
|
|
35893
36020
|
return bestByKey.get(key) === f;
|
|
35894
36021
|
});
|
|
35895
36022
|
}
|
|
36023
|
+
if (ctx.language === "csharp" && finalFlows.length > 1) {
|
|
36024
|
+
const CSHARP_ADO_EXECUTE = /^Execute(?:Reader|NonQuery|Scalar)(?:Async)?$/;
|
|
36025
|
+
const commandTextReceiverByLine = new Map;
|
|
36026
|
+
const execLinesByReceiver = new Map;
|
|
36027
|
+
for (const call of calls) {
|
|
36028
|
+
const receiver = (call.receiver ?? "").trim();
|
|
36029
|
+
if (!receiver)
|
|
36030
|
+
continue;
|
|
36031
|
+
if (call.method_name === "CommandText") {
|
|
36032
|
+
commandTextReceiverByLine.set(call.location.line, receiver);
|
|
36033
|
+
} else if (CSHARP_ADO_EXECUTE.test(call.method_name)) {
|
|
36034
|
+
const lines = execLinesByReceiver.get(receiver) ?? [];
|
|
36035
|
+
lines.push(call.location.line);
|
|
36036
|
+
execLinesByReceiver.set(receiver, lines);
|
|
36037
|
+
}
|
|
36038
|
+
}
|
|
36039
|
+
if (commandTextReceiverByLine.size > 0) {
|
|
36040
|
+
const reportedSqlSinkLines = new Set(finalFlows.filter((f) => f.sink_type === "sql_injection").map((f) => f.sink_line));
|
|
36041
|
+
finalFlows = finalFlows.filter((f) => {
|
|
36042
|
+
if (f.sink_type !== "sql_injection")
|
|
36043
|
+
return true;
|
|
36044
|
+
const receiver = commandTextReceiverByLine.get(f.sink_line);
|
|
36045
|
+
if (receiver === undefined)
|
|
36046
|
+
return true;
|
|
36047
|
+
const execLines = execLinesByReceiver.get(receiver) ?? [];
|
|
36048
|
+
return !execLines.some((line) => line > f.sink_line && reportedSqlSinkLines.has(line));
|
|
36049
|
+
});
|
|
36050
|
+
}
|
|
36051
|
+
}
|
|
35896
36052
|
return { flows: finalFlows };
|
|
35897
36053
|
}
|
|
35898
36054
|
}
|
|
@@ -36359,7 +36515,7 @@ function isReassignedToLiteralBetween(code, variable, srcLine, sinkLine) {
|
|
|
36359
36515
|
}
|
|
36360
36516
|
return false;
|
|
36361
36517
|
}
|
|
36362
|
-
function detectExpressionScanFlows(calls, sources, sinks, sanitizers, unreachableLines, tainted, code, language) {
|
|
36518
|
+
function detectExpressionScanFlows(calls, sources, sinks, sanitizers, unreachableLines, tainted, code, language, types) {
|
|
36363
36519
|
const flows = [];
|
|
36364
36520
|
const sourcesWithVar = sources.filter((s) => typeof s.variable === "string" && s.variable.length > 0);
|
|
36365
36521
|
const aliasSanitizedFor = new Map;
|
|
@@ -36642,13 +36798,37 @@ function detectExpressionScanFlows(calls, sources, sinks, sanitizers, unreachabl
|
|
|
36642
36798
|
if (s.line < anchor.line)
|
|
36643
36799
|
anchor = s;
|
|
36644
36800
|
}
|
|
36801
|
+
const methodAt = (line) => {
|
|
36802
|
+
for (const t of types ?? []) {
|
|
36803
|
+
for (const m of t.methods) {
|
|
36804
|
+
if (line >= m.start_line && line <= m.end_line)
|
|
36805
|
+
return m.name;
|
|
36806
|
+
}
|
|
36807
|
+
}
|
|
36808
|
+
return null;
|
|
36809
|
+
};
|
|
36645
36810
|
const existingVars = new Set(sourcesWithVar.map((s) => s.variable));
|
|
36646
|
-
for (const [varName] of derived) {
|
|
36811
|
+
for (const [varName, derivedLine] of derived) {
|
|
36647
36812
|
if (!varName || existingVars.has(varName))
|
|
36648
36813
|
continue;
|
|
36814
|
+
const owner = methodAt(derivedLine);
|
|
36815
|
+
let scopedAnchor = anchor;
|
|
36816
|
+
if (owner) {
|
|
36817
|
+
let best;
|
|
36818
|
+
for (const s of sourcesWithVar) {
|
|
36819
|
+
const sOwner = s.in_method ?? methodAt(s.line);
|
|
36820
|
+
if (sOwner !== owner)
|
|
36821
|
+
continue;
|
|
36822
|
+
if (!best || s.line < best.line)
|
|
36823
|
+
best = s;
|
|
36824
|
+
}
|
|
36825
|
+
if (best)
|
|
36826
|
+
scopedAnchor = best;
|
|
36827
|
+
}
|
|
36649
36828
|
sourcesWithVar.push({
|
|
36650
|
-
...
|
|
36651
|
-
variable: varName
|
|
36829
|
+
...scopedAnchor,
|
|
36830
|
+
variable: varName,
|
|
36831
|
+
...owner ? { in_method: owner } : {}
|
|
36652
36832
|
});
|
|
36653
36833
|
existingVars.add(varName);
|
|
36654
36834
|
}
|
|
@@ -48398,6 +48578,13 @@ function mergeMavenInheritance(modules, scanRoot) {
|
|
|
48398
48578
|
byBuildFile.set(normalize(m.buildFile), m);
|
|
48399
48579
|
}
|
|
48400
48580
|
}
|
|
48581
|
+
const ownSignals = new Map;
|
|
48582
|
+
for (const [buildFile, m] of byBuildFile) {
|
|
48583
|
+
ownSignals.set(buildFile, {
|
|
48584
|
+
urls: [...m.signals.distributionUrls],
|
|
48585
|
+
plugins: [...m.signals.plugins]
|
|
48586
|
+
});
|
|
48587
|
+
}
|
|
48401
48588
|
for (const child of modules) {
|
|
48402
48589
|
if (child.buildSystem !== "maven")
|
|
48403
48590
|
continue;
|
|
@@ -48405,7 +48592,7 @@ function mergeMavenInheritance(modules, scanRoot) {
|
|
|
48405
48592
|
continue;
|
|
48406
48593
|
const inheritedUrls = new Set;
|
|
48407
48594
|
const inheritedPlugins = new Set;
|
|
48408
|
-
walkParents(child, byBuildFile, normalizedScanRoot, inheritedUrls, inheritedPlugins);
|
|
48595
|
+
walkParents(child, byBuildFile, ownSignals, normalizedScanRoot, inheritedUrls, inheritedPlugins);
|
|
48409
48596
|
if (inheritedUrls.size === 0 && inheritedPlugins.size === 0)
|
|
48410
48597
|
continue;
|
|
48411
48598
|
const existingUrls = new Set(child.signals.distributionUrls);
|
|
@@ -48420,7 +48607,7 @@ function mergeMavenInheritance(modules, scanRoot) {
|
|
|
48420
48607
|
}
|
|
48421
48608
|
}
|
|
48422
48609
|
}
|
|
48423
|
-
function walkParents(start2, byBuildFile, scanRoot, outUrls, outPlugins) {
|
|
48610
|
+
function walkParents(start2, byBuildFile, ownSignals, scanRoot, outUrls, outPlugins) {
|
|
48424
48611
|
const visited = new Set([normalize(start2.buildFile)]);
|
|
48425
48612
|
let current = start2;
|
|
48426
48613
|
for (let depth = 0;depth < MAX_DEPTH; depth++) {
|
|
@@ -48442,10 +48629,13 @@ function walkParents(start2, byBuildFile, scanRoot, outUrls, outPlugins) {
|
|
|
48442
48629
|
const parent = byBuildFile.get(parentBuildFile);
|
|
48443
48630
|
if (!parent)
|
|
48444
48631
|
return;
|
|
48445
|
-
|
|
48446
|
-
|
|
48447
|
-
|
|
48448
|
-
|
|
48632
|
+
const parentOwn = ownSignals.get(parentBuildFile);
|
|
48633
|
+
if (parentOwn) {
|
|
48634
|
+
for (const u of parentOwn.urls)
|
|
48635
|
+
outUrls.add(u);
|
|
48636
|
+
for (const p of parentOwn.plugins)
|
|
48637
|
+
outPlugins.add(p);
|
|
48638
|
+
}
|
|
48449
48639
|
current = parent;
|
|
48450
48640
|
}
|
|
48451
48641
|
}
|
|
@@ -48821,7 +49011,7 @@ var colors = {
|
|
|
48821
49011
|
};
|
|
48822
49012
|
|
|
48823
49013
|
// src/version.ts
|
|
48824
|
-
var version = "4.9.
|
|
49014
|
+
var version = "4.9.12";
|
|
48825
49015
|
|
|
48826
49016
|
// src/formatters.ts
|
|
48827
49017
|
var LIBRARY_API_SURFACE_TAG2 = "library-api-surface:caller-responsibility";
|
|
@@ -49374,8 +49564,8 @@ function generateSarifResults(results, crossFileData) {
|
|
|
49374
49564
|
|
|
49375
49565
|
// src/build-info.ts
|
|
49376
49566
|
var buildInfo = {
|
|
49377
|
-
gitSha: "
|
|
49378
|
-
builtAt: "2026-09-
|
|
49567
|
+
gitSha: "344dd1f",
|
|
49568
|
+
builtAt: "2026-09-10T17:10:54.335Z"
|
|
49379
49569
|
};
|
|
49380
49570
|
|
|
49381
49571
|
// src/utils/args.ts
|
|
@@ -49719,6 +49909,22 @@ var LANG_MAP = {
|
|
|
49719
49909
|
".html": "html",
|
|
49720
49910
|
".htm": "html"
|
|
49721
49911
|
};
|
|
49912
|
+
var VULN_SEVERITY_RANK = { critical: 3, high: 2, medium: 1, low: 0 };
|
|
49913
|
+
function dedupeVulnerabilities(vulns) {
|
|
49914
|
+
const best = new Map;
|
|
49915
|
+
const order = [];
|
|
49916
|
+
for (const v of vulns) {
|
|
49917
|
+
const key = `${v.type}:${v.line}`;
|
|
49918
|
+
const current = best.get(key);
|
|
49919
|
+
if (current === undefined) {
|
|
49920
|
+
best.set(key, v);
|
|
49921
|
+
order.push(key);
|
|
49922
|
+
} else if ((VULN_SEVERITY_RANK[v.severity] ?? -1) > (VULN_SEVERITY_RANK[current.severity] ?? -1)) {
|
|
49923
|
+
best.set(key, v);
|
|
49924
|
+
}
|
|
49925
|
+
}
|
|
49926
|
+
return order.map((k) => best.get(k));
|
|
49927
|
+
}
|
|
49722
49928
|
function detectLanguage7(filePath) {
|
|
49723
49929
|
const ext = extname(filePath).toLowerCase();
|
|
49724
49930
|
return LANG_MAP[ext] || null;
|
|
@@ -49813,7 +50019,7 @@ async function scanFile(filePath, language, analyzeOpts) {
|
|
|
49813
50019
|
...finding.tags && finding.tags.length > 0 ? { tags: [...finding.tags] } : {}
|
|
49814
50020
|
});
|
|
49815
50021
|
}
|
|
49816
|
-
return { file: filePath, vulnerabilities };
|
|
50022
|
+
return { file: filePath, vulnerabilities: dedupeVulnerabilities(vulnerabilities) };
|
|
49817
50023
|
} catch (error) {
|
|
49818
50024
|
return {
|
|
49819
50025
|
file: filePath,
|
|
@@ -49856,7 +50062,7 @@ async function scanProject(files, language, analyzeOpts, crossFileBudgetMs) {
|
|
|
49856
50062
|
...finding.tags && finding.tags.length > 0 ? { tags: [...finding.tags] } : {}
|
|
49857
50063
|
});
|
|
49858
50064
|
}
|
|
49859
|
-
return { file, vulnerabilities };
|
|
50065
|
+
return { file, vulnerabilities: dedupeVulnerabilities(vulnerabilities) };
|
|
49860
50066
|
});
|
|
49861
50067
|
return {
|
|
49862
50068
|
results,
|
|
@@ -50756,6 +50962,7 @@ export {
|
|
|
50756
50962
|
loadConfig,
|
|
50757
50963
|
isTestFile2 as isTestFile,
|
|
50758
50964
|
detectLanguage7 as detectLanguage,
|
|
50965
|
+
dedupeVulnerabilities,
|
|
50759
50966
|
convertConfigToPassOptions,
|
|
50760
50967
|
applySuppressionsToResults,
|
|
50761
50968
|
PASS_REGISTRY
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cognium-dev",
|
|
3
|
-
"version": "4.9.
|
|
3
|
+
"version": "4.9.12",
|
|
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",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"test": "bun test",
|
|
15
15
|
"clean": "rm -rf dist cognium-dev cognium-dev-* *.bun-build wasm",
|
|
16
16
|
"typecheck": "tsc --noEmit",
|
|
17
|
-
"version": "node -e \"const v = require('./package.json').version; require('fs').writeFileSync('src/version.ts', '/**\\n * Version information\\n *\\n * Kept in sync with package.json via the \\`version\\` npm lifecycle script.\\n * Do not edit manually
|
|
17
|
+
"version": "node -e \"const v = require('./package.json').version; require('fs').writeFileSync('src/version.ts', '/**\\n * Version information\\n *\\n * Kept in sync with package.json via the \\`version\\` npm lifecycle script.\\n * Do not edit manually \u2014 use \\`npm version patch|minor|major\\` instead.\\n */\\nexport const version = \\x27' + v + '\\x27;\\n')\" && git add src/version.ts",
|
|
18
18
|
"dogfood": "bun run src/cli.ts scan src/ -q",
|
|
19
19
|
"prepublishOnly": "bun run build"
|
|
20
20
|
},
|
|
@@ -65,8 +65,8 @@
|
|
|
65
65
|
"registry": "https://registry.npmjs.org/"
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
|
-
"@cognium/project-profile-detect": "1.1.
|
|
69
|
-
"circle-ir": "4.9.
|
|
68
|
+
"@cognium/project-profile-detect": "1.1.1",
|
|
69
|
+
"circle-ir": "4.9.12"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@types/node": "^25.5.0",
|