circle-ir 4.7.2 → 4.9.7

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 (40) hide show
  1. package/dist/analysis/config-loader.d.ts.map +1 -1
  2. package/dist/analysis/config-loader.js +34 -0
  3. package/dist/analysis/config-loader.js.map +1 -1
  4. package/dist/analysis/passes/insecure-cookie-pass.d.ts +1 -0
  5. package/dist/analysis/passes/insecure-cookie-pass.d.ts.map +1 -1
  6. package/dist/analysis/passes/insecure-cookie-pass.js +37 -3
  7. package/dist/analysis/passes/insecure-cookie-pass.js.map +1 -1
  8. package/dist/analysis/passes/insecure-deserialization-config-pass.d.ts +2 -0
  9. package/dist/analysis/passes/insecure-deserialization-config-pass.d.ts.map +1 -1
  10. package/dist/analysis/passes/insecure-deserialization-config-pass.js +45 -2
  11. package/dist/analysis/passes/insecure-deserialization-config-pass.js.map +1 -1
  12. package/dist/analysis/passes/jwt-verify-disabled-pass.d.ts.map +1 -1
  13. package/dist/analysis/passes/jwt-verify-disabled-pass.js +48 -21
  14. package/dist/analysis/passes/jwt-verify-disabled-pass.js.map +1 -1
  15. package/dist/analysis/passes/language-sources-pass.d.ts.map +1 -1
  16. package/dist/analysis/passes/language-sources-pass.js +131 -0
  17. package/dist/analysis/passes/language-sources-pass.js.map +1 -1
  18. package/dist/analysis/passes/tls-verify-disabled-pass.d.ts.map +1 -1
  19. package/dist/analysis/passes/tls-verify-disabled-pass.js +34 -0
  20. package/dist/analysis/passes/tls-verify-disabled-pass.js.map +1 -1
  21. package/dist/analysis/passes/weak-crypto-pass.d.ts.map +1 -1
  22. package/dist/analysis/passes/weak-crypto-pass.js +32 -19
  23. package/dist/analysis/passes/weak-crypto-pass.js.map +1 -1
  24. package/dist/analysis/taint-matcher.d.ts.map +1 -1
  25. package/dist/analysis/taint-matcher.js +293 -25
  26. package/dist/analysis/taint-matcher.js.map +1 -1
  27. package/dist/analyzer.d.ts.map +1 -1
  28. package/dist/analyzer.js +14 -0
  29. package/dist/analyzer.js.map +1 -1
  30. package/dist/browser/circle-ir.js +660 -109
  31. package/dist/core/circle-ir-core.cjs +411 -68
  32. package/dist/core/circle-ir-core.js +411 -68
  33. package/dist/core/extractors/calls.js +17 -3
  34. package/dist/core/extractors/calls.js.map +1 -1
  35. package/dist/core/extractors/cfg.d.ts.map +1 -1
  36. package/dist/core/extractors/cfg.js +140 -40
  37. package/dist/core/extractors/cfg.js.map +1 -1
  38. package/dist/core/extractors/types.js +77 -2
  39. package/dist/core/extractors/types.js.map +1 -1
  40. package/package.json +1 -1
@@ -4355,6 +4355,7 @@ function extractCSharpTypes(tree, cache) {
4355
4355
  const nameNode = node.childForFieldName("name");
4356
4356
  const body2 = node.childForFieldName("body");
4357
4357
  const methods = [];
4358
+ const fields = extractCSharpFields(body2);
4358
4359
  if (body2) {
4359
4360
  for (let i2 = 0; i2 < body2.childCount; i2++) {
4360
4361
  const m = body2.child(i2);
@@ -4372,7 +4373,7 @@ function extractCSharpTypes(tree, cache) {
4372
4373
  parameters.push({
4373
4374
  name: getNodeText(pName),
4374
4375
  type: pType ? getNodeText(pType) : null,
4375
- annotations: [],
4376
+ annotations: extractCSharpParamAnnotations(pnode),
4376
4377
  line: pnode.startPosition.row + 1
4377
4378
  });
4378
4379
  }
@@ -4398,7 +4399,7 @@ function extractCSharpTypes(tree, cache) {
4398
4399
  implements: [],
4399
4400
  annotations: [],
4400
4401
  methods,
4401
- fields: [],
4402
+ fields,
4402
4403
  start_line: node.startPosition.row + 1,
4403
4404
  end_line: node.endPosition.row + 1
4404
4405
  });
@@ -4406,6 +4407,59 @@ function extractCSharpTypes(tree, cache) {
4406
4407
  }
4407
4408
  return types;
4408
4409
  }
4410
+ function extractCSharpFields(body2) {
4411
+ const fields = [];
4412
+ if (!body2) return fields;
4413
+ for (let i2 = 0; i2 < body2.childCount; i2++) {
4414
+ const c = body2.child(i2);
4415
+ if (!c) continue;
4416
+ if (c.type === "field_declaration") {
4417
+ let varDecl = null;
4418
+ for (let k = 0; k < c.childCount; k++) {
4419
+ const cc = c.child(k);
4420
+ if (cc?.type === "variable_declaration") {
4421
+ varDecl = cc;
4422
+ break;
4423
+ }
4424
+ }
4425
+ if (!varDecl) continue;
4426
+ const typeNode = varDecl.childForFieldName("type");
4427
+ const type = typeNode ? getNodeText(typeNode) : null;
4428
+ const modifiers = extractCSharpModifiers(c);
4429
+ for (let k = 0; k < varDecl.childCount; k++) {
4430
+ const decl = varDecl.child(k);
4431
+ if (decl?.type !== "variable_declarator") continue;
4432
+ const nameNode = decl.childForFieldName("name");
4433
+ fields.push({ name: nameNode ? getNodeText(nameNode) : "unknown", type, modifiers, annotations: [] });
4434
+ }
4435
+ } else if (c.type === "property_declaration") {
4436
+ const nameNode = c.childForFieldName("name");
4437
+ if (!nameNode) continue;
4438
+ const typeNode = c.childForFieldName("type");
4439
+ fields.push({
4440
+ name: getNodeText(nameNode),
4441
+ type: typeNode ? getNodeText(typeNode) : null,
4442
+ modifiers: extractCSharpModifiers(c),
4443
+ annotations: []
4444
+ });
4445
+ }
4446
+ }
4447
+ return fields;
4448
+ }
4449
+ function extractCSharpParamAnnotations(param) {
4450
+ const out2 = [];
4451
+ for (let i2 = 0; i2 < param.childCount; i2++) {
4452
+ const list = param.child(i2);
4453
+ if (list?.type !== "attribute_list") continue;
4454
+ for (let j = 0; j < list.childCount; j++) {
4455
+ const attr = list.child(j);
4456
+ if (attr?.type !== "attribute") continue;
4457
+ const name2 = attr.childForFieldName("name");
4458
+ if (name2) out2.push(getNodeText(name2));
4459
+ }
4460
+ }
4461
+ return out2;
4462
+ }
4409
4463
  function extractCSharpModifiers(node) {
4410
4464
  const mods = [];
4411
4465
  for (let i2 = 0; i2 < node.childCount; i2++) {
@@ -5980,13 +6034,21 @@ function extractCSharpCalls(tree, cache) {
5980
6034
  const left = asn.childForFieldName("left");
5981
6035
  if (left?.type !== "member_access_expression") continue;
5982
6036
  const nameNode = left.childForFieldName("name");
5983
- if (!nameNode || getNodeText(nameNode) !== "CommandText") continue;
6037
+ if (!nameNode) continue;
6038
+ const propName = getNodeText(nameNode);
6039
+ const exprNode = left.childForFieldName("expression");
6040
+ if (propName === "Filter") {
6041
+ const recv = exprNode ? getNodeText(exprNode) : null;
6042
+ const recvType = recv ? typeMap.get(recv) : void 0;
6043
+ if (recvType !== "DirectorySearcher") continue;
6044
+ } else if (propName !== "CommandText") {
6045
+ continue;
6046
+ }
5984
6047
  const right = asn.childForFieldName("right");
5985
6048
  if (!right) continue;
5986
6049
  const rhsText = getNodeText(right);
5987
- const exprNode = left.childForFieldName("expression");
5988
6050
  calls.push({
5989
- method_name: "CommandText",
6051
+ method_name: propName,
5990
6052
  receiver: exprNode ? getNodeText(exprNode) : null,
5991
6053
  receiver_type: null,
5992
6054
  receiver_type_fqn: null,
@@ -8552,6 +8614,9 @@ function buildCFG(tree, language, cache) {
8552
8614
  if (effectiveLanguage === "go") {
8553
8615
  return buildGoCFG(tree, blockIdCounter, cache);
8554
8616
  }
8617
+ if (effectiveLanguage === "csharp") {
8618
+ return buildCSharpCFG(tree, blockIdCounter, cache);
8619
+ }
8555
8620
  if (isJavaScript) {
8556
8621
  const functions = [
8557
8622
  ...getNodesFromCache(tree.rootNode, "function_declaration", cache),
@@ -8564,7 +8629,7 @@ function buildCFG(tree, language, cache) {
8564
8629
  const body2 = func2.childForFieldName("body");
8565
8630
  if (!body2) continue;
8566
8631
  if (body2.type === "statement_block") {
8567
- const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, true);
8632
+ const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, "js");
8568
8633
  allBlocks.push(...blocks);
8569
8634
  allEdges.push(...edges);
8570
8635
  blockIdCounter = nextId;
@@ -8586,7 +8651,7 @@ function buildCFG(tree, language, cache) {
8586
8651
  for (const method of methods) {
8587
8652
  const body2 = method.childForFieldName("body");
8588
8653
  if (!body2) continue;
8589
- const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, false);
8654
+ const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, "java");
8590
8655
  allBlocks.push(...blocks);
8591
8656
  allEdges.push(...edges);
8592
8657
  blockIdCounter = nextId;
@@ -8594,7 +8659,28 @@ function buildCFG(tree, language, cache) {
8594
8659
  }
8595
8660
  return { blocks: allBlocks, edges: allEdges };
8596
8661
  }
8597
- function buildMethodCFG(body2, startId, isJavaScript) {
8662
+ function buildCSharpCFG(tree, blockIdCounter, cache) {
8663
+ const allBlocks = [];
8664
+ const allEdges = [];
8665
+ const containers = [
8666
+ ...getNodesFromCache(tree.rootNode, "method_declaration", cache),
8667
+ ...getNodesFromCache(tree.rootNode, "constructor_declaration", cache),
8668
+ ...getNodesFromCache(tree.rootNode, "destructor_declaration", cache),
8669
+ ...getNodesFromCache(tree.rootNode, "operator_declaration", cache),
8670
+ ...getNodesFromCache(tree.rootNode, "local_function_statement", cache),
8671
+ ...getNodesFromCache(tree.rootNode, "accessor_declaration", cache)
8672
+ ];
8673
+ for (const container of containers) {
8674
+ const body2 = container.childForFieldName("body");
8675
+ if (!body2 || body2.type !== "block") continue;
8676
+ const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, "csharp");
8677
+ allBlocks.push(...blocks);
8678
+ allEdges.push(...edges);
8679
+ blockIdCounter = nextId;
8680
+ }
8681
+ return { blocks: allBlocks, edges: allEdges };
8682
+ }
8683
+ function buildMethodCFG(body2, startId, dialect) {
8598
8684
  const blocks = [];
8599
8685
  const edges = [];
8600
8686
  let currentId = startId;
@@ -8605,7 +8691,7 @@ function buildMethodCFG(body2, startId, isJavaScript) {
8605
8691
  end_line: body2.startPosition.row + 1
8606
8692
  };
8607
8693
  blocks.push(entryBlock);
8608
- const result = processStatements(body2, currentId, blocks, edges, isJavaScript);
8694
+ const result = processStatements(body2, currentId, blocks, edges, dialect);
8609
8695
  currentId = result.nextId;
8610
8696
  if (result.entryId !== -1) {
8611
8697
  edges.push({
@@ -8637,15 +8723,15 @@ function buildMethodCFG(body2, startId, isJavaScript) {
8637
8723
  }
8638
8724
  return { blocks, edges, nextId: currentId };
8639
8725
  }
8640
- function processStatements(container, startId, blocks, edges, isJavaScript) {
8726
+ function processStatements(container, startId, blocks, edges, dialect) {
8641
8727
  let currentId = startId;
8642
8728
  let firstBlockId = -1;
8643
8729
  let lastExitIds = [];
8644
8730
  for (let i2 = 0; i2 < container.childCount; i2++) {
8645
8731
  const stmt = container.child(i2);
8646
8732
  if (!stmt) continue;
8647
- if (!isStatement(stmt, isJavaScript)) continue;
8648
- const result = processStatement(stmt, currentId, blocks, edges, isJavaScript);
8733
+ if (!isStatement(stmt, dialect)) continue;
8734
+ const result = processStatement(stmt, currentId, blocks, edges, dialect);
8649
8735
  currentId = result.nextId;
8650
8736
  if (firstBlockId === -1) {
8651
8737
  firstBlockId = result.entryId;
@@ -8666,31 +8752,49 @@ function processStatements(container, startId, blocks, edges, isJavaScript) {
8666
8752
  nextId: currentId
8667
8753
  };
8668
8754
  }
8669
- function processStatement(stmt, startId, blocks, edges, isJavaScript) {
8755
+ function processStatement(stmt, startId, blocks, edges, dialect) {
8670
8756
  switch (stmt.type) {
8671
8757
  case "if_statement":
8672
- return processIfStatement(stmt, startId, blocks, edges, isJavaScript);
8758
+ return processIfStatement(stmt, startId, blocks, edges, dialect);
8673
8759
  case "for_statement":
8674
8760
  case "enhanced_for_statement":
8675
8761
  case "for_in_statement":
8676
8762
  case "for_of_statement":
8677
- return processForStatement(stmt, startId, blocks, edges, isJavaScript);
8763
+ case "foreach_statement":
8764
+ return processForStatement(stmt, startId, blocks, edges, dialect);
8678
8765
  case "while_statement":
8679
- return processWhileStatement(stmt, startId, blocks, edges, isJavaScript);
8766
+ return processWhileStatement(stmt, startId, blocks, edges, dialect);
8680
8767
  case "do_statement":
8681
- return processDoWhileStatement(stmt, startId, blocks, edges, isJavaScript);
8768
+ return processDoWhileStatement(stmt, startId, blocks, edges, dialect);
8682
8769
  case "try_statement":
8683
- return processTryStatement(stmt, startId, blocks, edges, isJavaScript);
8770
+ return processTryStatement(stmt, startId, blocks, edges, dialect);
8684
8771
  case "switch_expression":
8685
8772
  case "switch_statement":
8686
- return processSwitchStatement(stmt, startId, blocks, edges, isJavaScript);
8773
+ return processSwitchStatement(stmt, startId, blocks, edges, dialect);
8774
+ // C# scoped blocks add no branching — flow through the inner block so its
8775
+ // nested statements are still captured.
8776
+ case "using_statement":
8777
+ case "lock_statement":
8778
+ case "checked_statement":
8779
+ case "unsafe_statement": {
8780
+ const inner = stmt.childForFieldName("body") ?? lastBlockChild(stmt);
8781
+ if (inner) return processStatement(inner, startId, blocks, edges, dialect);
8782
+ return processSimpleStatement(stmt, startId, blocks);
8783
+ }
8687
8784
  case "block":
8688
8785
  case "statement_block":
8689
- return processStatements(stmt, startId, blocks, edges, isJavaScript);
8786
+ return processStatements(stmt, startId, blocks, edges, dialect);
8690
8787
  default:
8691
8788
  return processSimpleStatement(stmt, startId, blocks);
8692
8789
  }
8693
8790
  }
8791
+ function lastBlockChild(node) {
8792
+ for (let i2 = node.childCount - 1; i2 >= 0; i2--) {
8793
+ const c = node.child(i2);
8794
+ if (c && c.type === "block") return c;
8795
+ }
8796
+ return null;
8797
+ }
8694
8798
  function processSimpleStatement(stmt, startId, blocks) {
8695
8799
  const block = {
8696
8800
  id: startId,
@@ -8705,7 +8809,7 @@ function processSimpleStatement(stmt, startId, blocks) {
8705
8809
  nextId: startId + 1
8706
8810
  };
8707
8811
  }
8708
- function processIfStatement(stmt, startId, blocks, edges, isJavaScript) {
8812
+ function processIfStatement(stmt, startId, blocks, edges, dialect) {
8709
8813
  let currentId = startId;
8710
8814
  const condBlock = {
8711
8815
  id: currentId++,
@@ -8717,7 +8821,7 @@ function processIfStatement(stmt, startId, blocks, edges, isJavaScript) {
8717
8821
  const exitIds = [];
8718
8822
  const consequence = stmt.childForFieldName("consequence");
8719
8823
  if (consequence) {
8720
- const thenResult = processStatement(consequence, currentId, blocks, edges, isJavaScript);
8824
+ const thenResult = processStatement(consequence, currentId, blocks, edges, dialect);
8721
8825
  currentId = thenResult.nextId;
8722
8826
  edges.push({
8723
8827
  from: condBlock.id,
@@ -8728,7 +8832,7 @@ function processIfStatement(stmt, startId, blocks, edges, isJavaScript) {
8728
8832
  }
8729
8833
  const alternative = stmt.childForFieldName("alternative");
8730
8834
  if (alternative) {
8731
- const elseResult = processStatement(alternative, currentId, blocks, edges, isJavaScript);
8835
+ const elseResult = processStatement(alternative, currentId, blocks, edges, dialect);
8732
8836
  currentId = elseResult.nextId;
8733
8837
  edges.push({
8734
8838
  from: condBlock.id,
@@ -8745,7 +8849,7 @@ function processIfStatement(stmt, startId, blocks, edges, isJavaScript) {
8745
8849
  nextId: currentId
8746
8850
  };
8747
8851
  }
8748
- function processForStatement(stmt, startId, blocks, edges, isJavaScript) {
8852
+ function processForStatement(stmt, startId, blocks, edges, dialect) {
8749
8853
  let currentId = startId;
8750
8854
  const loopBlock = {
8751
8855
  id: currentId++,
@@ -8756,7 +8860,7 @@ function processForStatement(stmt, startId, blocks, edges, isJavaScript) {
8756
8860
  blocks.push(loopBlock);
8757
8861
  const body2 = stmt.childForFieldName("body");
8758
8862
  if (body2) {
8759
- const bodyResult = processStatement(body2, currentId, blocks, edges, isJavaScript);
8863
+ const bodyResult = processStatement(body2, currentId, blocks, edges, dialect);
8760
8864
  currentId = bodyResult.nextId;
8761
8865
  edges.push({
8762
8866
  from: loopBlock.id,
@@ -8778,16 +8882,16 @@ function processForStatement(stmt, startId, blocks, edges, isJavaScript) {
8778
8882
  nextId: currentId
8779
8883
  };
8780
8884
  }
8781
- function processWhileStatement(stmt, startId, blocks, edges, isJavaScript) {
8782
- return processForStatement(stmt, startId, blocks, edges, isJavaScript);
8885
+ function processWhileStatement(stmt, startId, blocks, edges, dialect) {
8886
+ return processForStatement(stmt, startId, blocks, edges, dialect);
8783
8887
  }
8784
- function processDoWhileStatement(stmt, startId, blocks, edges, isJavaScript) {
8888
+ function processDoWhileStatement(stmt, startId, blocks, edges, dialect) {
8785
8889
  let currentId = startId;
8786
8890
  const body2 = stmt.childForFieldName("body");
8787
8891
  let bodyEntryId = currentId;
8788
8892
  let bodyExitIds = [];
8789
8893
  if (body2) {
8790
- const bodyResult = processStatement(body2, currentId, blocks, edges, isJavaScript);
8894
+ const bodyResult = processStatement(body2, currentId, blocks, edges, dialect);
8791
8895
  currentId = bodyResult.nextId;
8792
8896
  bodyEntryId = bodyResult.entryId;
8793
8897
  bodyExitIds = bodyResult.exitIds;
@@ -8817,13 +8921,13 @@ function processDoWhileStatement(stmt, startId, blocks, edges, isJavaScript) {
8817
8921
  nextId: currentId
8818
8922
  };
8819
8923
  }
8820
- function processTryStatement(stmt, startId, blocks, edges, isJavaScript) {
8924
+ function processTryStatement(stmt, startId, blocks, edges, dialect) {
8821
8925
  let currentId = startId;
8822
8926
  const exitIds = [];
8823
8927
  const body2 = stmt.childForFieldName("body");
8824
8928
  let tryEntryId = -1;
8825
8929
  if (body2) {
8826
- const bodyResult = processStatements(body2, currentId, blocks, edges, isJavaScript);
8930
+ const bodyResult = processStatements(body2, currentId, blocks, edges, dialect);
8827
8931
  currentId = bodyResult.nextId;
8828
8932
  tryEntryId = bodyResult.entryId;
8829
8933
  exitIds.push(...bodyResult.exitIds);
@@ -8833,7 +8937,7 @@ function processTryStatement(stmt, startId, blocks, edges, isJavaScript) {
8833
8937
  if (child?.type === "catch_clause") {
8834
8938
  const catchBody = child.childForFieldName("body");
8835
8939
  if (catchBody) {
8836
- const catchResult = processStatements(catchBody, currentId, blocks, edges, isJavaScript);
8940
+ const catchResult = processStatements(catchBody, currentId, blocks, edges, dialect);
8837
8941
  currentId = catchResult.nextId;
8838
8942
  if (tryEntryId !== -1) {
8839
8943
  edges.push({
@@ -8846,9 +8950,18 @@ function processTryStatement(stmt, startId, blocks, edges, isJavaScript) {
8846
8950
  }
8847
8951
  }
8848
8952
  }
8849
- const finallyClause = stmt.childForFieldName("finally") ?? stmt.childForFieldName("finalizer");
8953
+ let finallyClause = stmt.childForFieldName("finally") ?? stmt.childForFieldName("finalizer");
8954
+ if (!finallyClause && dialect === "csharp") {
8955
+ for (let i2 = 0; i2 < stmt.childCount; i2++) {
8956
+ const child = stmt.child(i2);
8957
+ if (child?.type === "finally_clause") {
8958
+ finallyClause = lastBlockChild(child);
8959
+ break;
8960
+ }
8961
+ }
8962
+ }
8850
8963
  if (finallyClause) {
8851
- const finallyResult = processStatements(finallyClause, currentId, blocks, edges, isJavaScript);
8964
+ const finallyResult = processStatements(finallyClause, currentId, blocks, edges, dialect);
8852
8965
  currentId = finallyResult.nextId;
8853
8966
  for (const exitId of exitIds) {
8854
8967
  edges.push({
@@ -8869,7 +8982,7 @@ function processTryStatement(stmt, startId, blocks, edges, isJavaScript) {
8869
8982
  nextId: currentId
8870
8983
  };
8871
8984
  }
8872
- function processSwitchStatement(stmt, startId, blocks, edges, isJavaScript) {
8985
+ function processSwitchStatement(stmt, startId, blocks, edges, dialect) {
8873
8986
  let currentId = startId;
8874
8987
  const switchBlock = {
8875
8988
  id: currentId++,
@@ -8881,11 +8994,11 @@ function processSwitchStatement(stmt, startId, blocks, edges, isJavaScript) {
8881
8994
  const exitIds = [];
8882
8995
  const body2 = stmt.childForFieldName("body");
8883
8996
  if (body2) {
8884
- const caseTypes = isJavaScript ? ["switch_case", "switch_default"] : ["switch_block_statement_group", "switch_rule"];
8997
+ const caseTypes = dialect === "js" ? ["switch_case", "switch_default"] : dialect === "csharp" ? ["switch_section"] : ["switch_block_statement_group", "switch_rule"];
8885
8998
  for (let i2 = 0; i2 < body2.childCount; i2++) {
8886
8999
  const child = body2.child(i2);
8887
9000
  if (child && caseTypes.includes(child.type)) {
8888
- const caseResult = processStatements(child, currentId, blocks, edges, isJavaScript);
9001
+ const caseResult = processStatements(child, currentId, blocks, edges, dialect);
8889
9002
  currentId = caseResult.nextId;
8890
9003
  if (caseResult.entryId !== -1) {
8891
9004
  edges.push({
@@ -8915,7 +9028,7 @@ function buildBashCFG(tree, startId, cache) {
8915
9028
  for (const func2 of functions) {
8916
9029
  const body2 = func2.childForFieldName("body");
8917
9030
  if (!body2) continue;
8918
- const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, false);
9031
+ const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, "java");
8919
9032
  allBlocks.push(...blocks);
8920
9033
  allEdges.push(...edges);
8921
9034
  blockIdCounter = nextId;
@@ -8938,7 +9051,7 @@ function buildBashCFG(tree, startId, cache) {
8938
9051
  let lastExitIds = [];
8939
9052
  let firstBlockId = -1;
8940
9053
  for (const stmt of topLevelStatements) {
8941
- const result = processStatement(stmt, blockIdCounter, allBlocks, allEdges, false);
9054
+ const result = processStatement(stmt, blockIdCounter, allBlocks, allEdges, "java");
8942
9055
  blockIdCounter = result.nextId;
8943
9056
  if (firstBlockId === -1) {
8944
9057
  firstBlockId = result.entryId;
@@ -8982,7 +9095,8 @@ function isBashStatement(node) {
8982
9095
  ]);
8983
9096
  return bashStatementTypes.has(node.type);
8984
9097
  }
8985
- function isStatement(node, isJavaScript) {
9098
+ function isStatement(node, dialect) {
9099
+ if (dialect === "csharp") return csharpStatementTypes.has(node.type);
8986
9100
  const javaStatementTypes = /* @__PURE__ */ new Set([
8987
9101
  "local_variable_declaration",
8988
9102
  "expression_statement",
@@ -9026,8 +9140,30 @@ function isStatement(node, isJavaScript) {
9026
9140
  "export_statement",
9027
9141
  "import_statement"
9028
9142
  ]);
9029
- return isJavaScript ? jsStatementTypes.has(node.type) : javaStatementTypes.has(node.type);
9030
- }
9143
+ return dialect === "js" ? jsStatementTypes.has(node.type) : javaStatementTypes.has(node.type);
9144
+ }
9145
+ var csharpStatementTypes = /* @__PURE__ */ new Set([
9146
+ "local_declaration_statement",
9147
+ "expression_statement",
9148
+ "if_statement",
9149
+ "for_statement",
9150
+ "foreach_statement",
9151
+ "while_statement",
9152
+ "do_statement",
9153
+ "try_statement",
9154
+ "switch_statement",
9155
+ "return_statement",
9156
+ "throw_statement",
9157
+ "break_statement",
9158
+ "continue_statement",
9159
+ "using_statement",
9160
+ "lock_statement",
9161
+ "checked_statement",
9162
+ "unsafe_statement",
9163
+ "yield_statement",
9164
+ "goto_statement",
9165
+ "block"
9166
+ ]);
9031
9167
  function buildGoCFG(tree, blockIdCounter, cache) {
9032
9168
  const allBlocks = [];
9033
9169
  const allEdges = [];
@@ -9038,7 +9174,7 @@ function buildGoCFG(tree, blockIdCounter, cache) {
9038
9174
  for (const func2 of functions) {
9039
9175
  const body2 = func2.childForFieldName("body");
9040
9176
  if (!body2 || body2.type !== "block") continue;
9041
- const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, false);
9177
+ const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, "java");
9042
9178
  allBlocks.push(...blocks);
9043
9179
  allEdges.push(...edges);
9044
9180
  blockIdCounter = nextId;
@@ -13118,6 +13254,11 @@ var DEFAULT_SINKS = [
13118
13254
  // ADO.NET `cmd.CommandText = "…" + x` — emitted as a synthetic call by
13119
13255
  // extractCSharpCalls (property-assignment sink; the ctor-arg sink misses it).
13120
13256
  { method: "CommandText", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
13257
+ // `DirectorySearcher.Filter = "(uid=" + x + ")"` — LDAP injection (cognium-ai#272).
13258
+ // Emitted as a synthetic call by extractCSharpCalls ONLY when the receiver
13259
+ // resolves to a DirectorySearcher, so this classless entry never over-matches
13260
+ // other `.Filter =` assignments (DataView/BindingSource/collection filters).
13261
+ { method: "Filter", type: "ldap_injection", cwe: "CWE-90", severity: "high", arg_positions: [0], languages: ["csharp"] },
13121
13262
  // ADO.NET `cmd.Execute*()` — object-carried sink (cognium-dev#271). The taint
13122
13263
  // rides the SqlCommand receiver (CommandText set from tainted data); the
13123
13264
  // receiver is surfaced as arg[0] by extractCSharpCalls, and the command object
@@ -13134,6 +13275,9 @@ var DEFAULT_SINKS = [
13134
13275
  // injectable — the second is the argv path where taint rides arg[1] (#276).
13135
13276
  { method: "Start", class: "Process", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1], languages: ["csharp"] },
13136
13277
  { method: "ProcessStartInfo", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1], languages: ["csharp"] },
13278
+ // P/Invoke of libc `system(cmd)` — lowercase `system` in C# is virtually
13279
+ // always the imported shell entry point (cognium-ai#275 interop/IlPinvoke).
13280
+ { method: "system", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0], languages: ["csharp"] },
13137
13281
  // C# path traversal — System.IO file APIs (CWE-22). Distinctive method names.
13138
13282
  { method: "ReadAllText", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
13139
13283
  { method: "ReadAllBytes", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
@@ -13162,6 +13306,9 @@ var DEFAULT_SINKS = [
13162
13306
  { method: "Delete", class: "Directory", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
13163
13307
  { method: "GetFiles", class: "Directory", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
13164
13308
  { method: "EnumerateFiles", class: "Directory", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
13309
+ // ASP.NET `ControllerBase.PhysicalFile(path, contentType)` serves a file from
13310
+ // an absolute disk path — attacker-controllable path is CWE-22 (cognium-ai#326/#275).
13311
+ { method: "PhysicalFile", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
13165
13312
  // C# SSRF — HttpClient / WebClient / WebRequest (CWE-918).
13166
13313
  { method: "GetAsync", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["csharp"] },
13167
13314
  { method: "PostAsync", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["csharp"] },
@@ -13186,6 +13333,17 @@ var DEFAULT_SINKS = [
13186
13333
  { method: "Load", class: "Assembly", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["csharp"] },
13187
13334
  { method: "LoadFrom", class: "Assembly", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["csharp"] },
13188
13335
  { method: "LoadFile", class: "Assembly", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["csharp"] },
13336
+ // C# server-side template injection (SSTI). Compiling an attacker-controlled
13337
+ // template string is arbitrary code execution — classified as code_injection
13338
+ // (CWE-94), matching how Python (Jinja2/Mako) and Node SSTI are modelled.
13339
+ // Restricted to DISTINCTIVE template-compile APIs so the generic
13340
+ // `Template.Parse` / `.Compile` names (int.Parse, Regex.Compile, …) are not
13341
+ // over-matched. Taint-gated: a constant template never fires. `RunCompile`
13342
+ // = RazorEngine; `CompileRenderStringAsync` = RazorLight; `Compile` is
13343
+ // class-scoped to Handlebars. (cognium-dev#273)
13344
+ { method: "RunCompile", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["csharp"] },
13345
+ { method: "CompileRenderStringAsync", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0, 1], languages: ["csharp"] },
13346
+ { method: "Compile", class: "Handlebars", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["csharp"] },
13189
13347
  // C# insecure deserialization — the polymorphic BCL formatters that can
13190
13348
  // instantiate arbitrary types named in the payload (CWE-502, cognium-ai#318).
13191
13349
  // Each of these classes exists only to deserialize and is unsafe on untrusted
@@ -13200,6 +13358,14 @@ var DEFAULT_SINKS = [
13200
13358
  { method: "Raw", class: "Html", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0], languages: ["csharp"] },
13201
13359
  { method: "Write", class: "Response", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0], languages: ["csharp"] },
13202
13360
  { method: "HtmlString", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0], languages: ["csharp"] },
13361
+ // Blazor `new MarkupString(x)` renders its argument as raw HTML (the framework's
13362
+ // documented "trusted markup" escape hatch) — attacker-controlled input is XSS. (ca#275)
13363
+ { method: "MarkupString", class: "constructor", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0], languages: ["csharp"] },
13364
+ // `String.Format(fmt, …)` with an attacker-controlled FORMAT string — CWE-134.
13365
+ // Taint-gated on arg 0 (the format), so ordinary `String.Format("...", user)` where
13366
+ // only an argument is tainted never fires. .NET composite formatting can't corrupt
13367
+ // memory, so medium (FormatException DoS / unintended arg access), unlike C printf.
13368
+ { method: "Format", class: "String", type: "format_string", cwe: "CWE-134", severity: "medium", arg_positions: [0], languages: ["csharp"] },
13203
13369
  // C# LDAP injection — System.DirectoryServices (CWE-90). The user-built
13204
13370
  // filter is the constructor argument.
13205
13371
  { method: "DirectorySearcher", type: "ldap_injection", cwe: "CWE-90", severity: "high", arg_positions: [0], languages: ["csharp"] },
@@ -13238,6 +13404,10 @@ var DEFAULT_SINKS = [
13238
13404
  { method: "SelectSingleNode", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
13239
13405
  { method: "SelectNodes", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
13240
13406
  { method: "Compile", class: "XPathExpression", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
13407
+ // XPathNavigator.Select/Evaluate — class-scoped (both names collide with LINQ
13408
+ // `.Select`/`.Evaluate`, so they must resolve to an XPathNavigator receiver).
13409
+ { method: "Select", class: "XPathNavigator", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
13410
+ { method: "Evaluate", class: "XPathNavigator", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
13241
13411
  // C# XXE — untrusted XML into a parser without DTD hardening (CWE-611).
13242
13412
  { method: "LoadXml", type: "xxe", cwe: "CWE-611", severity: "high", arg_positions: [0], languages: ["csharp"] },
13243
13413
  { method: "Load", class: "XmlDocument", type: "xxe", cwe: "CWE-611", severity: "high", arg_positions: [0], languages: ["csharp"] },
@@ -14206,7 +14376,8 @@ function findSources(calls, types, patterns, sourceLines, language) {
14206
14376
  const skipMethods = ["toString", "hashCode", "equals", "compareTo"];
14207
14377
  if (skipMethods.includes(method.name)) continue;
14208
14378
  for (const param of method.parameters) {
14209
- const isTaintable = param.type ? isInterproceduralTaintableType(param.type, language) : true;
14379
+ const hasCSharpBindingAttr = language === "csharp" && param.annotations.some((a) => CSHARP_BINDING_ATTRS.has(a));
14380
+ const isTaintable = hasCSharpBindingAttr ? true : param.type ? isInterproceduralTaintableType(param.type, language) : true;
14210
14381
  if (isTaintable) {
14211
14382
  const paramLine = param.line ?? method.start_line;
14212
14383
  sources.push({
@@ -14326,6 +14497,13 @@ function findSources(calls, types, patterns, sourceLines, language) {
14326
14497
  }
14327
14498
  return result;
14328
14499
  }
14500
+ var CSHARP_BINDING_ATTRS = /* @__PURE__ */ new Set([
14501
+ "FromBody",
14502
+ "FromQuery",
14503
+ "FromRoute",
14504
+ "FromForm",
14505
+ "FromHeader"
14506
+ ]);
14329
14507
  function isInterproceduralTaintableType(typeName, language) {
14330
14508
  const baseType = typeName.split("<")[0].trim();
14331
14509
  const excludedTypes = [
@@ -14564,33 +14742,195 @@ function isSafeJSChildProcessCall(call, pattern, language) {
14564
14742
  if (SHELL_PROGRAMS.has(program)) return false;
14565
14743
  return true;
14566
14744
  }
14567
- function isSafeCSharpProcessStartCall(call, pattern, language) {
14745
+ var CSHARP_SHELL_PROGRAMS = /* @__PURE__ */ new Set([
14746
+ "sh",
14747
+ "bash",
14748
+ "zsh",
14749
+ "dash",
14750
+ "ash",
14751
+ "ksh",
14752
+ "cmd",
14753
+ "powershell",
14754
+ "pwsh"
14755
+ ]);
14756
+ function isConstNonShellExe(raw) {
14757
+ if (!raw) return false;
14758
+ const t = raw.trim();
14759
+ if (!/^@?"[^"]*"$/.test(t)) return false;
14760
+ const program = (t.replace(/^@?"|"$/g, "").split(/[\\/]/).pop() ?? "").toLowerCase().replace(/\.exe$/, "");
14761
+ return !CSHARP_SHELL_PROGRAMS.has(program);
14762
+ }
14763
+ var PSI_CTOR_EXE_RE = /\bnew\s+ProcessStartInfo\s*(?:<[^>]*>)?\s*\(\s*(@?"[^"]*")/;
14764
+ function processStartInfoExe(expr, sourceLines) {
14765
+ const inline = PSI_CTOR_EXE_RE.exec(expr);
14766
+ if (inline) return inline[1];
14767
+ if (sourceLines && /^[A-Za-z_]\w*$/.test(expr.trim())) {
14768
+ const varName = expr.trim();
14769
+ const assignRe = new RegExp(
14770
+ `\\b${varName}\\s*=\\s*new\\s+ProcessStartInfo\\s*(?:<[^>]*>)?\\s*\\(\\s*(@?"[^"]*")`
14771
+ );
14772
+ for (const line of sourceLines) {
14773
+ const m = assignRe.exec(line);
14774
+ if (m) return m[1];
14775
+ }
14776
+ }
14777
+ return null;
14778
+ }
14779
+ function isSafeCSharpProcessStartCall(call, pattern, language, sourceLines) {
14568
14780
  if (language !== "csharp") return false;
14569
14781
  if (pattern.type !== "command_injection") return false;
14570
- if (call.method_name !== "Start") return false;
14571
- if (call.arguments.length < 2) return false;
14572
- const fileArg = call.arguments.find((a) => a.position === 0);
14573
- if (!fileArg) return false;
14574
- let raw;
14575
- if (fileArg.literal !== null && fileArg.literal !== void 0) {
14576
- raw = String(fileArg.literal).trim();
14782
+ const method = call.method_name;
14783
+ if (method !== "Start" && method !== "ProcessStartInfo") return false;
14784
+ if (call.arguments.length >= 2) {
14785
+ const fileArg = call.arguments.find((a) => a.position === 0);
14786
+ const raw = fileArg?.literal != null ? String(fileArg.literal) : fileArg?.expression;
14787
+ return isConstNonShellExe(raw);
14788
+ }
14789
+ if (method === "Start" && call.arguments.length === 1) {
14790
+ const arg0 = call.arguments.find((a) => a.position === 0);
14791
+ const expr = (arg0?.expression ?? "").trim();
14792
+ return isConstNonShellExe(processStartInfoExe(expr, sourceLines));
14793
+ }
14794
+ return false;
14795
+ }
14796
+ function stripCsLiterals(line) {
14797
+ return line.replace(/\/\/.*$/, "").replace(/@?"(?:[^"\\]|\\.)*"/g, '""').replace(/'(?:[^'\\]|\\.)'/g, "''");
14798
+ }
14799
+ function csBraceDepthBefore(lines, idx) {
14800
+ let depth = 0;
14801
+ for (let i2 = 0; i2 < idx && i2 < lines.length; i2++) {
14802
+ for (const ch of stripCsLiterals(lines[i2])) {
14803
+ if (ch === "{") depth++;
14804
+ else if (ch === "}") depth--;
14805
+ }
14806
+ }
14807
+ return depth;
14808
+ }
14809
+ function netBraces(fragment) {
14810
+ let n = 0;
14811
+ for (const ch of fragment) {
14812
+ if (ch === "{") n++;
14813
+ else if (ch === "}") n--;
14814
+ }
14815
+ return n;
14816
+ }
14817
+ function splitCsIf(line) {
14818
+ const m = /\bif\s*\(/.exec(line);
14819
+ if (!m) return null;
14820
+ const ifCol = m.index;
14821
+ let i2 = m.index + m[0].length;
14822
+ let depth = 1;
14823
+ let inStr = false;
14824
+ let strCh = "";
14825
+ for (; i2 < line.length; i2++) {
14826
+ const c = line[i2];
14827
+ if (inStr) {
14828
+ if (c === "\\") {
14829
+ i2++;
14830
+ continue;
14831
+ }
14832
+ if (c === strCh) inStr = false;
14833
+ continue;
14834
+ }
14835
+ if (c === '"' || c === "'") {
14836
+ inStr = true;
14837
+ strCh = c;
14838
+ continue;
14839
+ }
14840
+ if (c === "(") depth++;
14841
+ else if (c === ")") {
14842
+ depth--;
14843
+ if (depth === 0) break;
14844
+ }
14845
+ }
14846
+ if (depth !== 0) return null;
14847
+ return { cond: line.slice(m.index + m[0].length, i2), rest: line.slice(i2 + 1), ifCol };
14848
+ }
14849
+ function csEqualityGuard(cond) {
14850
+ const c = cond.trim();
14851
+ let m = /^(.*?)\s*(==|!=)\s*@?"[^"]*"\s*$/.exec(c);
14852
+ if (m) return { op: m[2], exprSide: m[1].trim() };
14853
+ m = /^@?"[^"]*"\s*(==|!=)\s*(.*)$/.exec(c);
14854
+ if (m) return { op: m[1], exprSide: m[2].trim() };
14855
+ return null;
14856
+ }
14857
+ var CS_IDENT_RE = /[A-Za-z_]\w*/g;
14858
+ function csIdentifiers(expr) {
14859
+ return new Set(expr.match(CS_IDENT_RE) ?? []);
14860
+ }
14861
+ function csThenBlock(lines, ifIdx, rest) {
14862
+ const isExit = (s) => /^\s*(?:return|throw|continue|break)\b/.test(s);
14863
+ let firstIdx;
14864
+ let firstText;
14865
+ if (rest.trim()) {
14866
+ firstIdx = ifIdx;
14867
+ firstText = rest;
14577
14868
  } else {
14578
- raw = (fileArg.expression ?? "").trim();
14869
+ let j = ifIdx + 1;
14870
+ while (j < lines.length && stripCsLiterals(lines[j]).trim() === "") j++;
14871
+ firstIdx = j;
14872
+ firstText = lines[j] ?? "";
14579
14873
  }
14580
- if (!/^@?"[^"]*"$/.test(raw)) return false;
14581
- const program = (raw.replace(/^@?"|"$/g, "").split(/[\\/]/).pop() ?? "").toLowerCase().replace(/\.exe$/, "");
14582
- const SHELL_PROGRAMS = /* @__PURE__ */ new Set([
14583
- "sh",
14584
- "bash",
14585
- "zsh",
14586
- "dash",
14587
- "ash",
14588
- "ksh",
14589
- "cmd",
14590
- "powershell",
14591
- "pwsh"
14592
- ]);
14593
- return !SHELL_PROGRAMS.has(program);
14874
+ if (firstText.trim().startsWith("{")) {
14875
+ let depth = 0;
14876
+ let started = false;
14877
+ let endLine = lines.length - 1;
14878
+ let body2 = "";
14879
+ for (let i2 = firstIdx; i2 < lines.length; i2++) {
14880
+ const stripped = stripCsLiterals(i2 === firstIdx ? firstText : lines[i2]);
14881
+ let broke = false;
14882
+ for (const ch of stripped) {
14883
+ if (ch === "{") {
14884
+ depth++;
14885
+ started = true;
14886
+ if (depth === 1) continue;
14887
+ } else if (ch === "}") {
14888
+ depth--;
14889
+ if (depth === 0) {
14890
+ endLine = i2;
14891
+ broke = true;
14892
+ break;
14893
+ }
14894
+ }
14895
+ if (started && depth >= 1) body2 += ch;
14896
+ }
14897
+ if (broke) break;
14898
+ if (started) body2 += " ";
14899
+ }
14900
+ return { start: ifIdx, end: endLine, earlyExit: isExit(body2.trim()) };
14901
+ }
14902
+ return { start: ifIdx, end: firstIdx, earlyExit: isExit(firstText.trim()) };
14903
+ }
14904
+ function isCSharpSsrfHostAllowlistGuarded(call, pattern, language, sourceLines) {
14905
+ if (language !== "csharp") return false;
14906
+ if (pattern.type !== "ssrf") return false;
14907
+ if (!sourceLines || sourceLines.length === 0) return false;
14908
+ const candidates = /* @__PURE__ */ new Set();
14909
+ for (const a of call.arguments) {
14910
+ if (a.variable) candidates.add(a.variable);
14911
+ for (const id of csIdentifiers(a.expression ?? "")) candidates.add(id);
14912
+ }
14913
+ if (candidates.size === 0) return false;
14914
+ const sinkIdx = call.location.line - 1;
14915
+ const sinkDepth = csBraceDepthBefore(sourceLines, sinkIdx);
14916
+ for (let i2 = 0; i2 < sinkIdx; i2++) {
14917
+ const parts2 = splitCsIf(sourceLines[i2]);
14918
+ if (!parts2) continue;
14919
+ const guard = csEqualityGuard(parts2.cond);
14920
+ if (!guard) continue;
14921
+ const guardIds = csIdentifiers(guard.exprSide);
14922
+ if (![...guardIds].some((id) => candidates.has(id))) continue;
14923
+ const block = csThenBlock(sourceLines, i2, parts2.rest);
14924
+ if (guard.op === "==") {
14925
+ if (sinkIdx >= block.start && sinkIdx <= block.end) return true;
14926
+ } else {
14927
+ const guardDepth = csBraceDepthBefore(sourceLines, i2) + netBraces(stripCsLiterals(sourceLines[i2]).slice(0, parts2.ifCol));
14928
+ if (block.earlyExit && sinkIdx > block.end && guardDepth === sinkDepth) {
14929
+ return true;
14930
+ }
14931
+ }
14932
+ }
14933
+ return false;
14594
14934
  }
14595
14935
  function isSafeRustCommandCall(call, pattern, language) {
14596
14936
  if (language !== "rust") return false;
@@ -14847,7 +15187,10 @@ function findSinks(calls, patterns, typeHierarchy, language, sourceLines, types)
14847
15187
  if (isSafeJSChildProcessCall(call, pattern, language)) {
14848
15188
  continue;
14849
15189
  }
14850
- if (isSafeCSharpProcessStartCall(call, pattern, language)) {
15190
+ if (isSafeCSharpProcessStartCall(call, pattern, language, sourceLines)) {
15191
+ continue;
15192
+ }
15193
+ if (isCSharpSsrfHostAllowlistGuarded(call, pattern, language, sourceLines)) {
14851
15194
  continue;
14852
15195
  }
14853
15196
  if (pattern.safe_if_class_literal_at !== void 0 && argIsClassLiteral(call, pattern.safe_if_class_literal_at, types)) {