cognium-dev 4.7.1 → 4.8.2

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 +288 -49
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -5328,15 +5328,24 @@ function extractCSharpCalls(tree, cache) {
5328
5328
  if (left?.type !== "member_access_expression")
5329
5329
  continue;
5330
5330
  const nameNode = left.childForFieldName("name");
5331
- if (!nameNode || getNodeText(nameNode) !== "CommandText")
5331
+ if (!nameNode)
5332
+ continue;
5333
+ const propName = getNodeText(nameNode);
5334
+ const exprNode = left.childForFieldName("expression");
5335
+ if (propName === "Filter") {
5336
+ const recv = exprNode ? getNodeText(exprNode) : null;
5337
+ const recvType = recv ? typeMap.get(recv) : undefined;
5338
+ if (recvType !== "DirectorySearcher")
5339
+ continue;
5340
+ } else if (propName !== "CommandText") {
5332
5341
  continue;
5342
+ }
5333
5343
  const right = asn.childForFieldName("right");
5334
5344
  if (!right)
5335
5345
  continue;
5336
5346
  const rhsText = getNodeText(right);
5337
- const exprNode = left.childForFieldName("expression");
5338
5347
  calls.push({
5339
- method_name: "CommandText",
5348
+ method_name: propName,
5340
5349
  receiver: exprNode ? getNodeText(exprNode) : null,
5341
5350
  receiver_type: null,
5342
5351
  receiver_type_fqn: null,
@@ -7985,6 +7994,9 @@ function buildCFG(tree, language, cache) {
7985
7994
  if (effectiveLanguage === "go") {
7986
7995
  return buildGoCFG(tree, blockIdCounter, cache);
7987
7996
  }
7997
+ if (effectiveLanguage === "csharp") {
7998
+ return buildCSharpCFG(tree, blockIdCounter, cache);
7999
+ }
7988
8000
  if (isJavaScript) {
7989
8001
  const functions = [
7990
8002
  ...getNodesFromCache(tree.rootNode, "function_declaration", cache),
@@ -7998,7 +8010,7 @@ function buildCFG(tree, language, cache) {
7998
8010
  if (!body2)
7999
8011
  continue;
8000
8012
  if (body2.type === "statement_block") {
8001
- const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, true);
8013
+ const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, "js");
8002
8014
  allBlocks.push(...blocks);
8003
8015
  allEdges.push(...edges);
8004
8016
  blockIdCounter = nextId;
@@ -8021,7 +8033,7 @@ function buildCFG(tree, language, cache) {
8021
8033
  const body2 = method.childForFieldName("body");
8022
8034
  if (!body2)
8023
8035
  continue;
8024
- const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, false);
8036
+ const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, "java");
8025
8037
  allBlocks.push(...blocks);
8026
8038
  allEdges.push(...edges);
8027
8039
  blockIdCounter = nextId;
@@ -8029,7 +8041,29 @@ function buildCFG(tree, language, cache) {
8029
8041
  }
8030
8042
  return { blocks: allBlocks, edges: allEdges };
8031
8043
  }
8032
- function buildMethodCFG(body2, startId, isJavaScript) {
8044
+ function buildCSharpCFG(tree, blockIdCounter, cache) {
8045
+ const allBlocks = [];
8046
+ const allEdges = [];
8047
+ const containers = [
8048
+ ...getNodesFromCache(tree.rootNode, "method_declaration", cache),
8049
+ ...getNodesFromCache(tree.rootNode, "constructor_declaration", cache),
8050
+ ...getNodesFromCache(tree.rootNode, "destructor_declaration", cache),
8051
+ ...getNodesFromCache(tree.rootNode, "operator_declaration", cache),
8052
+ ...getNodesFromCache(tree.rootNode, "local_function_statement", cache),
8053
+ ...getNodesFromCache(tree.rootNode, "accessor_declaration", cache)
8054
+ ];
8055
+ for (const container of containers) {
8056
+ const body2 = container.childForFieldName("body");
8057
+ if (!body2 || body2.type !== "block")
8058
+ continue;
8059
+ const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, "csharp");
8060
+ allBlocks.push(...blocks);
8061
+ allEdges.push(...edges);
8062
+ blockIdCounter = nextId;
8063
+ }
8064
+ return { blocks: allBlocks, edges: allEdges };
8065
+ }
8066
+ function buildMethodCFG(body2, startId, dialect) {
8033
8067
  const blocks = [];
8034
8068
  const edges = [];
8035
8069
  let currentId = startId;
@@ -8040,7 +8074,7 @@ function buildMethodCFG(body2, startId, isJavaScript) {
8040
8074
  end_line: body2.startPosition.row + 1
8041
8075
  };
8042
8076
  blocks.push(entryBlock);
8043
- const result = processStatements(body2, currentId, blocks, edges, isJavaScript);
8077
+ const result = processStatements(body2, currentId, blocks, edges, dialect);
8044
8078
  currentId = result.nextId;
8045
8079
  if (result.entryId !== -1) {
8046
8080
  edges.push({
@@ -8072,7 +8106,7 @@ function buildMethodCFG(body2, startId, isJavaScript) {
8072
8106
  }
8073
8107
  return { blocks, edges, nextId: currentId };
8074
8108
  }
8075
- function processStatements(container, startId, blocks, edges, isJavaScript) {
8109
+ function processStatements(container, startId, blocks, edges, dialect) {
8076
8110
  let currentId = startId;
8077
8111
  let firstBlockId = -1;
8078
8112
  let lastExitIds = [];
@@ -8080,9 +8114,9 @@ function processStatements(container, startId, blocks, edges, isJavaScript) {
8080
8114
  const stmt = container.child(i2);
8081
8115
  if (!stmt)
8082
8116
  continue;
8083
- if (!isStatement(stmt, isJavaScript))
8117
+ if (!isStatement(stmt, dialect))
8084
8118
  continue;
8085
- const result = processStatement(stmt, currentId, blocks, edges, isJavaScript);
8119
+ const result = processStatement(stmt, currentId, blocks, edges, dialect);
8086
8120
  currentId = result.nextId;
8087
8121
  if (firstBlockId === -1) {
8088
8122
  firstBlockId = result.entryId;
@@ -8103,31 +8137,49 @@ function processStatements(container, startId, blocks, edges, isJavaScript) {
8103
8137
  nextId: currentId
8104
8138
  };
8105
8139
  }
8106
- function processStatement(stmt, startId, blocks, edges, isJavaScript) {
8140
+ function processStatement(stmt, startId, blocks, edges, dialect) {
8107
8141
  switch (stmt.type) {
8108
8142
  case "if_statement":
8109
- return processIfStatement(stmt, startId, blocks, edges, isJavaScript);
8143
+ return processIfStatement(stmt, startId, blocks, edges, dialect);
8110
8144
  case "for_statement":
8111
8145
  case "enhanced_for_statement":
8112
8146
  case "for_in_statement":
8113
8147
  case "for_of_statement":
8114
- return processForStatement(stmt, startId, blocks, edges, isJavaScript);
8148
+ case "foreach_statement":
8149
+ return processForStatement(stmt, startId, blocks, edges, dialect);
8115
8150
  case "while_statement":
8116
- return processWhileStatement(stmt, startId, blocks, edges, isJavaScript);
8151
+ return processWhileStatement(stmt, startId, blocks, edges, dialect);
8117
8152
  case "do_statement":
8118
- return processDoWhileStatement(stmt, startId, blocks, edges, isJavaScript);
8153
+ return processDoWhileStatement(stmt, startId, blocks, edges, dialect);
8119
8154
  case "try_statement":
8120
- return processTryStatement(stmt, startId, blocks, edges, isJavaScript);
8155
+ return processTryStatement(stmt, startId, blocks, edges, dialect);
8121
8156
  case "switch_expression":
8122
8157
  case "switch_statement":
8123
- return processSwitchStatement(stmt, startId, blocks, edges, isJavaScript);
8158
+ return processSwitchStatement(stmt, startId, blocks, edges, dialect);
8159
+ case "using_statement":
8160
+ case "lock_statement":
8161
+ case "checked_statement":
8162
+ case "unsafe_statement": {
8163
+ const inner = stmt.childForFieldName("body") ?? lastBlockChild(stmt);
8164
+ if (inner)
8165
+ return processStatement(inner, startId, blocks, edges, dialect);
8166
+ return processSimpleStatement(stmt, startId, blocks);
8167
+ }
8124
8168
  case "block":
8125
8169
  case "statement_block":
8126
- return processStatements(stmt, startId, blocks, edges, isJavaScript);
8170
+ return processStatements(stmt, startId, blocks, edges, dialect);
8127
8171
  default:
8128
8172
  return processSimpleStatement(stmt, startId, blocks);
8129
8173
  }
8130
8174
  }
8175
+ function lastBlockChild(node) {
8176
+ for (let i2 = node.childCount - 1;i2 >= 0; i2--) {
8177
+ const c = node.child(i2);
8178
+ if (c && c.type === "block")
8179
+ return c;
8180
+ }
8181
+ return null;
8182
+ }
8131
8183
  function processSimpleStatement(stmt, startId, blocks) {
8132
8184
  const block = {
8133
8185
  id: startId,
@@ -8142,7 +8194,7 @@ function processSimpleStatement(stmt, startId, blocks) {
8142
8194
  nextId: startId + 1
8143
8195
  };
8144
8196
  }
8145
- function processIfStatement(stmt, startId, blocks, edges, isJavaScript) {
8197
+ function processIfStatement(stmt, startId, blocks, edges, dialect) {
8146
8198
  let currentId = startId;
8147
8199
  const condBlock = {
8148
8200
  id: currentId++,
@@ -8154,7 +8206,7 @@ function processIfStatement(stmt, startId, blocks, edges, isJavaScript) {
8154
8206
  const exitIds = [];
8155
8207
  const consequence = stmt.childForFieldName("consequence");
8156
8208
  if (consequence) {
8157
- const thenResult = processStatement(consequence, currentId, blocks, edges, isJavaScript);
8209
+ const thenResult = processStatement(consequence, currentId, blocks, edges, dialect);
8158
8210
  currentId = thenResult.nextId;
8159
8211
  edges.push({
8160
8212
  from: condBlock.id,
@@ -8165,7 +8217,7 @@ function processIfStatement(stmt, startId, blocks, edges, isJavaScript) {
8165
8217
  }
8166
8218
  const alternative = stmt.childForFieldName("alternative");
8167
8219
  if (alternative) {
8168
- const elseResult = processStatement(alternative, currentId, blocks, edges, isJavaScript);
8220
+ const elseResult = processStatement(alternative, currentId, blocks, edges, dialect);
8169
8221
  currentId = elseResult.nextId;
8170
8222
  edges.push({
8171
8223
  from: condBlock.id,
@@ -8182,7 +8234,7 @@ function processIfStatement(stmt, startId, blocks, edges, isJavaScript) {
8182
8234
  nextId: currentId
8183
8235
  };
8184
8236
  }
8185
- function processForStatement(stmt, startId, blocks, edges, isJavaScript) {
8237
+ function processForStatement(stmt, startId, blocks, edges, dialect) {
8186
8238
  let currentId = startId;
8187
8239
  const loopBlock = {
8188
8240
  id: currentId++,
@@ -8193,7 +8245,7 @@ function processForStatement(stmt, startId, blocks, edges, isJavaScript) {
8193
8245
  blocks.push(loopBlock);
8194
8246
  const body2 = stmt.childForFieldName("body");
8195
8247
  if (body2) {
8196
- const bodyResult = processStatement(body2, currentId, blocks, edges, isJavaScript);
8248
+ const bodyResult = processStatement(body2, currentId, blocks, edges, dialect);
8197
8249
  currentId = bodyResult.nextId;
8198
8250
  edges.push({
8199
8251
  from: loopBlock.id,
@@ -8214,16 +8266,16 @@ function processForStatement(stmt, startId, blocks, edges, isJavaScript) {
8214
8266
  nextId: currentId
8215
8267
  };
8216
8268
  }
8217
- function processWhileStatement(stmt, startId, blocks, edges, isJavaScript) {
8218
- return processForStatement(stmt, startId, blocks, edges, isJavaScript);
8269
+ function processWhileStatement(stmt, startId, blocks, edges, dialect) {
8270
+ return processForStatement(stmt, startId, blocks, edges, dialect);
8219
8271
  }
8220
- function processDoWhileStatement(stmt, startId, blocks, edges, isJavaScript) {
8272
+ function processDoWhileStatement(stmt, startId, blocks, edges, dialect) {
8221
8273
  let currentId = startId;
8222
8274
  const body2 = stmt.childForFieldName("body");
8223
8275
  let bodyEntryId = currentId;
8224
8276
  let bodyExitIds = [];
8225
8277
  if (body2) {
8226
- const bodyResult = processStatement(body2, currentId, blocks, edges, isJavaScript);
8278
+ const bodyResult = processStatement(body2, currentId, blocks, edges, dialect);
8227
8279
  currentId = bodyResult.nextId;
8228
8280
  bodyEntryId = bodyResult.entryId;
8229
8281
  bodyExitIds = bodyResult.exitIds;
@@ -8253,13 +8305,13 @@ function processDoWhileStatement(stmt, startId, blocks, edges, isJavaScript) {
8253
8305
  nextId: currentId
8254
8306
  };
8255
8307
  }
8256
- function processTryStatement(stmt, startId, blocks, edges, isJavaScript) {
8308
+ function processTryStatement(stmt, startId, blocks, edges, dialect) {
8257
8309
  let currentId = startId;
8258
8310
  const exitIds = [];
8259
8311
  const body2 = stmt.childForFieldName("body");
8260
8312
  let tryEntryId = -1;
8261
8313
  if (body2) {
8262
- const bodyResult = processStatements(body2, currentId, blocks, edges, isJavaScript);
8314
+ const bodyResult = processStatements(body2, currentId, blocks, edges, dialect);
8263
8315
  currentId = bodyResult.nextId;
8264
8316
  tryEntryId = bodyResult.entryId;
8265
8317
  exitIds.push(...bodyResult.exitIds);
@@ -8269,7 +8321,7 @@ function processTryStatement(stmt, startId, blocks, edges, isJavaScript) {
8269
8321
  if (child?.type === "catch_clause") {
8270
8322
  const catchBody = child.childForFieldName("body");
8271
8323
  if (catchBody) {
8272
- const catchResult = processStatements(catchBody, currentId, blocks, edges, isJavaScript);
8324
+ const catchResult = processStatements(catchBody, currentId, blocks, edges, dialect);
8273
8325
  currentId = catchResult.nextId;
8274
8326
  if (tryEntryId !== -1) {
8275
8327
  edges.push({
@@ -8282,9 +8334,18 @@ function processTryStatement(stmt, startId, blocks, edges, isJavaScript) {
8282
8334
  }
8283
8335
  }
8284
8336
  }
8285
- const finallyClause = stmt.childForFieldName("finally") ?? stmt.childForFieldName("finalizer");
8337
+ let finallyClause = stmt.childForFieldName("finally") ?? stmt.childForFieldName("finalizer");
8338
+ if (!finallyClause && dialect === "csharp") {
8339
+ for (let i2 = 0;i2 < stmt.childCount; i2++) {
8340
+ const child = stmt.child(i2);
8341
+ if (child?.type === "finally_clause") {
8342
+ finallyClause = lastBlockChild(child);
8343
+ break;
8344
+ }
8345
+ }
8346
+ }
8286
8347
  if (finallyClause) {
8287
- const finallyResult = processStatements(finallyClause, currentId, blocks, edges, isJavaScript);
8348
+ const finallyResult = processStatements(finallyClause, currentId, blocks, edges, dialect);
8288
8349
  currentId = finallyResult.nextId;
8289
8350
  for (const exitId of exitIds) {
8290
8351
  edges.push({
@@ -8305,7 +8366,7 @@ function processTryStatement(stmt, startId, blocks, edges, isJavaScript) {
8305
8366
  nextId: currentId
8306
8367
  };
8307
8368
  }
8308
- function processSwitchStatement(stmt, startId, blocks, edges, isJavaScript) {
8369
+ function processSwitchStatement(stmt, startId, blocks, edges, dialect) {
8309
8370
  let currentId = startId;
8310
8371
  const switchBlock = {
8311
8372
  id: currentId++,
@@ -8317,11 +8378,11 @@ function processSwitchStatement(stmt, startId, blocks, edges, isJavaScript) {
8317
8378
  const exitIds = [];
8318
8379
  const body2 = stmt.childForFieldName("body");
8319
8380
  if (body2) {
8320
- const caseTypes = isJavaScript ? ["switch_case", "switch_default"] : ["switch_block_statement_group", "switch_rule"];
8381
+ const caseTypes = dialect === "js" ? ["switch_case", "switch_default"] : dialect === "csharp" ? ["switch_section"] : ["switch_block_statement_group", "switch_rule"];
8321
8382
  for (let i2 = 0;i2 < body2.childCount; i2++) {
8322
8383
  const child = body2.child(i2);
8323
8384
  if (child && caseTypes.includes(child.type)) {
8324
- const caseResult = processStatements(child, currentId, blocks, edges, isJavaScript);
8385
+ const caseResult = processStatements(child, currentId, blocks, edges, dialect);
8325
8386
  currentId = caseResult.nextId;
8326
8387
  if (caseResult.entryId !== -1) {
8327
8388
  edges.push({
@@ -8352,7 +8413,7 @@ function buildBashCFG(tree, startId, cache) {
8352
8413
  const body2 = func2.childForFieldName("body");
8353
8414
  if (!body2)
8354
8415
  continue;
8355
- const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, false);
8416
+ const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, "java");
8356
8417
  allBlocks.push(...blocks);
8357
8418
  allEdges.push(...edges);
8358
8419
  blockIdCounter = nextId;
@@ -8375,7 +8436,7 @@ function buildBashCFG(tree, startId, cache) {
8375
8436
  let lastExitIds = [];
8376
8437
  let firstBlockId = -1;
8377
8438
  for (const stmt of topLevelStatements) {
8378
- const result = processStatement(stmt, blockIdCounter, allBlocks, allEdges, false);
8439
+ const result = processStatement(stmt, blockIdCounter, allBlocks, allEdges, "java");
8379
8440
  blockIdCounter = result.nextId;
8380
8441
  if (firstBlockId === -1) {
8381
8442
  firstBlockId = result.entryId;
@@ -8419,7 +8480,9 @@ function isBashStatement(node) {
8419
8480
  ]);
8420
8481
  return bashStatementTypes.has(node.type);
8421
8482
  }
8422
- function isStatement(node, isJavaScript) {
8483
+ function isStatement(node, dialect) {
8484
+ if (dialect === "csharp")
8485
+ return csharpStatementTypes.has(node.type);
8423
8486
  const javaStatementTypes = new Set([
8424
8487
  "local_variable_declaration",
8425
8488
  "expression_statement",
@@ -8463,8 +8526,30 @@ function isStatement(node, isJavaScript) {
8463
8526
  "export_statement",
8464
8527
  "import_statement"
8465
8528
  ]);
8466
- return isJavaScript ? jsStatementTypes.has(node.type) : javaStatementTypes.has(node.type);
8467
- }
8529
+ return dialect === "js" ? jsStatementTypes.has(node.type) : javaStatementTypes.has(node.type);
8530
+ }
8531
+ var csharpStatementTypes = new Set([
8532
+ "local_declaration_statement",
8533
+ "expression_statement",
8534
+ "if_statement",
8535
+ "for_statement",
8536
+ "foreach_statement",
8537
+ "while_statement",
8538
+ "do_statement",
8539
+ "try_statement",
8540
+ "switch_statement",
8541
+ "return_statement",
8542
+ "throw_statement",
8543
+ "break_statement",
8544
+ "continue_statement",
8545
+ "using_statement",
8546
+ "lock_statement",
8547
+ "checked_statement",
8548
+ "unsafe_statement",
8549
+ "yield_statement",
8550
+ "goto_statement",
8551
+ "block"
8552
+ ]);
8468
8553
  function buildGoCFG(tree, blockIdCounter, cache) {
8469
8554
  const allBlocks = [];
8470
8555
  const allEdges = [];
@@ -8476,7 +8561,7 @@ function buildGoCFG(tree, blockIdCounter, cache) {
8476
8561
  const body2 = func2.childForFieldName("body");
8477
8562
  if (!body2 || body2.type !== "block")
8478
8563
  continue;
8479
- const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, false);
8564
+ const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, "java");
8480
8565
  allBlocks.push(...blocks);
8481
8566
  allEdges.push(...edges);
8482
8567
  blockIdCounter = nextId;
@@ -11386,7 +11471,7 @@ var DEFAULT_SINKS = [
11386
11471
  { method: "setCommandline", class: "DefaultExecutor", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
11387
11472
  { method: "parse", class: "CommandLine", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
11388
11473
  { method: "addArgument", class: "CommandLine", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
11389
- { method: "File", class: "constructor", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0, 1] },
11474
+ { method: "File", class: "constructor", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0, 1], exclude_languages: ["csharp"] },
11390
11475
  { method: "FileInputStream", class: "constructor", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
11391
11476
  { method: "FileOutputStream", class: "constructor", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
11392
11477
  { method: "FileReader", class: "constructor", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
@@ -12328,6 +12413,7 @@ var DEFAULT_SINKS = [
12328
12413
  { method: "FromSqlRaw", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12329
12414
  { method: "FromSqlRawAsync", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12330
12415
  { method: "CommandText", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12416
+ { method: "Filter", type: "ldap_injection", cwe: "CWE-90", severity: "high", arg_positions: [0], languages: ["csharp"] },
12331
12417
  { method: "ExecuteScalar", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12332
12418
  { method: "ExecuteReader", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12333
12419
  { method: "ExecuteNonQuery", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
@@ -12336,6 +12422,7 @@ var DEFAULT_SINKS = [
12336
12422
  { method: "ExecuteNonQueryAsync", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12337
12423
  { method: "Start", class: "Process", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1], languages: ["csharp"] },
12338
12424
  { method: "ProcessStartInfo", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1], languages: ["csharp"] },
12425
+ { method: "system", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12339
12426
  { method: "ReadAllText", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
12340
12427
  { method: "ReadAllBytes", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
12341
12428
  { method: "ReadAllLines", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
@@ -12347,6 +12434,19 @@ var DEFAULT_SINKS = [
12347
12434
  { method: "FileStream", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
12348
12435
  { method: "StreamReader", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
12349
12436
  { method: "StreamWriter", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
12437
+ { method: "Copy", class: "File", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0, 1], languages: ["csharp"] },
12438
+ { method: "Move", class: "File", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0, 1], languages: ["csharp"] },
12439
+ { method: "Delete", class: "File", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
12440
+ { method: "Open", class: "File", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
12441
+ { method: "OpenText", class: "File", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
12442
+ { method: "Create", class: "File", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
12443
+ { method: "WriteAllLines", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
12444
+ { method: "AppendAllLines", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
12445
+ { method: "CreateDirectory", class: "Directory", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
12446
+ { method: "Delete", class: "Directory", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
12447
+ { method: "GetFiles", class: "Directory", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
12448
+ { method: "EnumerateFiles", class: "Directory", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
12449
+ { method: "PhysicalFile", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
12350
12450
  { method: "GetAsync", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["csharp"] },
12351
12451
  { method: "PostAsync", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["csharp"] },
12352
12452
  { method: "PutAsync", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["csharp"] },
@@ -12361,11 +12461,19 @@ var DEFAULT_SINKS = [
12361
12461
  { method: "Create", class: "WebRequest", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["csharp"] },
12362
12462
  { method: "EvaluateAsync", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12363
12463
  { method: "RunAsync", class: "CSharpScript", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12464
+ { method: "Load", class: "Assembly", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12465
+ { method: "LoadFrom", class: "Assembly", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12466
+ { method: "LoadFile", class: "Assembly", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12364
12467
  { method: "Deserialize", class: "BinaryFormatter", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12365
12468
  { method: "Deserialize", class: "NetDataContractSerializer", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12469
+ { method: "Deserialize", class: "SoapFormatter", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12470
+ { method: "Deserialize", class: "LosFormatter", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12471
+ { method: "Deserialize", class: "ObjectStateFormatter", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12366
12472
  { method: "Raw", class: "Html", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0], languages: ["csharp"] },
12367
12473
  { method: "Write", class: "Response", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0], languages: ["csharp"] },
12368
12474
  { method: "HtmlString", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0], languages: ["csharp"] },
12475
+ { method: "MarkupString", class: "constructor", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0], languages: ["csharp"] },
12476
+ { method: "Format", class: "String", type: "format_string", cwe: "CWE-134", severity: "medium", arg_positions: [0], languages: ["csharp"] },
12369
12477
  { method: "DirectorySearcher", type: "ldap_injection", cwe: "CWE-90", severity: "high", arg_positions: [0], languages: ["csharp"] },
12370
12478
  { method: "DirectoryEntry", type: "ldap_injection", cwe: "CWE-90", severity: "high", arg_positions: [0], languages: ["csharp"] },
12371
12479
  { method: "Redirect", type: "open_redirect", cwe: "CWE-601", severity: "medium", arg_positions: [0], languages: ["csharp"] },
@@ -12373,12 +12481,22 @@ var DEFAULT_SINKS = [
12373
12481
  { method: "AddHeader", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["csharp"] },
12374
12482
  { method: "AppendHeader", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["csharp"] },
12375
12483
  { method: "Parse", class: "BsonDocument", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["csharp"] },
12484
+ { method: "LogInformation", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0], languages: ["csharp"] },
12485
+ { method: "LogWarning", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0], languages: ["csharp"] },
12486
+ { method: "LogError", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0], languages: ["csharp"] },
12487
+ { method: "LogDebug", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0], languages: ["csharp"] },
12488
+ { method: "LogCritical", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0], languages: ["csharp"] },
12489
+ { method: "LogTrace", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0], languages: ["csharp"] },
12490
+ { method: "Log", class: "ILogger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [1], languages: ["csharp"] },
12376
12491
  { method: "SelectSingleNode", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
12377
12492
  { method: "SelectNodes", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
12378
12493
  { method: "Compile", class: "XPathExpression", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
12494
+ { method: "Select", class: "XPathNavigator", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
12495
+ { method: "Evaluate", class: "XPathNavigator", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
12379
12496
  { method: "LoadXml", type: "xxe", cwe: "CWE-611", severity: "high", arg_positions: [0], languages: ["csharp"] },
12380
12497
  { method: "Load", class: "XmlDocument", type: "xxe", cwe: "CWE-611", severity: "high", arg_positions: [0], languages: ["csharp"] },
12381
12498
  { method: "Load", class: "XDocument", type: "xxe", cwe: "CWE-611", severity: "high", arg_positions: [0], languages: ["csharp"] },
12499
+ { method: "XmlTextReader", type: "xxe", cwe: "CWE-611", severity: "high", arg_positions: [0], languages: ["csharp"] },
12382
12500
  { method: "execute", class: "Connection", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0] },
12383
12501
  { method: "fetch", class: "Connection", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0] },
12384
12502
  { method: "fetchrow", class: "Connection", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0] },
@@ -13514,6 +13632,62 @@ function isSafeJSChildProcessCall(call, pattern, language) {
13514
13632
  return false;
13515
13633
  return true;
13516
13634
  }
13635
+ var CSHARP_SHELL_PROGRAMS = new Set([
13636
+ "sh",
13637
+ "bash",
13638
+ "zsh",
13639
+ "dash",
13640
+ "ash",
13641
+ "ksh",
13642
+ "cmd",
13643
+ "powershell",
13644
+ "pwsh"
13645
+ ]);
13646
+ function isConstNonShellExe(raw) {
13647
+ if (!raw)
13648
+ return false;
13649
+ const t = raw.trim();
13650
+ if (!/^@?"[^"]*"$/.test(t))
13651
+ return false;
13652
+ const program = (t.replace(/^@?"|"$/g, "").split(/[\\/]/).pop() ?? "").toLowerCase().replace(/\.exe$/, "");
13653
+ return !CSHARP_SHELL_PROGRAMS.has(program);
13654
+ }
13655
+ var PSI_CTOR_EXE_RE = /\bnew\s+ProcessStartInfo\s*(?:<[^>]*>)?\s*\(\s*(@?"[^"]*")/;
13656
+ function processStartInfoExe(expr, sourceLines) {
13657
+ const inline = PSI_CTOR_EXE_RE.exec(expr);
13658
+ if (inline)
13659
+ return inline[1];
13660
+ if (sourceLines && /^[A-Za-z_]\w*$/.test(expr.trim())) {
13661
+ const varName = expr.trim();
13662
+ const assignRe = new RegExp(`\\b${varName}\\s*=\\s*new\\s+ProcessStartInfo\\s*(?:<[^>]*>)?\\s*\\(\\s*(@?"[^"]*")`);
13663
+ for (const line of sourceLines) {
13664
+ const m = assignRe.exec(line);
13665
+ if (m)
13666
+ return m[1];
13667
+ }
13668
+ }
13669
+ return null;
13670
+ }
13671
+ function isSafeCSharpProcessStartCall(call, pattern, language, sourceLines) {
13672
+ if (language !== "csharp")
13673
+ return false;
13674
+ if (pattern.type !== "command_injection")
13675
+ return false;
13676
+ const method = call.method_name;
13677
+ if (method !== "Start" && method !== "ProcessStartInfo")
13678
+ return false;
13679
+ if (call.arguments.length >= 2) {
13680
+ const fileArg = call.arguments.find((a) => a.position === 0);
13681
+ const raw = fileArg?.literal != null ? String(fileArg.literal) : fileArg?.expression;
13682
+ return isConstNonShellExe(raw);
13683
+ }
13684
+ if (method === "Start" && call.arguments.length === 1) {
13685
+ const arg0 = call.arguments.find((a) => a.position === 0);
13686
+ const expr = (arg0?.expression ?? "").trim();
13687
+ return isConstNonShellExe(processStartInfoExe(expr, sourceLines));
13688
+ }
13689
+ return false;
13690
+ }
13517
13691
  function isSafeRustCommandCall(call, pattern, language) {
13518
13692
  if (language !== "rust")
13519
13693
  return false;
@@ -13804,6 +13978,9 @@ function findSinks(calls, patterns, typeHierarchy, language, sourceLines, types)
13804
13978
  if (isSafeJSChildProcessCall(call, pattern, language)) {
13805
13979
  continue;
13806
13980
  }
13981
+ if (isSafeCSharpProcessStartCall(call, pattern, language, sourceLines)) {
13982
+ continue;
13983
+ }
13807
13984
  if (pattern.safe_if_class_literal_at !== undefined && argIsClassLiteral(call, pattern.safe_if_class_literal_at, types)) {
13808
13985
  continue;
13809
13986
  }
@@ -14944,7 +15121,7 @@ function canSourceReachSink(sourceType, sinkType) {
14944
15121
  file_input: ["deserialization", "xxe", "path_traversal", "command_injection", "code_injection"],
14945
15122
  network_input: ["sql_injection", "command_injection", "xss", "ssrf", "log_injection", "format_string", "nosql_injection", "prompt_injection"],
14946
15123
  config_param: ["sql_injection", "command_injection", "path_traversal", "xss", "ssrf", "log_injection", "format_string"],
14947
- interprocedural_param: ["sql_injection", "command_injection", "path_traversal", "xss", "xpath_injection", "ldap_injection", "ssrf", "code_injection", "mybatis_mapper_call", "crlf", "mass_assignment", "open_redirect", "trust_boundary", "log_injection", "format_string", "nosql_injection", "prompt_injection"],
15124
+ interprocedural_param: ["sql_injection", "command_injection", "path_traversal", "xss", "xpath_injection", "ldap_injection", "ssrf", "code_injection", "mybatis_mapper_call", "crlf", "mass_assignment", "open_redirect", "trust_boundary", "log_injection", "format_string", "nosql_injection", "prompt_injection", "xxe", "deserialization"],
14948
15125
  plugin_param: ["sql_injection", "command_injection", "path_traversal", "xss", "code_injection", "log_injection", "format_string"]
14949
15126
  };
14950
15127
  const validSinks = sourceToSinkMapping[sourceType];
@@ -26443,7 +26620,8 @@ function buildJavaTaintedVars(sourceCode, seedVars) {
26443
26620
  if (knownTainted.has(lhs))
26444
26621
  continue;
26445
26622
  const escaped = (v) => v.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
26446
- const ref = [...knownTainted].some((v) => new RegExp(`(?<![\\p{L}\\p{N}_])${escaped(v)}(?![\\p{L}\\p{N}_])`, "u").test(rhs));
26623
+ const rhsCode = rhs.replace(/\$@?"(?:[^"\\]|\\.)*"/g, (lit) => " " + [...lit.matchAll(/\{([^}]*)\}/g)].map((x) => x[1]).join(" ") + " ").replace(/@?"(?:[^"\\]|\\.)*"/g, " ").replace(/'(?:[^'\\]|\\.)'/g, " ");
26624
+ const ref = [...knownTainted].some((v) => new RegExp(`(?<![\\p{L}\\p{N}_])${escaped(v)}(?![\\p{L}\\p{N}_])`, "u").test(rhsCode));
26447
26625
  if (ref) {
26448
26626
  derived.set(lhs, i2 + 1);
26449
26627
  knownTainted.add(lhs);
@@ -41433,6 +41611,10 @@ function isLikelyCredentialAssignment(line) {
41433
41611
  return null;
41434
41612
  if (isAllSameChar(value))
41435
41613
  return null;
41614
+ if (value.toLowerCase() === name2.toLowerCase())
41615
+ return null;
41616
+ if (/^(?:https?:\/\/|urn:|xmlns)/i.test(value))
41617
+ return null;
41436
41618
  if (value.length < 12)
41437
41619
  return null;
41438
41620
  if (shannonEntropy(value) < 3.5)
@@ -44098,9 +44280,14 @@ class InsecureDeserializationConfigPass {
44098
44280
  name = "insecure-deserialization-config";
44099
44281
  category = "security";
44100
44282
  run(ctx) {
44283
+ if (ctx.language === "java")
44284
+ return this.runJava(ctx);
44285
+ if (ctx.language === "csharp")
44286
+ return this.runCSharp(ctx);
44287
+ return { findings: [] };
44288
+ }
44289
+ runJava(ctx) {
44101
44290
  const { graph, language } = ctx;
44102
- if (language !== "java")
44103
- return { findings: [] };
44104
44291
  const file = graph.ir.meta.file;
44105
44292
  const findings = [];
44106
44293
  for (const call of graph.ir.calls) {
@@ -44126,6 +44313,35 @@ class InsecureDeserializationConfigPass {
44126
44313
  }
44127
44314
  return { findings };
44128
44315
  }
44316
+ runCSharp(ctx) {
44317
+ const file = ctx.graph.ir.meta.file;
44318
+ const findings = [];
44319
+ const lines = ctx.code.split(`
44320
+ `);
44321
+ for (let i2 = 0;i2 < lines.length; i2++) {
44322
+ const m = INSECURE_TYPE_NAME_HANDLING_RE.exec(lines[i2]);
44323
+ if (!m)
44324
+ continue;
44325
+ const line = i2 + 1;
44326
+ const api = `TypeNameHandling = TypeNameHandling.${m[1]}`;
44327
+ findings.push({ line, api });
44328
+ ctx.addFinding({
44329
+ id: `${this.name}-${file}-${line}`,
44330
+ pass: this.name,
44331
+ category: this.category,
44332
+ rule_id: this.name,
44333
+ cwe: "CWE-502",
44334
+ severity: "high",
44335
+ level: "error",
44336
+ message: `Json.NET configured with TypeNameHandling.${m[1]}: a $type field in ` + "untrusted JSON can instantiate arbitrary .NET types (deserialization RCE)",
44337
+ file,
44338
+ line,
44339
+ fix: "Use TypeNameHandling.None (the default), or bind a SerializationBinder that allow-lists the exact types you deserialize.",
44340
+ evidence: { api, language: "csharp" }
44341
+ });
44342
+ }
44343
+ return { findings };
44344
+ }
44129
44345
  isPermissiveXStreamConfig(call) {
44130
44346
  if (call.method_name !== "addPermission")
44131
44347
  return false;
@@ -44133,6 +44349,7 @@ class InsecureDeserializationConfigPass {
44133
44349
  return typeof arg0 === "string" && ANY_TYPE_PERMISSION_RE.test(arg0);
44134
44350
  }
44135
44351
  }
44352
+ var INSECURE_TYPE_NAME_HANDLING_RE = /\bTypeNameHandling\s*=\s*(?:Newtonsoft\.Json\.)?TypeNameHandling\.(All|Auto|Objects|Arrays)\b/;
44136
44353
 
44137
44354
  // ../circle-ir/dist/analysis/passes/plaintext-password-storage-pass.js
44138
44355
  function isWriteStorageCall(call, language) {
@@ -46533,6 +46750,24 @@ function getNodeTypesForLanguage(language) {
46533
46750
  "selector_expression",
46534
46751
  "identifier"
46535
46752
  ]);
46753
+ case "csharp":
46754
+ return new Set([
46755
+ "method_invocation",
46756
+ "object_creation_expression",
46757
+ "class_declaration",
46758
+ "method_declaration",
46759
+ "constructor_declaration",
46760
+ "field_declaration",
46761
+ "import_declaration",
46762
+ "interface_declaration",
46763
+ "enum_declaration",
46764
+ "package_declaration",
46765
+ "local_variable_declaration",
46766
+ "destructor_declaration",
46767
+ "operator_declaration",
46768
+ "local_function_statement",
46769
+ "accessor_declaration"
46770
+ ]);
46536
46771
  default:
46537
46772
  return new Set([
46538
46773
  "method_invocation",
@@ -48085,7 +48320,7 @@ var colors = {
48085
48320
  };
48086
48321
 
48087
48322
  // src/version.ts
48088
- var version = "4.7.1";
48323
+ var version = "4.8.2";
48089
48324
 
48090
48325
  // src/formatters.ts
48091
48326
  var LIBRARY_API_SURFACE_TAG2 = "library-api-surface:caller-responsibility";
@@ -49163,7 +49398,9 @@ async function initWasm(spin) {
49163
49398
  typescript: join3(wasmDir, "tree-sitter-javascript.wasm"),
49164
49399
  python: join3(wasmDir, "tree-sitter-python.wasm"),
49165
49400
  rust: join3(wasmDir, "tree-sitter-rust.wasm"),
49166
- html: join3(wasmDir, "tree-sitter-html.wasm")
49401
+ html: join3(wasmDir, "tree-sitter-html.wasm"),
49402
+ csharp: join3(wasmDir, "tree-sitter-csharp.wasm"),
49403
+ tsx: join3(wasmDir, "tree-sitter-tsx.wasm")
49167
49404
  }
49168
49405
  });
49169
49406
  } else {
@@ -49196,7 +49433,9 @@ Please ensure the wasm/ directory is located next to the binary or in your curre
49196
49433
  typescript: wasmBasePath + "tree-sitter-javascript.wasm",
49197
49434
  python: wasmBasePath + "tree-sitter-python.wasm",
49198
49435
  rust: wasmBasePath + "tree-sitter-rust.wasm",
49199
- html: wasmBasePath + "tree-sitter-html.wasm"
49436
+ html: wasmBasePath + "tree-sitter-html.wasm",
49437
+ csharp: wasmBasePath + "tree-sitter-csharp.wasm",
49438
+ tsx: wasmBasePath + "tree-sitter-tsx.wasm"
49200
49439
  }
49201
49440
  });
49202
49441
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cognium-dev",
3
- "version": "4.7.1",
3
+ "version": "4.8.2",
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.7.1"
69
+ "circle-ir": "^4.8.2"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@types/node": "^25.5.0",