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
@@ -4421,6 +4421,7 @@ function extractCSharpTypes(tree, cache) {
4421
4421
  const nameNode = node.childForFieldName("name");
4422
4422
  const body2 = node.childForFieldName("body");
4423
4423
  const methods = [];
4424
+ const fields = extractCSharpFields(body2);
4424
4425
  if (body2) {
4425
4426
  for (let i2 = 0; i2 < body2.childCount; i2++) {
4426
4427
  const m = body2.child(i2);
@@ -4438,7 +4439,7 @@ function extractCSharpTypes(tree, cache) {
4438
4439
  parameters.push({
4439
4440
  name: getNodeText(pName),
4440
4441
  type: pType ? getNodeText(pType) : null,
4441
- annotations: [],
4442
+ annotations: extractCSharpParamAnnotations(pnode),
4442
4443
  line: pnode.startPosition.row + 1
4443
4444
  });
4444
4445
  }
@@ -4464,7 +4465,7 @@ function extractCSharpTypes(tree, cache) {
4464
4465
  implements: [],
4465
4466
  annotations: [],
4466
4467
  methods,
4467
- fields: [],
4468
+ fields,
4468
4469
  start_line: node.startPosition.row + 1,
4469
4470
  end_line: node.endPosition.row + 1
4470
4471
  });
@@ -4472,6 +4473,59 @@ function extractCSharpTypes(tree, cache) {
4472
4473
  }
4473
4474
  return types;
4474
4475
  }
4476
+ function extractCSharpFields(body2) {
4477
+ const fields = [];
4478
+ if (!body2) return fields;
4479
+ for (let i2 = 0; i2 < body2.childCount; i2++) {
4480
+ const c = body2.child(i2);
4481
+ if (!c) continue;
4482
+ if (c.type === "field_declaration") {
4483
+ let varDecl = null;
4484
+ for (let k = 0; k < c.childCount; k++) {
4485
+ const cc = c.child(k);
4486
+ if (cc?.type === "variable_declaration") {
4487
+ varDecl = cc;
4488
+ break;
4489
+ }
4490
+ }
4491
+ if (!varDecl) continue;
4492
+ const typeNode = varDecl.childForFieldName("type");
4493
+ const type = typeNode ? getNodeText(typeNode) : null;
4494
+ const modifiers = extractCSharpModifiers(c);
4495
+ for (let k = 0; k < varDecl.childCount; k++) {
4496
+ const decl = varDecl.child(k);
4497
+ if (decl?.type !== "variable_declarator") continue;
4498
+ const nameNode = decl.childForFieldName("name");
4499
+ fields.push({ name: nameNode ? getNodeText(nameNode) : "unknown", type, modifiers, annotations: [] });
4500
+ }
4501
+ } else if (c.type === "property_declaration") {
4502
+ const nameNode = c.childForFieldName("name");
4503
+ if (!nameNode) continue;
4504
+ const typeNode = c.childForFieldName("type");
4505
+ fields.push({
4506
+ name: getNodeText(nameNode),
4507
+ type: typeNode ? getNodeText(typeNode) : null,
4508
+ modifiers: extractCSharpModifiers(c),
4509
+ annotations: []
4510
+ });
4511
+ }
4512
+ }
4513
+ return fields;
4514
+ }
4515
+ function extractCSharpParamAnnotations(param) {
4516
+ const out2 = [];
4517
+ for (let i2 = 0; i2 < param.childCount; i2++) {
4518
+ const list = param.child(i2);
4519
+ if (list?.type !== "attribute_list") continue;
4520
+ for (let j = 0; j < list.childCount; j++) {
4521
+ const attr = list.child(j);
4522
+ if (attr?.type !== "attribute") continue;
4523
+ const name2 = attr.childForFieldName("name");
4524
+ if (name2) out2.push(getNodeText(name2));
4525
+ }
4526
+ }
4527
+ return out2;
4528
+ }
4475
4529
  function extractCSharpModifiers(node) {
4476
4530
  const mods = [];
4477
4531
  for (let i2 = 0; i2 < node.childCount; i2++) {
@@ -6046,13 +6100,21 @@ function extractCSharpCalls(tree, cache) {
6046
6100
  const left = asn.childForFieldName("left");
6047
6101
  if (left?.type !== "member_access_expression") continue;
6048
6102
  const nameNode = left.childForFieldName("name");
6049
- if (!nameNode || getNodeText(nameNode) !== "CommandText") continue;
6103
+ if (!nameNode) continue;
6104
+ const propName = getNodeText(nameNode);
6105
+ const exprNode = left.childForFieldName("expression");
6106
+ if (propName === "Filter") {
6107
+ const recv = exprNode ? getNodeText(exprNode) : null;
6108
+ const recvType = recv ? typeMap.get(recv) : void 0;
6109
+ if (recvType !== "DirectorySearcher") continue;
6110
+ } else if (propName !== "CommandText") {
6111
+ continue;
6112
+ }
6050
6113
  const right = asn.childForFieldName("right");
6051
6114
  if (!right) continue;
6052
6115
  const rhsText = getNodeText(right);
6053
- const exprNode = left.childForFieldName("expression");
6054
6116
  calls.push({
6055
- method_name: "CommandText",
6117
+ method_name: propName,
6056
6118
  receiver: exprNode ? getNodeText(exprNode) : null,
6057
6119
  receiver_type: null,
6058
6120
  receiver_type_fqn: null,
@@ -8618,6 +8680,9 @@ function buildCFG(tree, language, cache) {
8618
8680
  if (effectiveLanguage === "go") {
8619
8681
  return buildGoCFG(tree, blockIdCounter, cache);
8620
8682
  }
8683
+ if (effectiveLanguage === "csharp") {
8684
+ return buildCSharpCFG(tree, blockIdCounter, cache);
8685
+ }
8621
8686
  if (isJavaScript) {
8622
8687
  const functions = [
8623
8688
  ...getNodesFromCache(tree.rootNode, "function_declaration", cache),
@@ -8630,7 +8695,7 @@ function buildCFG(tree, language, cache) {
8630
8695
  const body2 = func2.childForFieldName("body");
8631
8696
  if (!body2) continue;
8632
8697
  if (body2.type === "statement_block") {
8633
- const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, true);
8698
+ const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, "js");
8634
8699
  allBlocks.push(...blocks);
8635
8700
  allEdges.push(...edges);
8636
8701
  blockIdCounter = nextId;
@@ -8652,7 +8717,7 @@ function buildCFG(tree, language, cache) {
8652
8717
  for (const method of methods) {
8653
8718
  const body2 = method.childForFieldName("body");
8654
8719
  if (!body2) continue;
8655
- const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, false);
8720
+ const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, "java");
8656
8721
  allBlocks.push(...blocks);
8657
8722
  allEdges.push(...edges);
8658
8723
  blockIdCounter = nextId;
@@ -8660,7 +8725,28 @@ function buildCFG(tree, language, cache) {
8660
8725
  }
8661
8726
  return { blocks: allBlocks, edges: allEdges };
8662
8727
  }
8663
- function buildMethodCFG(body2, startId, isJavaScript) {
8728
+ function buildCSharpCFG(tree, blockIdCounter, cache) {
8729
+ const allBlocks = [];
8730
+ const allEdges = [];
8731
+ const containers = [
8732
+ ...getNodesFromCache(tree.rootNode, "method_declaration", cache),
8733
+ ...getNodesFromCache(tree.rootNode, "constructor_declaration", cache),
8734
+ ...getNodesFromCache(tree.rootNode, "destructor_declaration", cache),
8735
+ ...getNodesFromCache(tree.rootNode, "operator_declaration", cache),
8736
+ ...getNodesFromCache(tree.rootNode, "local_function_statement", cache),
8737
+ ...getNodesFromCache(tree.rootNode, "accessor_declaration", cache)
8738
+ ];
8739
+ for (const container of containers) {
8740
+ const body2 = container.childForFieldName("body");
8741
+ if (!body2 || body2.type !== "block") continue;
8742
+ const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, "csharp");
8743
+ allBlocks.push(...blocks);
8744
+ allEdges.push(...edges);
8745
+ blockIdCounter = nextId;
8746
+ }
8747
+ return { blocks: allBlocks, edges: allEdges };
8748
+ }
8749
+ function buildMethodCFG(body2, startId, dialect) {
8664
8750
  const blocks = [];
8665
8751
  const edges = [];
8666
8752
  let currentId = startId;
@@ -8671,7 +8757,7 @@ function buildMethodCFG(body2, startId, isJavaScript) {
8671
8757
  end_line: body2.startPosition.row + 1
8672
8758
  };
8673
8759
  blocks.push(entryBlock);
8674
- const result = processStatements(body2, currentId, blocks, edges, isJavaScript);
8760
+ const result = processStatements(body2, currentId, blocks, edges, dialect);
8675
8761
  currentId = result.nextId;
8676
8762
  if (result.entryId !== -1) {
8677
8763
  edges.push({
@@ -8703,15 +8789,15 @@ function buildMethodCFG(body2, startId, isJavaScript) {
8703
8789
  }
8704
8790
  return { blocks, edges, nextId: currentId };
8705
8791
  }
8706
- function processStatements(container, startId, blocks, edges, isJavaScript) {
8792
+ function processStatements(container, startId, blocks, edges, dialect) {
8707
8793
  let currentId = startId;
8708
8794
  let firstBlockId = -1;
8709
8795
  let lastExitIds = [];
8710
8796
  for (let i2 = 0; i2 < container.childCount; i2++) {
8711
8797
  const stmt = container.child(i2);
8712
8798
  if (!stmt) continue;
8713
- if (!isStatement(stmt, isJavaScript)) continue;
8714
- const result = processStatement(stmt, currentId, blocks, edges, isJavaScript);
8799
+ if (!isStatement(stmt, dialect)) continue;
8800
+ const result = processStatement(stmt, currentId, blocks, edges, dialect);
8715
8801
  currentId = result.nextId;
8716
8802
  if (firstBlockId === -1) {
8717
8803
  firstBlockId = result.entryId;
@@ -8732,31 +8818,49 @@ function processStatements(container, startId, blocks, edges, isJavaScript) {
8732
8818
  nextId: currentId
8733
8819
  };
8734
8820
  }
8735
- function processStatement(stmt, startId, blocks, edges, isJavaScript) {
8821
+ function processStatement(stmt, startId, blocks, edges, dialect) {
8736
8822
  switch (stmt.type) {
8737
8823
  case "if_statement":
8738
- return processIfStatement(stmt, startId, blocks, edges, isJavaScript);
8824
+ return processIfStatement(stmt, startId, blocks, edges, dialect);
8739
8825
  case "for_statement":
8740
8826
  case "enhanced_for_statement":
8741
8827
  case "for_in_statement":
8742
8828
  case "for_of_statement":
8743
- return processForStatement(stmt, startId, blocks, edges, isJavaScript);
8829
+ case "foreach_statement":
8830
+ return processForStatement(stmt, startId, blocks, edges, dialect);
8744
8831
  case "while_statement":
8745
- return processWhileStatement(stmt, startId, blocks, edges, isJavaScript);
8832
+ return processWhileStatement(stmt, startId, blocks, edges, dialect);
8746
8833
  case "do_statement":
8747
- return processDoWhileStatement(stmt, startId, blocks, edges, isJavaScript);
8834
+ return processDoWhileStatement(stmt, startId, blocks, edges, dialect);
8748
8835
  case "try_statement":
8749
- return processTryStatement(stmt, startId, blocks, edges, isJavaScript);
8836
+ return processTryStatement(stmt, startId, blocks, edges, dialect);
8750
8837
  case "switch_expression":
8751
8838
  case "switch_statement":
8752
- return processSwitchStatement(stmt, startId, blocks, edges, isJavaScript);
8839
+ return processSwitchStatement(stmt, startId, blocks, edges, dialect);
8840
+ // C# scoped blocks add no branching — flow through the inner block so its
8841
+ // nested statements are still captured.
8842
+ case "using_statement":
8843
+ case "lock_statement":
8844
+ case "checked_statement":
8845
+ case "unsafe_statement": {
8846
+ const inner = stmt.childForFieldName("body") ?? lastBlockChild(stmt);
8847
+ if (inner) return processStatement(inner, startId, blocks, edges, dialect);
8848
+ return processSimpleStatement(stmt, startId, blocks);
8849
+ }
8753
8850
  case "block":
8754
8851
  case "statement_block":
8755
- return processStatements(stmt, startId, blocks, edges, isJavaScript);
8852
+ return processStatements(stmt, startId, blocks, edges, dialect);
8756
8853
  default:
8757
8854
  return processSimpleStatement(stmt, startId, blocks);
8758
8855
  }
8759
8856
  }
8857
+ function lastBlockChild(node) {
8858
+ for (let i2 = node.childCount - 1; i2 >= 0; i2--) {
8859
+ const c = node.child(i2);
8860
+ if (c && c.type === "block") return c;
8861
+ }
8862
+ return null;
8863
+ }
8760
8864
  function processSimpleStatement(stmt, startId, blocks) {
8761
8865
  const block = {
8762
8866
  id: startId,
@@ -8771,7 +8875,7 @@ function processSimpleStatement(stmt, startId, blocks) {
8771
8875
  nextId: startId + 1
8772
8876
  };
8773
8877
  }
8774
- function processIfStatement(stmt, startId, blocks, edges, isJavaScript) {
8878
+ function processIfStatement(stmt, startId, blocks, edges, dialect) {
8775
8879
  let currentId = startId;
8776
8880
  const condBlock = {
8777
8881
  id: currentId++,
@@ -8783,7 +8887,7 @@ function processIfStatement(stmt, startId, blocks, edges, isJavaScript) {
8783
8887
  const exitIds = [];
8784
8888
  const consequence = stmt.childForFieldName("consequence");
8785
8889
  if (consequence) {
8786
- const thenResult = processStatement(consequence, currentId, blocks, edges, isJavaScript);
8890
+ const thenResult = processStatement(consequence, currentId, blocks, edges, dialect);
8787
8891
  currentId = thenResult.nextId;
8788
8892
  edges.push({
8789
8893
  from: condBlock.id,
@@ -8794,7 +8898,7 @@ function processIfStatement(stmt, startId, blocks, edges, isJavaScript) {
8794
8898
  }
8795
8899
  const alternative = stmt.childForFieldName("alternative");
8796
8900
  if (alternative) {
8797
- const elseResult = processStatement(alternative, currentId, blocks, edges, isJavaScript);
8901
+ const elseResult = processStatement(alternative, currentId, blocks, edges, dialect);
8798
8902
  currentId = elseResult.nextId;
8799
8903
  edges.push({
8800
8904
  from: condBlock.id,
@@ -8811,7 +8915,7 @@ function processIfStatement(stmt, startId, blocks, edges, isJavaScript) {
8811
8915
  nextId: currentId
8812
8916
  };
8813
8917
  }
8814
- function processForStatement(stmt, startId, blocks, edges, isJavaScript) {
8918
+ function processForStatement(stmt, startId, blocks, edges, dialect) {
8815
8919
  let currentId = startId;
8816
8920
  const loopBlock = {
8817
8921
  id: currentId++,
@@ -8822,7 +8926,7 @@ function processForStatement(stmt, startId, blocks, edges, isJavaScript) {
8822
8926
  blocks.push(loopBlock);
8823
8927
  const body2 = stmt.childForFieldName("body");
8824
8928
  if (body2) {
8825
- const bodyResult = processStatement(body2, currentId, blocks, edges, isJavaScript);
8929
+ const bodyResult = processStatement(body2, currentId, blocks, edges, dialect);
8826
8930
  currentId = bodyResult.nextId;
8827
8931
  edges.push({
8828
8932
  from: loopBlock.id,
@@ -8844,16 +8948,16 @@ function processForStatement(stmt, startId, blocks, edges, isJavaScript) {
8844
8948
  nextId: currentId
8845
8949
  };
8846
8950
  }
8847
- function processWhileStatement(stmt, startId, blocks, edges, isJavaScript) {
8848
- return processForStatement(stmt, startId, blocks, edges, isJavaScript);
8951
+ function processWhileStatement(stmt, startId, blocks, edges, dialect) {
8952
+ return processForStatement(stmt, startId, blocks, edges, dialect);
8849
8953
  }
8850
- function processDoWhileStatement(stmt, startId, blocks, edges, isJavaScript) {
8954
+ function processDoWhileStatement(stmt, startId, blocks, edges, dialect) {
8851
8955
  let currentId = startId;
8852
8956
  const body2 = stmt.childForFieldName("body");
8853
8957
  let bodyEntryId = currentId;
8854
8958
  let bodyExitIds = [];
8855
8959
  if (body2) {
8856
- const bodyResult = processStatement(body2, currentId, blocks, edges, isJavaScript);
8960
+ const bodyResult = processStatement(body2, currentId, blocks, edges, dialect);
8857
8961
  currentId = bodyResult.nextId;
8858
8962
  bodyEntryId = bodyResult.entryId;
8859
8963
  bodyExitIds = bodyResult.exitIds;
@@ -8883,13 +8987,13 @@ function processDoWhileStatement(stmt, startId, blocks, edges, isJavaScript) {
8883
8987
  nextId: currentId
8884
8988
  };
8885
8989
  }
8886
- function processTryStatement(stmt, startId, blocks, edges, isJavaScript) {
8990
+ function processTryStatement(stmt, startId, blocks, edges, dialect) {
8887
8991
  let currentId = startId;
8888
8992
  const exitIds = [];
8889
8993
  const body2 = stmt.childForFieldName("body");
8890
8994
  let tryEntryId = -1;
8891
8995
  if (body2) {
8892
- const bodyResult = processStatements(body2, currentId, blocks, edges, isJavaScript);
8996
+ const bodyResult = processStatements(body2, currentId, blocks, edges, dialect);
8893
8997
  currentId = bodyResult.nextId;
8894
8998
  tryEntryId = bodyResult.entryId;
8895
8999
  exitIds.push(...bodyResult.exitIds);
@@ -8899,7 +9003,7 @@ function processTryStatement(stmt, startId, blocks, edges, isJavaScript) {
8899
9003
  if (child?.type === "catch_clause") {
8900
9004
  const catchBody = child.childForFieldName("body");
8901
9005
  if (catchBody) {
8902
- const catchResult = processStatements(catchBody, currentId, blocks, edges, isJavaScript);
9006
+ const catchResult = processStatements(catchBody, currentId, blocks, edges, dialect);
8903
9007
  currentId = catchResult.nextId;
8904
9008
  if (tryEntryId !== -1) {
8905
9009
  edges.push({
@@ -8912,9 +9016,18 @@ function processTryStatement(stmt, startId, blocks, edges, isJavaScript) {
8912
9016
  }
8913
9017
  }
8914
9018
  }
8915
- const finallyClause = stmt.childForFieldName("finally") ?? stmt.childForFieldName("finalizer");
9019
+ let finallyClause = stmt.childForFieldName("finally") ?? stmt.childForFieldName("finalizer");
9020
+ if (!finallyClause && dialect === "csharp") {
9021
+ for (let i2 = 0; i2 < stmt.childCount; i2++) {
9022
+ const child = stmt.child(i2);
9023
+ if (child?.type === "finally_clause") {
9024
+ finallyClause = lastBlockChild(child);
9025
+ break;
9026
+ }
9027
+ }
9028
+ }
8916
9029
  if (finallyClause) {
8917
- const finallyResult = processStatements(finallyClause, currentId, blocks, edges, isJavaScript);
9030
+ const finallyResult = processStatements(finallyClause, currentId, blocks, edges, dialect);
8918
9031
  currentId = finallyResult.nextId;
8919
9032
  for (const exitId of exitIds) {
8920
9033
  edges.push({
@@ -8935,7 +9048,7 @@ function processTryStatement(stmt, startId, blocks, edges, isJavaScript) {
8935
9048
  nextId: currentId
8936
9049
  };
8937
9050
  }
8938
- function processSwitchStatement(stmt, startId, blocks, edges, isJavaScript) {
9051
+ function processSwitchStatement(stmt, startId, blocks, edges, dialect) {
8939
9052
  let currentId = startId;
8940
9053
  const switchBlock = {
8941
9054
  id: currentId++,
@@ -8947,11 +9060,11 @@ function processSwitchStatement(stmt, startId, blocks, edges, isJavaScript) {
8947
9060
  const exitIds = [];
8948
9061
  const body2 = stmt.childForFieldName("body");
8949
9062
  if (body2) {
8950
- const caseTypes = isJavaScript ? ["switch_case", "switch_default"] : ["switch_block_statement_group", "switch_rule"];
9063
+ const caseTypes = dialect === "js" ? ["switch_case", "switch_default"] : dialect === "csharp" ? ["switch_section"] : ["switch_block_statement_group", "switch_rule"];
8951
9064
  for (let i2 = 0; i2 < body2.childCount; i2++) {
8952
9065
  const child = body2.child(i2);
8953
9066
  if (child && caseTypes.includes(child.type)) {
8954
- const caseResult = processStatements(child, currentId, blocks, edges, isJavaScript);
9067
+ const caseResult = processStatements(child, currentId, blocks, edges, dialect);
8955
9068
  currentId = caseResult.nextId;
8956
9069
  if (caseResult.entryId !== -1) {
8957
9070
  edges.push({
@@ -8981,7 +9094,7 @@ function buildBashCFG(tree, startId, cache) {
8981
9094
  for (const func2 of functions) {
8982
9095
  const body2 = func2.childForFieldName("body");
8983
9096
  if (!body2) continue;
8984
- const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, false);
9097
+ const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, "java");
8985
9098
  allBlocks.push(...blocks);
8986
9099
  allEdges.push(...edges);
8987
9100
  blockIdCounter = nextId;
@@ -9004,7 +9117,7 @@ function buildBashCFG(tree, startId, cache) {
9004
9117
  let lastExitIds = [];
9005
9118
  let firstBlockId = -1;
9006
9119
  for (const stmt of topLevelStatements) {
9007
- const result = processStatement(stmt, blockIdCounter, allBlocks, allEdges, false);
9120
+ const result = processStatement(stmt, blockIdCounter, allBlocks, allEdges, "java");
9008
9121
  blockIdCounter = result.nextId;
9009
9122
  if (firstBlockId === -1) {
9010
9123
  firstBlockId = result.entryId;
@@ -9048,7 +9161,8 @@ function isBashStatement(node) {
9048
9161
  ]);
9049
9162
  return bashStatementTypes.has(node.type);
9050
9163
  }
9051
- function isStatement(node, isJavaScript) {
9164
+ function isStatement(node, dialect) {
9165
+ if (dialect === "csharp") return csharpStatementTypes.has(node.type);
9052
9166
  const javaStatementTypes = /* @__PURE__ */ new Set([
9053
9167
  "local_variable_declaration",
9054
9168
  "expression_statement",
@@ -9092,8 +9206,30 @@ function isStatement(node, isJavaScript) {
9092
9206
  "export_statement",
9093
9207
  "import_statement"
9094
9208
  ]);
9095
- return isJavaScript ? jsStatementTypes.has(node.type) : javaStatementTypes.has(node.type);
9096
- }
9209
+ return dialect === "js" ? jsStatementTypes.has(node.type) : javaStatementTypes.has(node.type);
9210
+ }
9211
+ var csharpStatementTypes = /* @__PURE__ */ new Set([
9212
+ "local_declaration_statement",
9213
+ "expression_statement",
9214
+ "if_statement",
9215
+ "for_statement",
9216
+ "foreach_statement",
9217
+ "while_statement",
9218
+ "do_statement",
9219
+ "try_statement",
9220
+ "switch_statement",
9221
+ "return_statement",
9222
+ "throw_statement",
9223
+ "break_statement",
9224
+ "continue_statement",
9225
+ "using_statement",
9226
+ "lock_statement",
9227
+ "checked_statement",
9228
+ "unsafe_statement",
9229
+ "yield_statement",
9230
+ "goto_statement",
9231
+ "block"
9232
+ ]);
9097
9233
  function buildGoCFG(tree, blockIdCounter, cache) {
9098
9234
  const allBlocks = [];
9099
9235
  const allEdges = [];
@@ -9104,7 +9240,7 @@ function buildGoCFG(tree, blockIdCounter, cache) {
9104
9240
  for (const func2 of functions) {
9105
9241
  const body2 = func2.childForFieldName("body");
9106
9242
  if (!body2 || body2.type !== "block") continue;
9107
- const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, false);
9243
+ const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, "java");
9108
9244
  allBlocks.push(...blocks);
9109
9245
  allEdges.push(...edges);
9110
9246
  blockIdCounter = nextId;
@@ -13184,6 +13320,11 @@ var DEFAULT_SINKS = [
13184
13320
  // ADO.NET `cmd.CommandText = "…" + x` — emitted as a synthetic call by
13185
13321
  // extractCSharpCalls (property-assignment sink; the ctor-arg sink misses it).
13186
13322
  { method: "CommandText", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
13323
+ // `DirectorySearcher.Filter = "(uid=" + x + ")"` — LDAP injection (cognium-ai#272).
13324
+ // Emitted as a synthetic call by extractCSharpCalls ONLY when the receiver
13325
+ // resolves to a DirectorySearcher, so this classless entry never over-matches
13326
+ // other `.Filter =` assignments (DataView/BindingSource/collection filters).
13327
+ { method: "Filter", type: "ldap_injection", cwe: "CWE-90", severity: "high", arg_positions: [0], languages: ["csharp"] },
13187
13328
  // ADO.NET `cmd.Execute*()` — object-carried sink (cognium-dev#271). The taint
13188
13329
  // rides the SqlCommand receiver (CommandText set from tainted data); the
13189
13330
  // receiver is surfaced as arg[0] by extractCSharpCalls, and the command object
@@ -13200,6 +13341,9 @@ var DEFAULT_SINKS = [
13200
13341
  // injectable — the second is the argv path where taint rides arg[1] (#276).
13201
13342
  { method: "Start", class: "Process", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1], languages: ["csharp"] },
13202
13343
  { method: "ProcessStartInfo", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1], languages: ["csharp"] },
13344
+ // P/Invoke of libc `system(cmd)` — lowercase `system` in C# is virtually
13345
+ // always the imported shell entry point (cognium-ai#275 interop/IlPinvoke).
13346
+ { method: "system", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0], languages: ["csharp"] },
13203
13347
  // C# path traversal — System.IO file APIs (CWE-22). Distinctive method names.
13204
13348
  { method: "ReadAllText", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
13205
13349
  { method: "ReadAllBytes", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
@@ -13228,6 +13372,9 @@ var DEFAULT_SINKS = [
13228
13372
  { method: "Delete", class: "Directory", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
13229
13373
  { method: "GetFiles", class: "Directory", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
13230
13374
  { method: "EnumerateFiles", class: "Directory", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
13375
+ // ASP.NET `ControllerBase.PhysicalFile(path, contentType)` serves a file from
13376
+ // an absolute disk path — attacker-controllable path is CWE-22 (cognium-ai#326/#275).
13377
+ { method: "PhysicalFile", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
13231
13378
  // C# SSRF — HttpClient / WebClient / WebRequest (CWE-918).
13232
13379
  { method: "GetAsync", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["csharp"] },
13233
13380
  { method: "PostAsync", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["csharp"] },
@@ -13252,6 +13399,17 @@ var DEFAULT_SINKS = [
13252
13399
  { method: "Load", class: "Assembly", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["csharp"] },
13253
13400
  { method: "LoadFrom", class: "Assembly", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["csharp"] },
13254
13401
  { method: "LoadFile", class: "Assembly", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["csharp"] },
13402
+ // C# server-side template injection (SSTI). Compiling an attacker-controlled
13403
+ // template string is arbitrary code execution — classified as code_injection
13404
+ // (CWE-94), matching how Python (Jinja2/Mako) and Node SSTI are modelled.
13405
+ // Restricted to DISTINCTIVE template-compile APIs so the generic
13406
+ // `Template.Parse` / `.Compile` names (int.Parse, Regex.Compile, …) are not
13407
+ // over-matched. Taint-gated: a constant template never fires. `RunCompile`
13408
+ // = RazorEngine; `CompileRenderStringAsync` = RazorLight; `Compile` is
13409
+ // class-scoped to Handlebars. (cognium-dev#273)
13410
+ { method: "RunCompile", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["csharp"] },
13411
+ { method: "CompileRenderStringAsync", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0, 1], languages: ["csharp"] },
13412
+ { method: "Compile", class: "Handlebars", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["csharp"] },
13255
13413
  // C# insecure deserialization — the polymorphic BCL formatters that can
13256
13414
  // instantiate arbitrary types named in the payload (CWE-502, cognium-ai#318).
13257
13415
  // Each of these classes exists only to deserialize and is unsafe on untrusted
@@ -13266,6 +13424,14 @@ var DEFAULT_SINKS = [
13266
13424
  { method: "Raw", class: "Html", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0], languages: ["csharp"] },
13267
13425
  { method: "Write", class: "Response", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0], languages: ["csharp"] },
13268
13426
  { method: "HtmlString", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0], languages: ["csharp"] },
13427
+ // Blazor `new MarkupString(x)` renders its argument as raw HTML (the framework's
13428
+ // documented "trusted markup" escape hatch) — attacker-controlled input is XSS. (ca#275)
13429
+ { method: "MarkupString", class: "constructor", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0], languages: ["csharp"] },
13430
+ // `String.Format(fmt, …)` with an attacker-controlled FORMAT string — CWE-134.
13431
+ // Taint-gated on arg 0 (the format), so ordinary `String.Format("...", user)` where
13432
+ // only an argument is tainted never fires. .NET composite formatting can't corrupt
13433
+ // memory, so medium (FormatException DoS / unintended arg access), unlike C printf.
13434
+ { method: "Format", class: "String", type: "format_string", cwe: "CWE-134", severity: "medium", arg_positions: [0], languages: ["csharp"] },
13269
13435
  // C# LDAP injection — System.DirectoryServices (CWE-90). The user-built
13270
13436
  // filter is the constructor argument.
13271
13437
  { method: "DirectorySearcher", type: "ldap_injection", cwe: "CWE-90", severity: "high", arg_positions: [0], languages: ["csharp"] },
@@ -13304,6 +13470,10 @@ var DEFAULT_SINKS = [
13304
13470
  { method: "SelectSingleNode", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
13305
13471
  { method: "SelectNodes", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
13306
13472
  { method: "Compile", class: "XPathExpression", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
13473
+ // XPathNavigator.Select/Evaluate — class-scoped (both names collide with LINQ
13474
+ // `.Select`/`.Evaluate`, so they must resolve to an XPathNavigator receiver).
13475
+ { method: "Select", class: "XPathNavigator", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
13476
+ { method: "Evaluate", class: "XPathNavigator", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
13307
13477
  // C# XXE — untrusted XML into a parser without DTD hardening (CWE-611).
13308
13478
  { method: "LoadXml", type: "xxe", cwe: "CWE-611", severity: "high", arg_positions: [0], languages: ["csharp"] },
13309
13479
  { method: "Load", class: "XmlDocument", type: "xxe", cwe: "CWE-611", severity: "high", arg_positions: [0], languages: ["csharp"] },
@@ -14272,7 +14442,8 @@ function findSources(calls, types, patterns, sourceLines, language) {
14272
14442
  const skipMethods = ["toString", "hashCode", "equals", "compareTo"];
14273
14443
  if (skipMethods.includes(method.name)) continue;
14274
14444
  for (const param of method.parameters) {
14275
- const isTaintable = param.type ? isInterproceduralTaintableType(param.type, language) : true;
14445
+ const hasCSharpBindingAttr = language === "csharp" && param.annotations.some((a) => CSHARP_BINDING_ATTRS.has(a));
14446
+ const isTaintable = hasCSharpBindingAttr ? true : param.type ? isInterproceduralTaintableType(param.type, language) : true;
14276
14447
  if (isTaintable) {
14277
14448
  const paramLine = param.line ?? method.start_line;
14278
14449
  sources.push({
@@ -14392,6 +14563,13 @@ function findSources(calls, types, patterns, sourceLines, language) {
14392
14563
  }
14393
14564
  return result;
14394
14565
  }
14566
+ var CSHARP_BINDING_ATTRS = /* @__PURE__ */ new Set([
14567
+ "FromBody",
14568
+ "FromQuery",
14569
+ "FromRoute",
14570
+ "FromForm",
14571
+ "FromHeader"
14572
+ ]);
14395
14573
  function isInterproceduralTaintableType(typeName, language) {
14396
14574
  const baseType = typeName.split("<")[0].trim();
14397
14575
  const excludedTypes = [
@@ -14630,33 +14808,195 @@ function isSafeJSChildProcessCall(call, pattern, language) {
14630
14808
  if (SHELL_PROGRAMS.has(program)) return false;
14631
14809
  return true;
14632
14810
  }
14633
- function isSafeCSharpProcessStartCall(call, pattern, language) {
14811
+ var CSHARP_SHELL_PROGRAMS = /* @__PURE__ */ new Set([
14812
+ "sh",
14813
+ "bash",
14814
+ "zsh",
14815
+ "dash",
14816
+ "ash",
14817
+ "ksh",
14818
+ "cmd",
14819
+ "powershell",
14820
+ "pwsh"
14821
+ ]);
14822
+ function isConstNonShellExe(raw) {
14823
+ if (!raw) return false;
14824
+ const t = raw.trim();
14825
+ if (!/^@?"[^"]*"$/.test(t)) return false;
14826
+ const program = (t.replace(/^@?"|"$/g, "").split(/[\\/]/).pop() ?? "").toLowerCase().replace(/\.exe$/, "");
14827
+ return !CSHARP_SHELL_PROGRAMS.has(program);
14828
+ }
14829
+ var PSI_CTOR_EXE_RE = /\bnew\s+ProcessStartInfo\s*(?:<[^>]*>)?\s*\(\s*(@?"[^"]*")/;
14830
+ function processStartInfoExe(expr, sourceLines) {
14831
+ const inline = PSI_CTOR_EXE_RE.exec(expr);
14832
+ if (inline) return inline[1];
14833
+ if (sourceLines && /^[A-Za-z_]\w*$/.test(expr.trim())) {
14834
+ const varName = expr.trim();
14835
+ const assignRe = new RegExp(
14836
+ `\\b${varName}\\s*=\\s*new\\s+ProcessStartInfo\\s*(?:<[^>]*>)?\\s*\\(\\s*(@?"[^"]*")`
14837
+ );
14838
+ for (const line of sourceLines) {
14839
+ const m = assignRe.exec(line);
14840
+ if (m) return m[1];
14841
+ }
14842
+ }
14843
+ return null;
14844
+ }
14845
+ function isSafeCSharpProcessStartCall(call, pattern, language, sourceLines) {
14634
14846
  if (language !== "csharp") return false;
14635
14847
  if (pattern.type !== "command_injection") return false;
14636
- if (call.method_name !== "Start") return false;
14637
- if (call.arguments.length < 2) return false;
14638
- const fileArg = call.arguments.find((a) => a.position === 0);
14639
- if (!fileArg) return false;
14640
- let raw;
14641
- if (fileArg.literal !== null && fileArg.literal !== void 0) {
14642
- raw = String(fileArg.literal).trim();
14848
+ const method = call.method_name;
14849
+ if (method !== "Start" && method !== "ProcessStartInfo") return false;
14850
+ if (call.arguments.length >= 2) {
14851
+ const fileArg = call.arguments.find((a) => a.position === 0);
14852
+ const raw = fileArg?.literal != null ? String(fileArg.literal) : fileArg?.expression;
14853
+ return isConstNonShellExe(raw);
14854
+ }
14855
+ if (method === "Start" && call.arguments.length === 1) {
14856
+ const arg0 = call.arguments.find((a) => a.position === 0);
14857
+ const expr = (arg0?.expression ?? "").trim();
14858
+ return isConstNonShellExe(processStartInfoExe(expr, sourceLines));
14859
+ }
14860
+ return false;
14861
+ }
14862
+ function stripCsLiterals(line) {
14863
+ return line.replace(/\/\/.*$/, "").replace(/@?"(?:[^"\\]|\\.)*"/g, '""').replace(/'(?:[^'\\]|\\.)'/g, "''");
14864
+ }
14865
+ function csBraceDepthBefore(lines, idx) {
14866
+ let depth = 0;
14867
+ for (let i2 = 0; i2 < idx && i2 < lines.length; i2++) {
14868
+ for (const ch of stripCsLiterals(lines[i2])) {
14869
+ if (ch === "{") depth++;
14870
+ else if (ch === "}") depth--;
14871
+ }
14872
+ }
14873
+ return depth;
14874
+ }
14875
+ function netBraces(fragment) {
14876
+ let n = 0;
14877
+ for (const ch of fragment) {
14878
+ if (ch === "{") n++;
14879
+ else if (ch === "}") n--;
14880
+ }
14881
+ return n;
14882
+ }
14883
+ function splitCsIf(line) {
14884
+ const m = /\bif\s*\(/.exec(line);
14885
+ if (!m) return null;
14886
+ const ifCol = m.index;
14887
+ let i2 = m.index + m[0].length;
14888
+ let depth = 1;
14889
+ let inStr = false;
14890
+ let strCh = "";
14891
+ for (; i2 < line.length; i2++) {
14892
+ const c = line[i2];
14893
+ if (inStr) {
14894
+ if (c === "\\") {
14895
+ i2++;
14896
+ continue;
14897
+ }
14898
+ if (c === strCh) inStr = false;
14899
+ continue;
14900
+ }
14901
+ if (c === '"' || c === "'") {
14902
+ inStr = true;
14903
+ strCh = c;
14904
+ continue;
14905
+ }
14906
+ if (c === "(") depth++;
14907
+ else if (c === ")") {
14908
+ depth--;
14909
+ if (depth === 0) break;
14910
+ }
14911
+ }
14912
+ if (depth !== 0) return null;
14913
+ return { cond: line.slice(m.index + m[0].length, i2), rest: line.slice(i2 + 1), ifCol };
14914
+ }
14915
+ function csEqualityGuard(cond) {
14916
+ const c = cond.trim();
14917
+ let m = /^(.*?)\s*(==|!=)\s*@?"[^"]*"\s*$/.exec(c);
14918
+ if (m) return { op: m[2], exprSide: m[1].trim() };
14919
+ m = /^@?"[^"]*"\s*(==|!=)\s*(.*)$/.exec(c);
14920
+ if (m) return { op: m[1], exprSide: m[2].trim() };
14921
+ return null;
14922
+ }
14923
+ var CS_IDENT_RE = /[A-Za-z_]\w*/g;
14924
+ function csIdentifiers(expr) {
14925
+ return new Set(expr.match(CS_IDENT_RE) ?? []);
14926
+ }
14927
+ function csThenBlock(lines, ifIdx, rest) {
14928
+ const isExit = (s) => /^\s*(?:return|throw|continue|break)\b/.test(s);
14929
+ let firstIdx;
14930
+ let firstText;
14931
+ if (rest.trim()) {
14932
+ firstIdx = ifIdx;
14933
+ firstText = rest;
14643
14934
  } else {
14644
- raw = (fileArg.expression ?? "").trim();
14935
+ let j = ifIdx + 1;
14936
+ while (j < lines.length && stripCsLiterals(lines[j]).trim() === "") j++;
14937
+ firstIdx = j;
14938
+ firstText = lines[j] ?? "";
14645
14939
  }
14646
- if (!/^@?"[^"]*"$/.test(raw)) return false;
14647
- const program = (raw.replace(/^@?"|"$/g, "").split(/[\\/]/).pop() ?? "").toLowerCase().replace(/\.exe$/, "");
14648
- const SHELL_PROGRAMS = /* @__PURE__ */ new Set([
14649
- "sh",
14650
- "bash",
14651
- "zsh",
14652
- "dash",
14653
- "ash",
14654
- "ksh",
14655
- "cmd",
14656
- "powershell",
14657
- "pwsh"
14658
- ]);
14659
- return !SHELL_PROGRAMS.has(program);
14940
+ if (firstText.trim().startsWith("{")) {
14941
+ let depth = 0;
14942
+ let started = false;
14943
+ let endLine = lines.length - 1;
14944
+ let body2 = "";
14945
+ for (let i2 = firstIdx; i2 < lines.length; i2++) {
14946
+ const stripped = stripCsLiterals(i2 === firstIdx ? firstText : lines[i2]);
14947
+ let broke = false;
14948
+ for (const ch of stripped) {
14949
+ if (ch === "{") {
14950
+ depth++;
14951
+ started = true;
14952
+ if (depth === 1) continue;
14953
+ } else if (ch === "}") {
14954
+ depth--;
14955
+ if (depth === 0) {
14956
+ endLine = i2;
14957
+ broke = true;
14958
+ break;
14959
+ }
14960
+ }
14961
+ if (started && depth >= 1) body2 += ch;
14962
+ }
14963
+ if (broke) break;
14964
+ if (started) body2 += " ";
14965
+ }
14966
+ return { start: ifIdx, end: endLine, earlyExit: isExit(body2.trim()) };
14967
+ }
14968
+ return { start: ifIdx, end: firstIdx, earlyExit: isExit(firstText.trim()) };
14969
+ }
14970
+ function isCSharpSsrfHostAllowlistGuarded(call, pattern, language, sourceLines) {
14971
+ if (language !== "csharp") return false;
14972
+ if (pattern.type !== "ssrf") return false;
14973
+ if (!sourceLines || sourceLines.length === 0) return false;
14974
+ const candidates = /* @__PURE__ */ new Set();
14975
+ for (const a of call.arguments) {
14976
+ if (a.variable) candidates.add(a.variable);
14977
+ for (const id of csIdentifiers(a.expression ?? "")) candidates.add(id);
14978
+ }
14979
+ if (candidates.size === 0) return false;
14980
+ const sinkIdx = call.location.line - 1;
14981
+ const sinkDepth = csBraceDepthBefore(sourceLines, sinkIdx);
14982
+ for (let i2 = 0; i2 < sinkIdx; i2++) {
14983
+ const parts2 = splitCsIf(sourceLines[i2]);
14984
+ if (!parts2) continue;
14985
+ const guard = csEqualityGuard(parts2.cond);
14986
+ if (!guard) continue;
14987
+ const guardIds = csIdentifiers(guard.exprSide);
14988
+ if (![...guardIds].some((id) => candidates.has(id))) continue;
14989
+ const block = csThenBlock(sourceLines, i2, parts2.rest);
14990
+ if (guard.op === "==") {
14991
+ if (sinkIdx >= block.start && sinkIdx <= block.end) return true;
14992
+ } else {
14993
+ const guardDepth = csBraceDepthBefore(sourceLines, i2) + netBraces(stripCsLiterals(sourceLines[i2]).slice(0, parts2.ifCol));
14994
+ if (block.earlyExit && sinkIdx > block.end && guardDepth === sinkDepth) {
14995
+ return true;
14996
+ }
14997
+ }
14998
+ }
14999
+ return false;
14660
15000
  }
14661
15001
  function isSafeRustCommandCall(call, pattern, language) {
14662
15002
  if (language !== "rust") return false;
@@ -14913,7 +15253,10 @@ function findSinks(calls, patterns, typeHierarchy, language, sourceLines, types)
14913
15253
  if (isSafeJSChildProcessCall(call, pattern, language)) {
14914
15254
  continue;
14915
15255
  }
14916
- if (isSafeCSharpProcessStartCall(call, pattern, language)) {
15256
+ if (isSafeCSharpProcessStartCall(call, pattern, language, sourceLines)) {
15257
+ continue;
15258
+ }
15259
+ if (isCSharpSsrfHostAllowlistGuarded(call, pattern, language, sourceLines)) {
14917
15260
  continue;
14918
15261
  }
14919
15262
  if (pattern.safe_if_class_literal_at !== void 0 && argIsClassLiteral(call, pattern.safe_if_class_literal_at, types)) {