cognium-dev 4.7.2 → 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 +239 -72
  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;
@@ -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"] },
@@ -12359,6 +12446,7 @@ var DEFAULT_SINKS = [
12359
12446
  { method: "Delete", class: "Directory", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
12360
12447
  { method: "GetFiles", class: "Directory", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
12361
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"] },
12362
12450
  { method: "GetAsync", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["csharp"] },
12363
12451
  { method: "PostAsync", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["csharp"] },
12364
12452
  { method: "PutAsync", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["csharp"] },
@@ -12384,6 +12472,8 @@ var DEFAULT_SINKS = [
12384
12472
  { method: "Raw", class: "Html", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0], languages: ["csharp"] },
12385
12473
  { method: "Write", class: "Response", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0], languages: ["csharp"] },
12386
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"] },
12387
12477
  { method: "DirectorySearcher", type: "ldap_injection", cwe: "CWE-90", severity: "high", arg_positions: [0], languages: ["csharp"] },
12388
12478
  { method: "DirectoryEntry", type: "ldap_injection", cwe: "CWE-90", severity: "high", arg_positions: [0], languages: ["csharp"] },
12389
12479
  { method: "Redirect", type: "open_redirect", cwe: "CWE-601", severity: "medium", arg_positions: [0], languages: ["csharp"] },
@@ -12401,6 +12491,8 @@ var DEFAULT_SINKS = [
12401
12491
  { method: "SelectSingleNode", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
12402
12492
  { method: "SelectNodes", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
12403
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"] },
12404
12496
  { method: "LoadXml", type: "xxe", cwe: "CWE-611", severity: "high", arg_positions: [0], languages: ["csharp"] },
12405
12497
  { method: "Load", class: "XmlDocument", type: "xxe", cwe: "CWE-611", severity: "high", arg_positions: [0], languages: ["csharp"] },
12406
12498
  { method: "Load", class: "XDocument", type: "xxe", cwe: "CWE-611", severity: "high", arg_positions: [0], languages: ["csharp"] },
@@ -13540,39 +13632,61 @@ function isSafeJSChildProcessCall(call, pattern, language) {
13540
13632
  return false;
13541
13633
  return true;
13542
13634
  }
13543
- function isSafeCSharpProcessStartCall(call, pattern, language) {
13544
- if (language !== "csharp")
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)
13545
13648
  return false;
13546
- if (pattern.type !== "command_injection")
13649
+ const t = raw.trim();
13650
+ if (!/^@?"[^"]*"$/.test(t))
13547
13651
  return false;
13548
- if (call.method_name !== "Start")
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")
13549
13673
  return false;
13550
- if (call.arguments.length < 2)
13674
+ if (pattern.type !== "command_injection")
13551
13675
  return false;
13552
- const fileArg = call.arguments.find((a) => a.position === 0);
13553
- if (!fileArg)
13676
+ const method = call.method_name;
13677
+ if (method !== "Start" && method !== "ProcessStartInfo")
13554
13678
  return false;
13555
- let raw;
13556
- if (fileArg.literal !== null && fileArg.literal !== undefined) {
13557
- raw = String(fileArg.literal).trim();
13558
- } else {
13559
- raw = (fileArg.expression ?? "").trim();
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);
13560
13683
  }
13561
- if (!/^@?"[^"]*"$/.test(raw))
13562
- return false;
13563
- const program = (raw.replace(/^@?"|"$/g, "").split(/[\\/]/).pop() ?? "").toLowerCase().replace(/\.exe$/, "");
13564
- const SHELL_PROGRAMS = new Set([
13565
- "sh",
13566
- "bash",
13567
- "zsh",
13568
- "dash",
13569
- "ash",
13570
- "ksh",
13571
- "cmd",
13572
- "powershell",
13573
- "pwsh"
13574
- ]);
13575
- return !SHELL_PROGRAMS.has(program);
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;
13576
13690
  }
13577
13691
  function isSafeRustCommandCall(call, pattern, language) {
13578
13692
  if (language !== "rust")
@@ -13864,7 +13978,7 @@ function findSinks(calls, patterns, typeHierarchy, language, sourceLines, types)
13864
13978
  if (isSafeJSChildProcessCall(call, pattern, language)) {
13865
13979
  continue;
13866
13980
  }
13867
- if (isSafeCSharpProcessStartCall(call, pattern, language)) {
13981
+ if (isSafeCSharpProcessStartCall(call, pattern, language, sourceLines)) {
13868
13982
  continue;
13869
13983
  }
13870
13984
  if (pattern.safe_if_class_literal_at !== undefined && argIsClassLiteral(call, pattern.safe_if_class_literal_at, types)) {
@@ -44166,9 +44280,14 @@ class InsecureDeserializationConfigPass {
44166
44280
  name = "insecure-deserialization-config";
44167
44281
  category = "security";
44168
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) {
44169
44290
  const { graph, language } = ctx;
44170
- if (language !== "java")
44171
- return { findings: [] };
44172
44291
  const file = graph.ir.meta.file;
44173
44292
  const findings = [];
44174
44293
  for (const call of graph.ir.calls) {
@@ -44194,6 +44313,35 @@ class InsecureDeserializationConfigPass {
44194
44313
  }
44195
44314
  return { findings };
44196
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
+ }
44197
44345
  isPermissiveXStreamConfig(call) {
44198
44346
  if (call.method_name !== "addPermission")
44199
44347
  return false;
@@ -44201,6 +44349,7 @@ class InsecureDeserializationConfigPass {
44201
44349
  return typeof arg0 === "string" && ANY_TYPE_PERMISSION_RE.test(arg0);
44202
44350
  }
44203
44351
  }
44352
+ var INSECURE_TYPE_NAME_HANDLING_RE = /\bTypeNameHandling\s*=\s*(?:Newtonsoft\.Json\.)?TypeNameHandling\.(All|Auto|Objects|Arrays)\b/;
44204
44353
 
44205
44354
  // ../circle-ir/dist/analysis/passes/plaintext-password-storage-pass.js
44206
44355
  function isWriteStorageCall(call, language) {
@@ -46601,6 +46750,24 @@ function getNodeTypesForLanguage(language) {
46601
46750
  "selector_expression",
46602
46751
  "identifier"
46603
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
+ ]);
46604
46771
  default:
46605
46772
  return new Set([
46606
46773
  "method_invocation",
@@ -48153,7 +48320,7 @@ var colors = {
48153
48320
  };
48154
48321
 
48155
48322
  // src/version.ts
48156
- var version = "4.7.2";
48323
+ var version = "4.8.2";
48157
48324
 
48158
48325
  // src/formatters.ts
48159
48326
  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.7.2",
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.2"
69
+ "circle-ir": "^4.8.2"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@types/node": "^25.5.0",