cognium-dev 4.9.28 → 4.9.29
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 +143 -27
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -3689,6 +3689,26 @@ function extractTypes(tree, cache, language) {
|
|
|
3689
3689
|
}
|
|
3690
3690
|
return extractJavaTypes(tree, cache);
|
|
3691
3691
|
}
|
|
3692
|
+
function csharpMemberNodes(body2) {
|
|
3693
|
+
if (!body2)
|
|
3694
|
+
return [];
|
|
3695
|
+
const out2 = [];
|
|
3696
|
+
const visit = (parent, depth) => {
|
|
3697
|
+
if (depth > 32)
|
|
3698
|
+
return;
|
|
3699
|
+
for (let i2 = 0;i2 < parent.childCount; i2++) {
|
|
3700
|
+
const c = parent.child(i2);
|
|
3701
|
+
if (!c)
|
|
3702
|
+
continue;
|
|
3703
|
+
if (c.type.startsWith("preproc_"))
|
|
3704
|
+
visit(c, depth + 1);
|
|
3705
|
+
else
|
|
3706
|
+
out2.push(c);
|
|
3707
|
+
}
|
|
3708
|
+
};
|
|
3709
|
+
visit(body2, 0);
|
|
3710
|
+
return out2;
|
|
3711
|
+
}
|
|
3692
3712
|
function extractCSharpTypes(tree, cache) {
|
|
3693
3713
|
const types = [];
|
|
3694
3714
|
const KINDS = {
|
|
@@ -3705,9 +3725,8 @@ function extractCSharpTypes(tree, cache) {
|
|
|
3705
3725
|
const methods = [];
|
|
3706
3726
|
const fields = extractCSharpFields(body2);
|
|
3707
3727
|
if (body2) {
|
|
3708
|
-
for (
|
|
3709
|
-
|
|
3710
|
-
if (!m || m.type !== "method_declaration")
|
|
3728
|
+
for (const m of csharpMemberNodes(body2)) {
|
|
3729
|
+
if (m.type !== "method_declaration")
|
|
3711
3730
|
continue;
|
|
3712
3731
|
const mName = m.childForFieldName("name");
|
|
3713
3732
|
const paramList = m.childForFieldName("parameters");
|
|
@@ -3761,10 +3780,7 @@ function extractCSharpFields(body2) {
|
|
|
3761
3780
|
const fields = [];
|
|
3762
3781
|
if (!body2)
|
|
3763
3782
|
return fields;
|
|
3764
|
-
for (
|
|
3765
|
-
const c = body2.child(i2);
|
|
3766
|
-
if (!c)
|
|
3767
|
-
continue;
|
|
3783
|
+
for (const c of csharpMemberNodes(body2)) {
|
|
3768
3784
|
if (c.type === "field_declaration") {
|
|
3769
3785
|
let varDecl = null;
|
|
3770
3786
|
for (let k = 0;k < c.childCount; k++) {
|
|
@@ -5351,6 +5367,15 @@ function extractCalls(tree, cache, language) {
|
|
|
5351
5367
|
function buildCSharpReceiverTypeMap(tree, cache) {
|
|
5352
5368
|
const map = new Map;
|
|
5353
5369
|
const simple = (t) => t.replace(/<[^>]*>/g, "").split(".").pop()?.trim() ?? t;
|
|
5370
|
+
for (const prm of getNodesFromCache(tree.rootNode, "parameter", cache)) {
|
|
5371
|
+
const nameNode = prm.childForFieldName("name");
|
|
5372
|
+
const typeNode = prm.childForFieldName("type");
|
|
5373
|
+
if (nameNode?.type !== "identifier" || !typeNode)
|
|
5374
|
+
continue;
|
|
5375
|
+
const t = getNodeText(typeNode);
|
|
5376
|
+
if (t && t !== "var")
|
|
5377
|
+
map.set(getNodeText(nameNode), simple(t));
|
|
5378
|
+
}
|
|
5354
5379
|
for (const vd of getNodesFromCache(tree.rootNode, "variable_declaration", cache)) {
|
|
5355
5380
|
const typeNode = vd.childForFieldName("type");
|
|
5356
5381
|
const declaredType = typeNode ? getNodeText(typeNode) : null;
|
|
@@ -5387,6 +5412,7 @@ function findFirstDescendant(node, type) {
|
|
|
5387
5412
|
}
|
|
5388
5413
|
return null;
|
|
5389
5414
|
}
|
|
5415
|
+
var CSHARP_RESPONSE_TYPES = new Set(["HttpResponse", "HttpResponseBase"]);
|
|
5390
5416
|
var CSHARP_COMMAND_EXECUTE_METHODS = new Set([
|
|
5391
5417
|
"ExecuteScalar",
|
|
5392
5418
|
"ExecuteReader",
|
|
@@ -5547,7 +5573,8 @@ function extractCSharpCalls(tree, cache) {
|
|
|
5547
5573
|
continue;
|
|
5548
5574
|
} else if (propName === "StatusDescription") {
|
|
5549
5575
|
const recv = exprNode ? getNodeText(exprNode) : "";
|
|
5550
|
-
|
|
5576
|
+
const recvType = recv ? typeMap.get(recv) : undefined;
|
|
5577
|
+
if (!/(^|\.)(Response|HttpResponse|Context\.Response)$/.test(recv) && !(recvType && CSHARP_RESPONSE_TYPES.has(recvType)))
|
|
5551
5578
|
continue;
|
|
5552
5579
|
} else if (propName === "BaseAddress") {
|
|
5553
5580
|
const recv = exprNode ? getNodeText(exprNode) : null;
|
|
@@ -11207,6 +11234,14 @@ var DEFAULT_SOURCES = [
|
|
|
11207
11234
|
{ method: "nextLine", class: "Scanner", type: "io_input", severity: "high", return_tainted: true },
|
|
11208
11235
|
{ method: "next", class: "Scanner", type: "io_input", severity: "high", return_tainted: true },
|
|
11209
11236
|
{ method: "nextInt", class: "Scanner", type: "io_input", severity: "high", return_tainted: true },
|
|
11237
|
+
{ method: "ReadLine", class: "StreamReader", type: "io_input", severity: "high", return_tainted: true, languages: ["csharp"] },
|
|
11238
|
+
{ method: "ReadLineAsync", class: "StreamReader", type: "io_input", severity: "high", return_tainted: true, languages: ["csharp"] },
|
|
11239
|
+
{ method: "ReadToEnd", class: "StreamReader", type: "io_input", severity: "high", return_tainted: true, languages: ["csharp"] },
|
|
11240
|
+
{ method: "ReadToEndAsync", class: "StreamReader", type: "io_input", severity: "high", return_tainted: true, languages: ["csharp"] },
|
|
11241
|
+
{ method: "GetStream", class: "TcpClient", type: "network_input", severity: "high", return_tainted: true, languages: ["csharp"] },
|
|
11242
|
+
{ method: "AcceptTcpClient", class: "TcpListener", type: "network_input", severity: "high", return_tainted: true, languages: ["csharp"] },
|
|
11243
|
+
{ method: "OpenRead", class: "WebClient", type: "network_input", severity: "high", return_tainted: true, languages: ["csharp"] },
|
|
11244
|
+
{ method: "DownloadString", class: "WebClient", type: "network_input", severity: "high", return_tainted: true, languages: ["csharp"] },
|
|
11210
11245
|
{ method: "getString", class: "ResultSet", type: "db_input", severity: "medium", return_tainted: true },
|
|
11211
11246
|
{ method: "getObject", class: "ResultSet", type: "db_input", severity: "medium", return_tainted: true },
|
|
11212
11247
|
{ method: "getInt", class: "ResultSet", type: "db_input", severity: "medium", return_tainted: true },
|
|
@@ -12730,8 +12765,8 @@ var DEFAULT_SINKS = [
|
|
|
12730
12765
|
{ method: "OpenRead", class: "File", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12731
12766
|
{ method: "OpenWrite", class: "File", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12732
12767
|
{ method: "FileStream", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12733
|
-
{ method: "StreamReader", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12734
|
-
{ method: "StreamWriter", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12768
|
+
{ method: "StreamReader", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], safe_if_stream_arg_at: 0, languages: ["csharp"] },
|
|
12769
|
+
{ method: "StreamWriter", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], safe_if_stream_arg_at: 0, languages: ["csharp"] },
|
|
12735
12770
|
{ method: "Copy", class: "File", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0, 1], languages: ["csharp"] },
|
|
12736
12771
|
{ method: "Move", class: "File", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0, 1], languages: ["csharp"] },
|
|
12737
12772
|
{ method: "Delete", class: "File", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
@@ -12761,6 +12796,10 @@ var DEFAULT_SINKS = [
|
|
|
12761
12796
|
{ method: "DownloadFile", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [1], languages: ["csharp"] },
|
|
12762
12797
|
{ method: "Create", class: "WebRequest", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12763
12798
|
{ method: "RestClient", class: "constructor", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
12799
|
+
{ method: "CompileAssemblyFromSource", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [1, 2], languages: ["csharp"] },
|
|
12800
|
+
{ method: "CompileAssemblyFromSourceBatch", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [1, 2], languages: ["csharp"] },
|
|
12801
|
+
{ method: "ParseText", class: "CSharpSyntaxTree", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
12802
|
+
{ method: "ParseText", class: "SyntaxFactory", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
12764
12803
|
{ method: "EvaluateAsync", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
12765
12804
|
{ method: "RunAsync", class: "CSharpScript", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
12766
12805
|
{ method: "Load", class: "Assembly", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
@@ -14348,6 +14387,15 @@ function escapeRe(s) {
|
|
|
14348
14387
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
14349
14388
|
}
|
|
14350
14389
|
var TYPE_TOKEN_RE = /^new\s+(?:TypeReference|TypeToken)\s*<[\s\S]*>\s*\(\s*\)\s*\{\s*\}$/;
|
|
14390
|
+
function argIsStreamExpression(call, position) {
|
|
14391
|
+
const arg = call.arguments.find((a) => a.position === position);
|
|
14392
|
+
if (!arg)
|
|
14393
|
+
return false;
|
|
14394
|
+
const expr = (arg.expression ?? "").trim();
|
|
14395
|
+
if (!expr)
|
|
14396
|
+
return false;
|
|
14397
|
+
return /^new\s+[A-Za-z_][\w.]*Stream\s*\(/.test(expr) || /\.\s*Get(?:Response)?Stream\s*\(/.test(expr) || /\.\s*OpenReadStream\s*\(/.test(expr) || /\.\s*OpenRead\s*\(/.test(expr) || /\.\s*(?:Body|BaseStream)\s*$/.test(expr) || /^(?:[A-Za-z_]\w*\.)*[A-Za-z_]*[sS]tream\d*$/.test(expr);
|
|
14398
|
+
}
|
|
14351
14399
|
function argIsStringLiteral(call, position) {
|
|
14352
14400
|
const arg = call.arguments.find((a) => a.position === position);
|
|
14353
14401
|
if (!arg)
|
|
@@ -14618,6 +14666,9 @@ function findSinks(calls, patterns, typeHierarchy, language, sourceLines, types)
|
|
|
14618
14666
|
if (pattern.safe_if_string_literal_at !== undefined && argIsStringLiteral(call, pattern.safe_if_string_literal_at)) {
|
|
14619
14667
|
continue;
|
|
14620
14668
|
}
|
|
14669
|
+
if (pattern.safe_if_stream_arg_at !== undefined && argIsStreamExpression(call, pattern.safe_if_stream_arg_at)) {
|
|
14670
|
+
continue;
|
|
14671
|
+
}
|
|
14621
14672
|
if (pattern.type === "command_injection") {
|
|
14622
14673
|
if (call.is_constructor) {
|
|
14623
14674
|
if (!CWE_78_RECEIVER_ALLOWLIST.has(call.method_name)) {
|
|
@@ -26866,6 +26917,10 @@ function findCSharpRequestSources(sourceCode, language) {
|
|
|
26866
26917
|
const formFileDeclRe = /\bIFormFile\s+([A-Za-z_]\w*)/g;
|
|
26867
26918
|
const httpRequestReceivers = new Set(["Request"]);
|
|
26868
26919
|
const httpRequestDeclRe = /\b(?:HttpRequest|HttpRequestBase)\??\s+([A-Za-z_]\w*)/g;
|
|
26920
|
+
const streamReaderVars = new Set;
|
|
26921
|
+
const streamReaderDeclRe = /\b(?:StreamReader|TextReader|BinaryReader)\??\s+([A-Za-z_]\w*)/g;
|
|
26922
|
+
const dbReaderVars = new Set;
|
|
26923
|
+
const dbReaderDeclRe = /\b(?:SqlDataReader|DbDataReader|IDataReader|OdbcDataReader|OleDbDataReader)\??\s+([A-Za-z_]\w*)/g;
|
|
26869
26924
|
for (const line of lines) {
|
|
26870
26925
|
const formRe = new RegExp(formFileDeclRe.source, "g");
|
|
26871
26926
|
let d;
|
|
@@ -26874,15 +26929,25 @@ function findCSharpRequestSources(sourceCode, language) {
|
|
|
26874
26929
|
const reqRe = new RegExp(httpRequestDeclRe.source, "g");
|
|
26875
26930
|
while ((d = reqRe.exec(line)) !== null)
|
|
26876
26931
|
httpRequestReceivers.add(d[1]);
|
|
26877
|
-
|
|
26932
|
+
const srRe = new RegExp(streamReaderDeclRe.source, "g");
|
|
26933
|
+
while ((d = srRe.exec(line)) !== null)
|
|
26934
|
+
streamReaderVars.add(d[1]);
|
|
26935
|
+
const dbRe = new RegExp(dbReaderDeclRe.source, "g");
|
|
26936
|
+
while ((d = dbRe.exec(line)) !== null)
|
|
26937
|
+
dbReaderVars.add(d[1]);
|
|
26938
|
+
}
|
|
26939
|
+
const streamReadRe = streamReaderVars.size > 0 ? new RegExp(`\\b(?:${[...streamReaderVars].join("|")})\\s*\\.\\s*(?:ReadLine|ReadToEnd|ReadLineAsync|ReadToEndAsync|ReadBlock|Read)\\s*\\(`) : null;
|
|
26940
|
+
const dbReadRe = dbReaderVars.size > 0 ? new RegExp(`\\b(?:${[...dbReaderVars].join("|")})\\s*\\.\\s*(?:GetString|GetValue|GetInt32|GetInt64|GetDecimal|GetDateTime|GetFieldValue|\\[)`) : null;
|
|
26878
26941
|
const formFileReadRe = formFileParams.size > 0 ? new RegExp(`\\b(?:${[...formFileParams].join("|")})\\s*\\.\\s*(?:FileName|ContentType)\\b`) : null;
|
|
26879
26942
|
const requestReadRe = new RegExp(`\\b(?:${[...httpRequestReceivers].join("|")})\\s*\\.\\s*(?:Query|Form|Headers|Cookies|QueryString|RouteValues|Body|Files|Params)\\b`);
|
|
26880
|
-
const classify = (text) => requestReadRe.test(text) ? "http_param" : formFileReadRe?.test(text) ? "http_param" : consoleReadRe.test(text) ? "io_input" : envReadRe.test(text) ? "env_input" : null;
|
|
26943
|
+
const classify = (text) => requestReadRe.test(text) ? "http_param" : formFileReadRe?.test(text) ? "http_param" : consoleReadRe.test(text) ? "io_input" : envReadRe.test(text) ? "env_input" : streamReadRe?.test(text) ? "io_input" : dbReadRe?.test(text) ? "db_input" : null;
|
|
26881
26944
|
const inlineReads = [
|
|
26882
26945
|
[requestReadRe, "http_param"],
|
|
26883
26946
|
[formFileReadRe, "http_param"],
|
|
26884
26947
|
[consoleReadRe, "io_input"],
|
|
26885
|
-
[envReadRe, "env_input"]
|
|
26948
|
+
[envReadRe, "env_input"],
|
|
26949
|
+
[streamReadRe, "io_input"],
|
|
26950
|
+
[dbReadRe, "db_input"]
|
|
26886
26951
|
];
|
|
26887
26952
|
const inlineRead = (text) => {
|
|
26888
26953
|
const argsStart = text.indexOf("(");
|
|
@@ -26904,7 +26969,8 @@ function findCSharpRequestSources(sourceCode, language) {
|
|
|
26904
26969
|
const embeddedAssignRe = /(?:^|[{;])\s*(?:await\s+)?(?:using\s*\(?\s*)?(?:var\s+|[A-Za-z_][\w.<>\[\]]*\s+)?([A-Za-z_]\w*)\s*=(?!=)\s*([^;{}]+)/;
|
|
26905
26970
|
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
26906
26971
|
const m = assignRe.exec(lines[i2]);
|
|
26907
|
-
|
|
26972
|
+
const rhsCrossesBlock = m !== null && m[2].includes("{");
|
|
26973
|
+
if (!m || rhsCrossesBlock) {
|
|
26908
26974
|
const stmt = lines[i2];
|
|
26909
26975
|
if (stmt.includes("{") && !/^\s*(?:\/\/|\/\*|\*)/.test(stmt)) {
|
|
26910
26976
|
const emb = new RegExp(embeddedAssignRe.source, "g");
|
|
@@ -26922,7 +26988,7 @@ function findCSharpRequestSources(sourceCode, language) {
|
|
|
26922
26988
|
sources.push({
|
|
26923
26989
|
type: type3,
|
|
26924
26990
|
location: `${varName2} = ${rhs2.trim().substring(0, 50)}${rhs2.length > 50 ? "..." : ""}`,
|
|
26925
|
-
severity: "high",
|
|
26991
|
+
severity: type3 === "db_input" ? "medium" : "high",
|
|
26926
26992
|
line: lineNumber3,
|
|
26927
26993
|
confidence: 1,
|
|
26928
26994
|
variable: varName2
|
|
@@ -26945,7 +27011,7 @@ function findCSharpRequestSources(sourceCode, language) {
|
|
|
26945
27011
|
sources.push({
|
|
26946
27012
|
type: type2,
|
|
26947
27013
|
location: `${read} in ${code.substring(0, 50)}${code.length > 50 ? "..." : ""}`,
|
|
26948
|
-
severity: "high",
|
|
27014
|
+
severity: type2 === "db_input" ? "medium" : "high",
|
|
26949
27015
|
line: lineNumber2,
|
|
26950
27016
|
confidence: 1,
|
|
26951
27017
|
variable: "<inline>",
|
|
@@ -26963,7 +27029,7 @@ function findCSharpRequestSources(sourceCode, language) {
|
|
|
26963
27029
|
sources.push({
|
|
26964
27030
|
type,
|
|
26965
27031
|
location: `${varName} = ${rhs.trim().substring(0, 50)}${rhs.length > 50 ? "..." : ""}`,
|
|
26966
|
-
severity: "high",
|
|
27032
|
+
severity: type === "db_input" ? "medium" : "high",
|
|
26967
27033
|
line: lineNumber,
|
|
26968
27034
|
confidence: 1,
|
|
26969
27035
|
variable: varName
|
|
@@ -27157,7 +27223,7 @@ function findPythonAssignmentSources(sourceCode, language) {
|
|
|
27157
27223
|
sources.push({
|
|
27158
27224
|
type,
|
|
27159
27225
|
location: `${varName} = ${rhs.trim().substring(0, 50)}${rhs.length > 50 ? "..." : ""}`,
|
|
27160
|
-
severity: "high",
|
|
27226
|
+
severity: type === "db_input" ? "medium" : "high",
|
|
27161
27227
|
line: lineNumber,
|
|
27162
27228
|
confidence: 0.95,
|
|
27163
27229
|
variable: varName
|
|
@@ -37753,13 +37819,17 @@ function maskStringLiteralsForTokenScan(expr) {
|
|
|
37753
37819
|
}
|
|
37754
37820
|
return out2;
|
|
37755
37821
|
}
|
|
37822
|
+
function argsReferenceTaintedVar(expr, sources) {
|
|
37823
|
+
const codePart = expr.replace(/\$@?"(?:[^"\\]|\\.)*"/g, (lit) => " " + [...lit.matchAll(/\{([^}]*)\}/g)].map((x) => x[1]).join(" ") + " ").replace(/@?"(?:[^"\\]|\\.)*"/g, " ").replace(/\/\*[\s\S]*?\*\//g, " ").replace(/\/\/[^\n]*/g, " ");
|
|
37824
|
+
return sources.some((s) => new RegExp(`(?<![\\p{L}\\p{N}_])${s.variable.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?![\\p{L}\\p{N}_])`, "u").test(codePart));
|
|
37825
|
+
}
|
|
37756
37826
|
function detectExpressionScanFlows(calls, sources, sinks, sanitizers, unreachableLines, tainted, code, language, types) {
|
|
37757
37827
|
const flows = [];
|
|
37758
|
-
const
|
|
37759
|
-
const
|
|
37828
|
+
const methodRanges = (langs) => language && langs.includes(language) && types ? types.flatMap((t) => t.methods.map((m) => [m.start_line, m.end_line])) : [];
|
|
37829
|
+
const enclosingStart = (ranges, line) => {
|
|
37760
37830
|
let best = -1;
|
|
37761
37831
|
let bestSpan = -1;
|
|
37762
|
-
for (const [start2, end] of
|
|
37832
|
+
for (const [start2, end] of ranges) {
|
|
37763
37833
|
if (line >= start2 && line <= end && end - start2 > bestSpan) {
|
|
37764
37834
|
best = start2;
|
|
37765
37835
|
bestSpan = end - start2;
|
|
@@ -37767,6 +37837,10 @@ function detectExpressionScanFlows(calls, sources, sinks, sanitizers, unreachabl
|
|
|
37767
37837
|
}
|
|
37768
37838
|
return best;
|
|
37769
37839
|
};
|
|
37840
|
+
const goFnRanges = methodRanges(["go"]);
|
|
37841
|
+
const goFnStart = (line) => enclosingStart(goFnRanges, line);
|
|
37842
|
+
const csFnRanges = methodRanges(["csharp"]);
|
|
37843
|
+
const csFnStart = (line) => enclosingStart(csFnRanges, line);
|
|
37770
37844
|
const sourcesWithVar = sources.filter((s) => typeof s.variable === "string" && s.variable.length > 0);
|
|
37771
37845
|
const aliasSanitizedFor = new Map;
|
|
37772
37846
|
if (language === "python" && typeof code === "string") {
|
|
@@ -38102,15 +38176,51 @@ function detectExpressionScanFlows(calls, sources, sinks, sanitizers, unreachabl
|
|
|
38102
38176
|
const [, obj, rhs] = m;
|
|
38103
38177
|
if (known.has(obj))
|
|
38104
38178
|
continue;
|
|
38105
|
-
|
|
38106
|
-
const rhsTainted = sourcesWithVar.some((s) => new RegExp(`(?<![\\p{L}\\p{N}_])${s.variable.replace(/[.*+?^${}()|[\\]\\\\]/g, "\\$&")}(?![\\p{L}\\p{N}_])`, "u").test(codePart));
|
|
38107
|
-
if (!rhsTainted)
|
|
38179
|
+
if (!argsReferenceTaintedVar(rhs, sourcesWithVar))
|
|
38108
38180
|
continue;
|
|
38109
38181
|
sourcesWithVar.push({ ...anchor, variable: obj, line: i2 + 1 });
|
|
38110
38182
|
added = true;
|
|
38111
38183
|
}
|
|
38112
38184
|
}
|
|
38113
38185
|
}
|
|
38186
|
+
const builderSeeds = new Set;
|
|
38187
|
+
if (language === "csharp" && typeof code === "string" && sourcesWithVar.length > 0) {
|
|
38188
|
+
const lines = code.split(`
|
|
38189
|
+
`);
|
|
38190
|
+
const builders = new Set;
|
|
38191
|
+
for (const line of lines) {
|
|
38192
|
+
for (const m of line.matchAll(/\bStringBuilder\s+([\p{L}_][\p{L}\p{N}_]*)/gu))
|
|
38193
|
+
builders.add(m[1]);
|
|
38194
|
+
for (const m of line.matchAll(/\b([\p{L}_][\p{L}\p{N}_]*)\s*=\s*new\s+StringBuilder\b/gu))
|
|
38195
|
+
builders.add(m[1]);
|
|
38196
|
+
}
|
|
38197
|
+
if (builders.size > 0) {
|
|
38198
|
+
const appendRe = /([\p{L}_][\p{L}\p{N}_]*)\s*\.\s*(?:Append|AppendLine|AppendFormat|Insert)\s*\(([\s\S]*)/u;
|
|
38199
|
+
const anchor = sourcesWithVar.reduce((a, s) => s.line < a.line ? s : a, sourcesWithVar[0]);
|
|
38200
|
+
let added = true;
|
|
38201
|
+
let guard = 0;
|
|
38202
|
+
while (added && guard < lines.length + 2) {
|
|
38203
|
+
added = false;
|
|
38204
|
+
guard++;
|
|
38205
|
+
const known = new Set(sourcesWithVar.map((s) => s.variable));
|
|
38206
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
38207
|
+
const m = appendRe.exec(lines[i2]);
|
|
38208
|
+
if (!m)
|
|
38209
|
+
continue;
|
|
38210
|
+
const [, obj, args2] = m;
|
|
38211
|
+
if (!builders.has(obj) || known.has(obj))
|
|
38212
|
+
continue;
|
|
38213
|
+
const appendFn = csFnStart(i2 + 1);
|
|
38214
|
+
const reachable = sourcesWithVar.filter((sv) => appendFn === -1 || csFnStart(sv.line) === -1 || csFnStart(sv.line) === appendFn);
|
|
38215
|
+
if (reachable.length > 0 && argsReferenceTaintedVar(args2, reachable)) {
|
|
38216
|
+
sourcesWithVar.push({ ...anchor, variable: obj, line: i2 + 1 });
|
|
38217
|
+
builderSeeds.add(`${obj}@${i2 + 1}`);
|
|
38218
|
+
added = true;
|
|
38219
|
+
}
|
|
38220
|
+
}
|
|
38221
|
+
}
|
|
38222
|
+
}
|
|
38223
|
+
}
|
|
38114
38224
|
const SIMPLE_IDENT = /^[\p{L}\p{N}_]+$/u;
|
|
38115
38225
|
const reCache = new Map;
|
|
38116
38226
|
for (const s of sourcesWithVar) {
|
|
@@ -38181,6 +38291,12 @@ function detectExpressionScanFlows(calls, sources, sinks, sanitizers, unreachabl
|
|
|
38181
38291
|
if (srcFn !== -1 && sinkFn !== -1 && srcFn !== sinkFn)
|
|
38182
38292
|
continue;
|
|
38183
38293
|
}
|
|
38294
|
+
if (csFnRanges.length > 0 && builderSeeds.has(`${source.variable}@${source.line}`)) {
|
|
38295
|
+
const srcFn = csFnStart(source.line);
|
|
38296
|
+
const sinkFn = csFnStart(sink.line);
|
|
38297
|
+
if (srcFn !== sinkFn)
|
|
38298
|
+
continue;
|
|
38299
|
+
}
|
|
38184
38300
|
if (complex) {
|
|
38185
38301
|
const re = reCache.get(source.variable);
|
|
38186
38302
|
if (!re || !re.test(expr))
|
|
@@ -50669,7 +50785,7 @@ var colors = {
|
|
|
50669
50785
|
};
|
|
50670
50786
|
|
|
50671
50787
|
// src/version.ts
|
|
50672
|
-
var version = "4.9.
|
|
50788
|
+
var version = "4.9.29";
|
|
50673
50789
|
|
|
50674
50790
|
// src/formatters.ts
|
|
50675
50791
|
var LIBRARY_API_SURFACE_TAG2 = "library-api-surface:caller-responsibility";
|
|
@@ -51221,8 +51337,8 @@ function generateSarifResults(results, crossFileData) {
|
|
|
51221
51337
|
|
|
51222
51338
|
// src/build-info.ts
|
|
51223
51339
|
var buildInfo = {
|
|
51224
|
-
gitSha: "
|
|
51225
|
-
builtAt: "2026-10-
|
|
51340
|
+
gitSha: "9d1d45a",
|
|
51341
|
+
builtAt: "2026-10-01T03:14:59.073Z"
|
|
51226
51342
|
};
|
|
51227
51343
|
|
|
51228
51344
|
// src/utils/args.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cognium-dev",
|
|
3
|
-
"version": "4.9.
|
|
3
|
+
"version": "4.9.29",
|
|
4
4
|
"description": "Static Application Security Testing CLI for detecting security vulnerabilities via taint tracking",
|
|
5
5
|
"bin": {
|
|
6
6
|
"cognium-dev": "dist/cli.js"
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
67
|
"@cognium/project-profile-detect": "1.1.2",
|
|
68
|
-
"circle-ir": "4.9.
|
|
68
|
+
"circle-ir": "4.9.29"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@types/node": "^26.6.2",
|