cognium-dev 4.3.1 → 4.5.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.
Files changed (2) hide show
  1. package/dist/cli.js +81 -4
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -5268,6 +5268,14 @@ function findFirstDescendant(node, type) {
5268
5268
  }
5269
5269
  return null;
5270
5270
  }
5271
+ var CSHARP_COMMAND_EXECUTE_METHODS = new Set([
5272
+ "ExecuteScalar",
5273
+ "ExecuteReader",
5274
+ "ExecuteNonQuery",
5275
+ "ExecuteScalarAsync",
5276
+ "ExecuteReaderAsync",
5277
+ "ExecuteNonQueryAsync"
5278
+ ]);
5271
5279
  function extractCSharpCalls(tree, cache) {
5272
5280
  const calls = [];
5273
5281
  const typeMap = buildCSharpReceiverTypeMap(tree, cache);
@@ -5285,12 +5293,16 @@ function extractCSharpCalls(tree, cache) {
5285
5293
  methodName = getNodeText(fn);
5286
5294
  }
5287
5295
  const argsNode = inv.childForFieldName("arguments");
5296
+ let args2 = argsNode ? extractCSharpArguments(argsNode) : [];
5297
+ if (receiver && CSHARP_COMMAND_EXECUTE_METHODS.has(methodName)) {
5298
+ args2 = [{ position: 0, expression: receiver, variable: receiver, literal: null, value: null }, ...args2];
5299
+ }
5288
5300
  calls.push({
5289
5301
  method_name: methodName,
5290
5302
  receiver,
5291
5303
  receiver_type: receiver ? typeMap.get(receiver) ?? null : null,
5292
5304
  receiver_type_fqn: null,
5293
- arguments: argsNode ? extractCSharpArguments(argsNode) : [],
5305
+ arguments: args2,
5294
5306
  location: { line: inv.startPosition.row + 1, column: inv.startPosition.column },
5295
5307
  in_method: findEnclosingMethod(inv)
5296
5308
  });
@@ -5310,6 +5322,35 @@ function extractCSharpCalls(tree, cache) {
5310
5322
  is_constructor: true
5311
5323
  });
5312
5324
  }
5325
+ const assignments = getNodesFromCache(tree.rootNode, "assignment_expression", cache);
5326
+ for (const asn of assignments) {
5327
+ const left = asn.childForFieldName("left");
5328
+ if (left?.type !== "member_access_expression")
5329
+ continue;
5330
+ const nameNode = left.childForFieldName("name");
5331
+ if (!nameNode || getNodeText(nameNode) !== "CommandText")
5332
+ continue;
5333
+ const right = asn.childForFieldName("right");
5334
+ if (!right)
5335
+ continue;
5336
+ const rhsText = getNodeText(right);
5337
+ const exprNode = left.childForFieldName("expression");
5338
+ calls.push({
5339
+ method_name: "CommandText",
5340
+ receiver: exprNode ? getNodeText(exprNode) : null,
5341
+ receiver_type: null,
5342
+ receiver_type_fqn: null,
5343
+ arguments: [{
5344
+ position: 0,
5345
+ expression: rhsText,
5346
+ variable: right.type === "identifier" ? rhsText : null,
5347
+ literal: right.type === "string_literal" ? rhsText : null,
5348
+ value: null
5349
+ }],
5350
+ location: { line: asn.startPosition.row + 1, column: asn.startPosition.column },
5351
+ in_method: findEnclosingMethod(asn)
5352
+ });
5353
+ }
5313
5354
  return calls;
5314
5355
  }
5315
5356
  function extractCSharpArguments(argsNode) {
@@ -12284,6 +12325,13 @@ var DEFAULT_SINKS = [
12284
12325
  { method: "ExecuteSqlRawAsync", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12285
12326
  { method: "FromSqlRaw", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12286
12327
  { method: "FromSqlRawAsync", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12328
+ { method: "CommandText", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12329
+ { method: "ExecuteScalar", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12330
+ { method: "ExecuteReader", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12331
+ { method: "ExecuteNonQuery", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12332
+ { method: "ExecuteScalarAsync", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12333
+ { method: "ExecuteReaderAsync", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12334
+ { method: "ExecuteNonQueryAsync", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12287
12335
  { method: "Start", class: "Process", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12288
12336
  { method: "ProcessStartInfo", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1], languages: ["csharp"] },
12289
12337
  { method: "ReadAllText", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
@@ -25589,18 +25637,20 @@ function findCSharpRequestSources(sourceCode, language) {
25589
25637
  `);
25590
25638
  const assignRe = /^\s*(?:var\s+|[A-Za-z_][\w.<>\[\]]*\s+)?([A-Za-z_]\w*)\s*=\s*(.+?);?\s*$/;
25591
25639
  const requestReadRe = /\bRequest\s*\.\s*(?:Query|Form|Headers|Cookies|QueryString|RouteValues|Body|Files|Params)\b/;
25640
+ const consoleReadRe = /\bConsole\s*\.\s*ReadLine\s*\(/;
25592
25641
  for (let i2 = 0;i2 < lines.length; i2++) {
25593
25642
  const m = assignRe.exec(lines[i2]);
25594
25643
  if (!m)
25595
25644
  continue;
25596
25645
  const [, varName, rhs] = m;
25597
- if (!requestReadRe.test(rhs))
25646
+ const type = requestReadRe.test(rhs) ? "http_param" : consoleReadRe.test(rhs) ? "io_input" : null;
25647
+ if (!type)
25598
25648
  continue;
25599
25649
  const lineNumber = i2 + 1;
25600
25650
  if (sources.some((s) => s.line === lineNumber && s.variable === varName))
25601
25651
  continue;
25602
25652
  sources.push({
25603
- type: "http_param",
25653
+ type,
25604
25654
  location: `${varName} = ${rhs.trim().substring(0, 50)}${rhs.length > 50 ? "..." : ""}`,
25605
25655
  severity: "high",
25606
25656
  line: lineNumber,
@@ -35990,6 +36040,33 @@ function detectExpressionScanFlows(calls, sources, sinks, sanitizers, unreachabl
35990
36040
  }
35991
36041
  }
35992
36042
  }
36043
+ if (language === "csharp" && typeof code === "string" && sourcesWithVar.length > 0) {
36044
+ const lines = code.split(`
36045
+ `);
36046
+ const ctRe = /(\w+)\s*\.\s*CommandText\s*\+?=\s*(.+)/;
36047
+ const anchor = sourcesWithVar.reduce((a, s) => s.line < a.line ? s : a, sourcesWithVar[0]);
36048
+ let added = true;
36049
+ let guard = 0;
36050
+ while (added && guard < lines.length + 2) {
36051
+ added = false;
36052
+ guard++;
36053
+ const known = new Set(sourcesWithVar.map((s) => s.variable));
36054
+ for (let i2 = 0;i2 < lines.length; i2++) {
36055
+ const m = ctRe.exec(lines[i2]);
36056
+ if (!m)
36057
+ continue;
36058
+ const [, obj, rhs] = m;
36059
+ if (known.has(obj))
36060
+ continue;
36061
+ const codePart = rhs.replace(/\$@?"(?:[^"\\]|\\.)*"/g, (lit) => " " + [...lit.matchAll(/\{([^}]*)\}/g)].map((x) => x[1]).join(" ") + " ").replace(/@?"(?:[^"\\]|\\.)*"/g, " ");
36062
+ const rhsTainted = sourcesWithVar.some((s) => new RegExp(`(?<![\\p{L}\\p{N}_])${s.variable.replace(/[.*+?^${}()|[\\]\\\\]/g, "\\$&")}(?![\\p{L}\\p{N}_])`, "u").test(codePart));
36063
+ if (!rhsTainted)
36064
+ continue;
36065
+ sourcesWithVar.push({ ...anchor, variable: obj, line: i2 + 1 });
36066
+ added = true;
36067
+ }
36068
+ }
36069
+ }
35993
36070
  const reCache = new Map;
35994
36071
  for (const s of sourcesWithVar) {
35995
36072
  if (reCache.has(s.variable))
@@ -47778,7 +47855,7 @@ var colors = {
47778
47855
  };
47779
47856
 
47780
47857
  // src/version.ts
47781
- var version = "4.3.1";
47858
+ var version = "4.5.0";
47782
47859
 
47783
47860
  // src/formatters.ts
47784
47861
  var LIBRARY_API_SURFACE_TAG2 = "library-api-surface:caller-responsibility";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cognium-dev",
3
- "version": "4.3.1",
3
+ "version": "4.5.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",
@@ -66,7 +66,7 @@
66
66
  },
67
67
  "dependencies": {
68
68
  "@cognium/project-profile-detect": "^1.1.0",
69
- "circle-ir": "^4.3.1"
69
+ "circle-ir": "^4.5.0"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@types/node": "^25.5.0",