circle-ir 4.7.1 → 4.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analysis/config-loader.d.ts.map +1 -1
- package/dist/analysis/config-loader.js +79 -2
- package/dist/analysis/config-loader.js.map +1 -1
- package/dist/analysis/findings.js +1 -1
- package/dist/analysis/findings.js.map +1 -1
- package/dist/analysis/passes/insecure-deserialization-config-pass.d.ts +2 -0
- package/dist/analysis/passes/insecure-deserialization-config-pass.d.ts.map +1 -1
- package/dist/analysis/passes/insecure-deserialization-config-pass.js +45 -2
- package/dist/analysis/passes/insecure-deserialization-config-pass.js.map +1 -1
- package/dist/analysis/passes/language-sources-pass.d.ts.map +1 -1
- package/dist/analysis/passes/language-sources-pass.js +11 -1
- package/dist/analysis/passes/language-sources-pass.js.map +1 -1
- package/dist/analysis/passes/scan-secrets-pass.d.ts.map +1 -1
- package/dist/analysis/passes/scan-secrets-pass.js +10 -0
- package/dist/analysis/passes/scan-secrets-pass.js.map +1 -1
- package/dist/analysis/taint-matcher.d.ts.map +1 -1
- package/dist/analysis/taint-matcher.js +80 -0
- package/dist/analysis/taint-matcher.js.map +1 -1
- package/dist/analyzer.d.ts.map +1 -1
- package/dist/analyzer.js +14 -0
- package/dist/analyzer.js.map +1 -1
- package/dist/browser/circle-ir.js +320 -47
- package/dist/core/circle-ir-core.cjs +256 -43
- package/dist/core/circle-ir-core.js +256 -43
- package/dist/core/extractors/calls.js +17 -3
- package/dist/core/extractors/calls.js.map +1 -1
- package/dist/core/extractors/cfg.d.ts.map +1 -1
- package/dist/core/extractors/cfg.js +140 -40
- package/dist/core/extractors/cfg.js.map +1 -1
- package/package.json +1 -1
|
@@ -6046,13 +6046,21 @@ function extractCSharpCalls(tree, cache) {
|
|
|
6046
6046
|
const left = asn.childForFieldName("left");
|
|
6047
6047
|
if (left?.type !== "member_access_expression") continue;
|
|
6048
6048
|
const nameNode = left.childForFieldName("name");
|
|
6049
|
-
if (!nameNode
|
|
6049
|
+
if (!nameNode) continue;
|
|
6050
|
+
const propName = getNodeText(nameNode);
|
|
6051
|
+
const exprNode = left.childForFieldName("expression");
|
|
6052
|
+
if (propName === "Filter") {
|
|
6053
|
+
const recv = exprNode ? getNodeText(exprNode) : null;
|
|
6054
|
+
const recvType = recv ? typeMap.get(recv) : void 0;
|
|
6055
|
+
if (recvType !== "DirectorySearcher") continue;
|
|
6056
|
+
} else if (propName !== "CommandText") {
|
|
6057
|
+
continue;
|
|
6058
|
+
}
|
|
6050
6059
|
const right = asn.childForFieldName("right");
|
|
6051
6060
|
if (!right) continue;
|
|
6052
6061
|
const rhsText = getNodeText(right);
|
|
6053
|
-
const exprNode = left.childForFieldName("expression");
|
|
6054
6062
|
calls.push({
|
|
6055
|
-
method_name:
|
|
6063
|
+
method_name: propName,
|
|
6056
6064
|
receiver: exprNode ? getNodeText(exprNode) : null,
|
|
6057
6065
|
receiver_type: null,
|
|
6058
6066
|
receiver_type_fqn: null,
|
|
@@ -8618,6 +8626,9 @@ function buildCFG(tree, language, cache) {
|
|
|
8618
8626
|
if (effectiveLanguage === "go") {
|
|
8619
8627
|
return buildGoCFG(tree, blockIdCounter, cache);
|
|
8620
8628
|
}
|
|
8629
|
+
if (effectiveLanguage === "csharp") {
|
|
8630
|
+
return buildCSharpCFG(tree, blockIdCounter, cache);
|
|
8631
|
+
}
|
|
8621
8632
|
if (isJavaScript) {
|
|
8622
8633
|
const functions = [
|
|
8623
8634
|
...getNodesFromCache(tree.rootNode, "function_declaration", cache),
|
|
@@ -8630,7 +8641,7 @@ function buildCFG(tree, language, cache) {
|
|
|
8630
8641
|
const body2 = func2.childForFieldName("body");
|
|
8631
8642
|
if (!body2) continue;
|
|
8632
8643
|
if (body2.type === "statement_block") {
|
|
8633
|
-
const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter,
|
|
8644
|
+
const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, "js");
|
|
8634
8645
|
allBlocks.push(...blocks);
|
|
8635
8646
|
allEdges.push(...edges);
|
|
8636
8647
|
blockIdCounter = nextId;
|
|
@@ -8652,7 +8663,7 @@ function buildCFG(tree, language, cache) {
|
|
|
8652
8663
|
for (const method of methods) {
|
|
8653
8664
|
const body2 = method.childForFieldName("body");
|
|
8654
8665
|
if (!body2) continue;
|
|
8655
|
-
const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter,
|
|
8666
|
+
const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, "java");
|
|
8656
8667
|
allBlocks.push(...blocks);
|
|
8657
8668
|
allEdges.push(...edges);
|
|
8658
8669
|
blockIdCounter = nextId;
|
|
@@ -8660,7 +8671,28 @@ function buildCFG(tree, language, cache) {
|
|
|
8660
8671
|
}
|
|
8661
8672
|
return { blocks: allBlocks, edges: allEdges };
|
|
8662
8673
|
}
|
|
8663
|
-
function
|
|
8674
|
+
function buildCSharpCFG(tree, blockIdCounter, cache) {
|
|
8675
|
+
const allBlocks = [];
|
|
8676
|
+
const allEdges = [];
|
|
8677
|
+
const containers = [
|
|
8678
|
+
...getNodesFromCache(tree.rootNode, "method_declaration", cache),
|
|
8679
|
+
...getNodesFromCache(tree.rootNode, "constructor_declaration", cache),
|
|
8680
|
+
...getNodesFromCache(tree.rootNode, "destructor_declaration", cache),
|
|
8681
|
+
...getNodesFromCache(tree.rootNode, "operator_declaration", cache),
|
|
8682
|
+
...getNodesFromCache(tree.rootNode, "local_function_statement", cache),
|
|
8683
|
+
...getNodesFromCache(tree.rootNode, "accessor_declaration", cache)
|
|
8684
|
+
];
|
|
8685
|
+
for (const container of containers) {
|
|
8686
|
+
const body2 = container.childForFieldName("body");
|
|
8687
|
+
if (!body2 || body2.type !== "block") continue;
|
|
8688
|
+
const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, "csharp");
|
|
8689
|
+
allBlocks.push(...blocks);
|
|
8690
|
+
allEdges.push(...edges);
|
|
8691
|
+
blockIdCounter = nextId;
|
|
8692
|
+
}
|
|
8693
|
+
return { blocks: allBlocks, edges: allEdges };
|
|
8694
|
+
}
|
|
8695
|
+
function buildMethodCFG(body2, startId, dialect) {
|
|
8664
8696
|
const blocks = [];
|
|
8665
8697
|
const edges = [];
|
|
8666
8698
|
let currentId = startId;
|
|
@@ -8671,7 +8703,7 @@ function buildMethodCFG(body2, startId, isJavaScript) {
|
|
|
8671
8703
|
end_line: body2.startPosition.row + 1
|
|
8672
8704
|
};
|
|
8673
8705
|
blocks.push(entryBlock);
|
|
8674
|
-
const result = processStatements(body2, currentId, blocks, edges,
|
|
8706
|
+
const result = processStatements(body2, currentId, blocks, edges, dialect);
|
|
8675
8707
|
currentId = result.nextId;
|
|
8676
8708
|
if (result.entryId !== -1) {
|
|
8677
8709
|
edges.push({
|
|
@@ -8703,15 +8735,15 @@ function buildMethodCFG(body2, startId, isJavaScript) {
|
|
|
8703
8735
|
}
|
|
8704
8736
|
return { blocks, edges, nextId: currentId };
|
|
8705
8737
|
}
|
|
8706
|
-
function processStatements(container, startId, blocks, edges,
|
|
8738
|
+
function processStatements(container, startId, blocks, edges, dialect) {
|
|
8707
8739
|
let currentId = startId;
|
|
8708
8740
|
let firstBlockId = -1;
|
|
8709
8741
|
let lastExitIds = [];
|
|
8710
8742
|
for (let i2 = 0; i2 < container.childCount; i2++) {
|
|
8711
8743
|
const stmt = container.child(i2);
|
|
8712
8744
|
if (!stmt) continue;
|
|
8713
|
-
if (!isStatement(stmt,
|
|
8714
|
-
const result = processStatement(stmt, currentId, blocks, edges,
|
|
8745
|
+
if (!isStatement(stmt, dialect)) continue;
|
|
8746
|
+
const result = processStatement(stmt, currentId, blocks, edges, dialect);
|
|
8715
8747
|
currentId = result.nextId;
|
|
8716
8748
|
if (firstBlockId === -1) {
|
|
8717
8749
|
firstBlockId = result.entryId;
|
|
@@ -8732,31 +8764,49 @@ function processStatements(container, startId, blocks, edges, isJavaScript) {
|
|
|
8732
8764
|
nextId: currentId
|
|
8733
8765
|
};
|
|
8734
8766
|
}
|
|
8735
|
-
function processStatement(stmt, startId, blocks, edges,
|
|
8767
|
+
function processStatement(stmt, startId, blocks, edges, dialect) {
|
|
8736
8768
|
switch (stmt.type) {
|
|
8737
8769
|
case "if_statement":
|
|
8738
|
-
return processIfStatement(stmt, startId, blocks, edges,
|
|
8770
|
+
return processIfStatement(stmt, startId, blocks, edges, dialect);
|
|
8739
8771
|
case "for_statement":
|
|
8740
8772
|
case "enhanced_for_statement":
|
|
8741
8773
|
case "for_in_statement":
|
|
8742
8774
|
case "for_of_statement":
|
|
8743
|
-
|
|
8775
|
+
case "foreach_statement":
|
|
8776
|
+
return processForStatement(stmt, startId, blocks, edges, dialect);
|
|
8744
8777
|
case "while_statement":
|
|
8745
|
-
return processWhileStatement(stmt, startId, blocks, edges,
|
|
8778
|
+
return processWhileStatement(stmt, startId, blocks, edges, dialect);
|
|
8746
8779
|
case "do_statement":
|
|
8747
|
-
return processDoWhileStatement(stmt, startId, blocks, edges,
|
|
8780
|
+
return processDoWhileStatement(stmt, startId, blocks, edges, dialect);
|
|
8748
8781
|
case "try_statement":
|
|
8749
|
-
return processTryStatement(stmt, startId, blocks, edges,
|
|
8782
|
+
return processTryStatement(stmt, startId, blocks, edges, dialect);
|
|
8750
8783
|
case "switch_expression":
|
|
8751
8784
|
case "switch_statement":
|
|
8752
|
-
return processSwitchStatement(stmt, startId, blocks, edges,
|
|
8785
|
+
return processSwitchStatement(stmt, startId, blocks, edges, dialect);
|
|
8786
|
+
// C# scoped blocks add no branching — flow through the inner block so its
|
|
8787
|
+
// nested statements are still captured.
|
|
8788
|
+
case "using_statement":
|
|
8789
|
+
case "lock_statement":
|
|
8790
|
+
case "checked_statement":
|
|
8791
|
+
case "unsafe_statement": {
|
|
8792
|
+
const inner = stmt.childForFieldName("body") ?? lastBlockChild(stmt);
|
|
8793
|
+
if (inner) return processStatement(inner, startId, blocks, edges, dialect);
|
|
8794
|
+
return processSimpleStatement(stmt, startId, blocks);
|
|
8795
|
+
}
|
|
8753
8796
|
case "block":
|
|
8754
8797
|
case "statement_block":
|
|
8755
|
-
return processStatements(stmt, startId, blocks, edges,
|
|
8798
|
+
return processStatements(stmt, startId, blocks, edges, dialect);
|
|
8756
8799
|
default:
|
|
8757
8800
|
return processSimpleStatement(stmt, startId, blocks);
|
|
8758
8801
|
}
|
|
8759
8802
|
}
|
|
8803
|
+
function lastBlockChild(node) {
|
|
8804
|
+
for (let i2 = node.childCount - 1; i2 >= 0; i2--) {
|
|
8805
|
+
const c = node.child(i2);
|
|
8806
|
+
if (c && c.type === "block") return c;
|
|
8807
|
+
}
|
|
8808
|
+
return null;
|
|
8809
|
+
}
|
|
8760
8810
|
function processSimpleStatement(stmt, startId, blocks) {
|
|
8761
8811
|
const block = {
|
|
8762
8812
|
id: startId,
|
|
@@ -8771,7 +8821,7 @@ function processSimpleStatement(stmt, startId, blocks) {
|
|
|
8771
8821
|
nextId: startId + 1
|
|
8772
8822
|
};
|
|
8773
8823
|
}
|
|
8774
|
-
function processIfStatement(stmt, startId, blocks, edges,
|
|
8824
|
+
function processIfStatement(stmt, startId, blocks, edges, dialect) {
|
|
8775
8825
|
let currentId = startId;
|
|
8776
8826
|
const condBlock = {
|
|
8777
8827
|
id: currentId++,
|
|
@@ -8783,7 +8833,7 @@ function processIfStatement(stmt, startId, blocks, edges, isJavaScript) {
|
|
|
8783
8833
|
const exitIds = [];
|
|
8784
8834
|
const consequence = stmt.childForFieldName("consequence");
|
|
8785
8835
|
if (consequence) {
|
|
8786
|
-
const thenResult = processStatement(consequence, currentId, blocks, edges,
|
|
8836
|
+
const thenResult = processStatement(consequence, currentId, blocks, edges, dialect);
|
|
8787
8837
|
currentId = thenResult.nextId;
|
|
8788
8838
|
edges.push({
|
|
8789
8839
|
from: condBlock.id,
|
|
@@ -8794,7 +8844,7 @@ function processIfStatement(stmt, startId, blocks, edges, isJavaScript) {
|
|
|
8794
8844
|
}
|
|
8795
8845
|
const alternative = stmt.childForFieldName("alternative");
|
|
8796
8846
|
if (alternative) {
|
|
8797
|
-
const elseResult = processStatement(alternative, currentId, blocks, edges,
|
|
8847
|
+
const elseResult = processStatement(alternative, currentId, blocks, edges, dialect);
|
|
8798
8848
|
currentId = elseResult.nextId;
|
|
8799
8849
|
edges.push({
|
|
8800
8850
|
from: condBlock.id,
|
|
@@ -8811,7 +8861,7 @@ function processIfStatement(stmt, startId, blocks, edges, isJavaScript) {
|
|
|
8811
8861
|
nextId: currentId
|
|
8812
8862
|
};
|
|
8813
8863
|
}
|
|
8814
|
-
function processForStatement(stmt, startId, blocks, edges,
|
|
8864
|
+
function processForStatement(stmt, startId, blocks, edges, dialect) {
|
|
8815
8865
|
let currentId = startId;
|
|
8816
8866
|
const loopBlock = {
|
|
8817
8867
|
id: currentId++,
|
|
@@ -8822,7 +8872,7 @@ function processForStatement(stmt, startId, blocks, edges, isJavaScript) {
|
|
|
8822
8872
|
blocks.push(loopBlock);
|
|
8823
8873
|
const body2 = stmt.childForFieldName("body");
|
|
8824
8874
|
if (body2) {
|
|
8825
|
-
const bodyResult = processStatement(body2, currentId, blocks, edges,
|
|
8875
|
+
const bodyResult = processStatement(body2, currentId, blocks, edges, dialect);
|
|
8826
8876
|
currentId = bodyResult.nextId;
|
|
8827
8877
|
edges.push({
|
|
8828
8878
|
from: loopBlock.id,
|
|
@@ -8844,16 +8894,16 @@ function processForStatement(stmt, startId, blocks, edges, isJavaScript) {
|
|
|
8844
8894
|
nextId: currentId
|
|
8845
8895
|
};
|
|
8846
8896
|
}
|
|
8847
|
-
function processWhileStatement(stmt, startId, blocks, edges,
|
|
8848
|
-
return processForStatement(stmt, startId, blocks, edges,
|
|
8897
|
+
function processWhileStatement(stmt, startId, blocks, edges, dialect) {
|
|
8898
|
+
return processForStatement(stmt, startId, blocks, edges, dialect);
|
|
8849
8899
|
}
|
|
8850
|
-
function processDoWhileStatement(stmt, startId, blocks, edges,
|
|
8900
|
+
function processDoWhileStatement(stmt, startId, blocks, edges, dialect) {
|
|
8851
8901
|
let currentId = startId;
|
|
8852
8902
|
const body2 = stmt.childForFieldName("body");
|
|
8853
8903
|
let bodyEntryId = currentId;
|
|
8854
8904
|
let bodyExitIds = [];
|
|
8855
8905
|
if (body2) {
|
|
8856
|
-
const bodyResult = processStatement(body2, currentId, blocks, edges,
|
|
8906
|
+
const bodyResult = processStatement(body2, currentId, blocks, edges, dialect);
|
|
8857
8907
|
currentId = bodyResult.nextId;
|
|
8858
8908
|
bodyEntryId = bodyResult.entryId;
|
|
8859
8909
|
bodyExitIds = bodyResult.exitIds;
|
|
@@ -8883,13 +8933,13 @@ function processDoWhileStatement(stmt, startId, blocks, edges, isJavaScript) {
|
|
|
8883
8933
|
nextId: currentId
|
|
8884
8934
|
};
|
|
8885
8935
|
}
|
|
8886
|
-
function processTryStatement(stmt, startId, blocks, edges,
|
|
8936
|
+
function processTryStatement(stmt, startId, blocks, edges, dialect) {
|
|
8887
8937
|
let currentId = startId;
|
|
8888
8938
|
const exitIds = [];
|
|
8889
8939
|
const body2 = stmt.childForFieldName("body");
|
|
8890
8940
|
let tryEntryId = -1;
|
|
8891
8941
|
if (body2) {
|
|
8892
|
-
const bodyResult = processStatements(body2, currentId, blocks, edges,
|
|
8942
|
+
const bodyResult = processStatements(body2, currentId, blocks, edges, dialect);
|
|
8893
8943
|
currentId = bodyResult.nextId;
|
|
8894
8944
|
tryEntryId = bodyResult.entryId;
|
|
8895
8945
|
exitIds.push(...bodyResult.exitIds);
|
|
@@ -8899,7 +8949,7 @@ function processTryStatement(stmt, startId, blocks, edges, isJavaScript) {
|
|
|
8899
8949
|
if (child?.type === "catch_clause") {
|
|
8900
8950
|
const catchBody = child.childForFieldName("body");
|
|
8901
8951
|
if (catchBody) {
|
|
8902
|
-
const catchResult = processStatements(catchBody, currentId, blocks, edges,
|
|
8952
|
+
const catchResult = processStatements(catchBody, currentId, blocks, edges, dialect);
|
|
8903
8953
|
currentId = catchResult.nextId;
|
|
8904
8954
|
if (tryEntryId !== -1) {
|
|
8905
8955
|
edges.push({
|
|
@@ -8912,9 +8962,18 @@ function processTryStatement(stmt, startId, blocks, edges, isJavaScript) {
|
|
|
8912
8962
|
}
|
|
8913
8963
|
}
|
|
8914
8964
|
}
|
|
8915
|
-
|
|
8965
|
+
let finallyClause = stmt.childForFieldName("finally") ?? stmt.childForFieldName("finalizer");
|
|
8966
|
+
if (!finallyClause && dialect === "csharp") {
|
|
8967
|
+
for (let i2 = 0; i2 < stmt.childCount; i2++) {
|
|
8968
|
+
const child = stmt.child(i2);
|
|
8969
|
+
if (child?.type === "finally_clause") {
|
|
8970
|
+
finallyClause = lastBlockChild(child);
|
|
8971
|
+
break;
|
|
8972
|
+
}
|
|
8973
|
+
}
|
|
8974
|
+
}
|
|
8916
8975
|
if (finallyClause) {
|
|
8917
|
-
const finallyResult = processStatements(finallyClause, currentId, blocks, edges,
|
|
8976
|
+
const finallyResult = processStatements(finallyClause, currentId, blocks, edges, dialect);
|
|
8918
8977
|
currentId = finallyResult.nextId;
|
|
8919
8978
|
for (const exitId of exitIds) {
|
|
8920
8979
|
edges.push({
|
|
@@ -8935,7 +8994,7 @@ function processTryStatement(stmt, startId, blocks, edges, isJavaScript) {
|
|
|
8935
8994
|
nextId: currentId
|
|
8936
8995
|
};
|
|
8937
8996
|
}
|
|
8938
|
-
function processSwitchStatement(stmt, startId, blocks, edges,
|
|
8997
|
+
function processSwitchStatement(stmt, startId, blocks, edges, dialect) {
|
|
8939
8998
|
let currentId = startId;
|
|
8940
8999
|
const switchBlock = {
|
|
8941
9000
|
id: currentId++,
|
|
@@ -8947,11 +9006,11 @@ function processSwitchStatement(stmt, startId, blocks, edges, isJavaScript) {
|
|
|
8947
9006
|
const exitIds = [];
|
|
8948
9007
|
const body2 = stmt.childForFieldName("body");
|
|
8949
9008
|
if (body2) {
|
|
8950
|
-
const caseTypes =
|
|
9009
|
+
const caseTypes = dialect === "js" ? ["switch_case", "switch_default"] : dialect === "csharp" ? ["switch_section"] : ["switch_block_statement_group", "switch_rule"];
|
|
8951
9010
|
for (let i2 = 0; i2 < body2.childCount; i2++) {
|
|
8952
9011
|
const child = body2.child(i2);
|
|
8953
9012
|
if (child && caseTypes.includes(child.type)) {
|
|
8954
|
-
const caseResult = processStatements(child, currentId, blocks, edges,
|
|
9013
|
+
const caseResult = processStatements(child, currentId, blocks, edges, dialect);
|
|
8955
9014
|
currentId = caseResult.nextId;
|
|
8956
9015
|
if (caseResult.entryId !== -1) {
|
|
8957
9016
|
edges.push({
|
|
@@ -8981,7 +9040,7 @@ function buildBashCFG(tree, startId, cache) {
|
|
|
8981
9040
|
for (const func2 of functions) {
|
|
8982
9041
|
const body2 = func2.childForFieldName("body");
|
|
8983
9042
|
if (!body2) continue;
|
|
8984
|
-
const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter,
|
|
9043
|
+
const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, "java");
|
|
8985
9044
|
allBlocks.push(...blocks);
|
|
8986
9045
|
allEdges.push(...edges);
|
|
8987
9046
|
blockIdCounter = nextId;
|
|
@@ -9004,7 +9063,7 @@ function buildBashCFG(tree, startId, cache) {
|
|
|
9004
9063
|
let lastExitIds = [];
|
|
9005
9064
|
let firstBlockId = -1;
|
|
9006
9065
|
for (const stmt of topLevelStatements) {
|
|
9007
|
-
const result = processStatement(stmt, blockIdCounter, allBlocks, allEdges,
|
|
9066
|
+
const result = processStatement(stmt, blockIdCounter, allBlocks, allEdges, "java");
|
|
9008
9067
|
blockIdCounter = result.nextId;
|
|
9009
9068
|
if (firstBlockId === -1) {
|
|
9010
9069
|
firstBlockId = result.entryId;
|
|
@@ -9048,7 +9107,8 @@ function isBashStatement(node) {
|
|
|
9048
9107
|
]);
|
|
9049
9108
|
return bashStatementTypes.has(node.type);
|
|
9050
9109
|
}
|
|
9051
|
-
function isStatement(node,
|
|
9110
|
+
function isStatement(node, dialect) {
|
|
9111
|
+
if (dialect === "csharp") return csharpStatementTypes.has(node.type);
|
|
9052
9112
|
const javaStatementTypes = /* @__PURE__ */ new Set([
|
|
9053
9113
|
"local_variable_declaration",
|
|
9054
9114
|
"expression_statement",
|
|
@@ -9092,8 +9152,30 @@ function isStatement(node, isJavaScript) {
|
|
|
9092
9152
|
"export_statement",
|
|
9093
9153
|
"import_statement"
|
|
9094
9154
|
]);
|
|
9095
|
-
return
|
|
9096
|
-
}
|
|
9155
|
+
return dialect === "js" ? jsStatementTypes.has(node.type) : javaStatementTypes.has(node.type);
|
|
9156
|
+
}
|
|
9157
|
+
var csharpStatementTypes = /* @__PURE__ */ new Set([
|
|
9158
|
+
"local_declaration_statement",
|
|
9159
|
+
"expression_statement",
|
|
9160
|
+
"if_statement",
|
|
9161
|
+
"for_statement",
|
|
9162
|
+
"foreach_statement",
|
|
9163
|
+
"while_statement",
|
|
9164
|
+
"do_statement",
|
|
9165
|
+
"try_statement",
|
|
9166
|
+
"switch_statement",
|
|
9167
|
+
"return_statement",
|
|
9168
|
+
"throw_statement",
|
|
9169
|
+
"break_statement",
|
|
9170
|
+
"continue_statement",
|
|
9171
|
+
"using_statement",
|
|
9172
|
+
"lock_statement",
|
|
9173
|
+
"checked_statement",
|
|
9174
|
+
"unsafe_statement",
|
|
9175
|
+
"yield_statement",
|
|
9176
|
+
"goto_statement",
|
|
9177
|
+
"block"
|
|
9178
|
+
]);
|
|
9097
9179
|
function buildGoCFG(tree, blockIdCounter, cache) {
|
|
9098
9180
|
const allBlocks = [];
|
|
9099
9181
|
const allEdges = [];
|
|
@@ -9104,7 +9186,7 @@ function buildGoCFG(tree, blockIdCounter, cache) {
|
|
|
9104
9186
|
for (const func2 of functions) {
|
|
9105
9187
|
const body2 = func2.childForFieldName("body");
|
|
9106
9188
|
if (!body2 || body2.type !== "block") continue;
|
|
9107
|
-
const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter,
|
|
9189
|
+
const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, "java");
|
|
9108
9190
|
allBlocks.push(...blocks);
|
|
9109
9191
|
allEdges.push(...edges);
|
|
9110
9192
|
blockIdCounter = nextId;
|
|
@@ -11653,7 +11735,11 @@ var DEFAULT_SINKS = [
|
|
|
11653
11735
|
// File: covers both File(String pathname) and File(parent, child). The 2-arg
|
|
11654
11736
|
// overload's child argument carries CVE-2018-8041 (Camel mail Content-Disposition
|
|
11655
11737
|
// filename written to disk).
|
|
11656
|
-
|
|
11738
|
+
// Java `new File(path)` idiom. Excluded for C#: there is no `new File()` in
|
|
11739
|
+
// .NET (it's `System.IO.File` statics + `FileStream`, covered separately), and
|
|
11740
|
+
// this over-matched ASP.NET `ControllerBase.File(stream|bytes, contentType)` —
|
|
11741
|
+
// a result helper that returns a file, not a path sink (cognium-ai#326 B).
|
|
11742
|
+
{ method: "File", class: "constructor", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0, 1], exclude_languages: ["csharp"] },
|
|
11657
11743
|
{ method: "FileInputStream", class: "constructor", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
|
|
11658
11744
|
{ method: "FileOutputStream", class: "constructor", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
|
|
11659
11745
|
{ method: "FileReader", class: "constructor", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
|
|
@@ -13180,6 +13266,11 @@ var DEFAULT_SINKS = [
|
|
|
13180
13266
|
// ADO.NET `cmd.CommandText = "…" + x` — emitted as a synthetic call by
|
|
13181
13267
|
// extractCSharpCalls (property-assignment sink; the ctor-arg sink misses it).
|
|
13182
13268
|
{ method: "CommandText", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
13269
|
+
// `DirectorySearcher.Filter = "(uid=" + x + ")"` — LDAP injection (cognium-ai#272).
|
|
13270
|
+
// Emitted as a synthetic call by extractCSharpCalls ONLY when the receiver
|
|
13271
|
+
// resolves to a DirectorySearcher, so this classless entry never over-matches
|
|
13272
|
+
// other `.Filter =` assignments (DataView/BindingSource/collection filters).
|
|
13273
|
+
{ method: "Filter", type: "ldap_injection", cwe: "CWE-90", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13183
13274
|
// ADO.NET `cmd.Execute*()` — object-carried sink (cognium-dev#271). The taint
|
|
13184
13275
|
// rides the SqlCommand receiver (CommandText set from tainted data); the
|
|
13185
13276
|
// receiver is surfaced as arg[0] by extractCSharpCalls, and the command object
|
|
@@ -13196,6 +13287,9 @@ var DEFAULT_SINKS = [
|
|
|
13196
13287
|
// injectable — the second is the argv path where taint rides arg[1] (#276).
|
|
13197
13288
|
{ method: "Start", class: "Process", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1], languages: ["csharp"] },
|
|
13198
13289
|
{ method: "ProcessStartInfo", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1], languages: ["csharp"] },
|
|
13290
|
+
// P/Invoke of libc `system(cmd)` — lowercase `system` in C# is virtually
|
|
13291
|
+
// always the imported shell entry point (cognium-ai#275 interop/IlPinvoke).
|
|
13292
|
+
{ method: "system", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
13199
13293
|
// C# path traversal — System.IO file APIs (CWE-22). Distinctive method names.
|
|
13200
13294
|
{ method: "ReadAllText", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13201
13295
|
{ method: "ReadAllBytes", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
@@ -13208,6 +13302,25 @@ var DEFAULT_SINKS = [
|
|
|
13208
13302
|
{ method: "FileStream", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13209
13303
|
{ method: "StreamReader", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13210
13304
|
{ method: "StreamWriter", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13305
|
+
// Remaining System.IO.File path APIs — class-scoped so they don't collide
|
|
13306
|
+
// with unrelated methods. Copy/Move take a source AND destination path (both
|
|
13307
|
+
// attacker-controllable → read-anywhere / write-anywhere), hence [0, 1].
|
|
13308
|
+
{ method: "Copy", class: "File", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0, 1], languages: ["csharp"] },
|
|
13309
|
+
{ method: "Move", class: "File", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0, 1], languages: ["csharp"] },
|
|
13310
|
+
{ method: "Delete", class: "File", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13311
|
+
{ method: "Open", class: "File", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13312
|
+
{ method: "OpenText", class: "File", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13313
|
+
{ method: "Create", class: "File", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13314
|
+
{ method: "WriteAllLines", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13315
|
+
{ method: "AppendAllLines", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13316
|
+
// System.IO.Directory path APIs.
|
|
13317
|
+
{ method: "CreateDirectory", class: "Directory", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13318
|
+
{ method: "Delete", class: "Directory", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13319
|
+
{ method: "GetFiles", class: "Directory", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13320
|
+
{ method: "EnumerateFiles", class: "Directory", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13321
|
+
// ASP.NET `ControllerBase.PhysicalFile(path, contentType)` serves a file from
|
|
13322
|
+
// an absolute disk path — attacker-controllable path is CWE-22 (cognium-ai#326/#275).
|
|
13323
|
+
{ method: "PhysicalFile", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13211
13324
|
// C# SSRF — HttpClient / WebClient / WebRequest (CWE-918).
|
|
13212
13325
|
{ method: "GetAsync", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13213
13326
|
{ method: "PostAsync", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
@@ -13224,13 +13337,36 @@ var DEFAULT_SINKS = [
|
|
|
13224
13337
|
// C# code injection — dynamic script/assembly loading (CWE-94).
|
|
13225
13338
|
{ method: "EvaluateAsync", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
13226
13339
|
{ method: "RunAsync", class: "CSharpScript", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
13227
|
-
//
|
|
13340
|
+
// Loading an assembly from an attacker-controlled name/path is arbitrary code
|
|
13341
|
+
// execution. Class-scoped to `Assembly` (low FP — a tainted arg here is rare
|
|
13342
|
+
// in benign code). `Type.GetType`/`Activator.CreateInstance` are intentionally
|
|
13343
|
+
// NOT added — reflection with config-driven type names is common in DI, an FP
|
|
13344
|
+
// trap without the reflection-suppress machinery.
|
|
13345
|
+
{ method: "Load", class: "Assembly", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
13346
|
+
{ method: "LoadFrom", class: "Assembly", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
13347
|
+
{ method: "LoadFile", class: "Assembly", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
13348
|
+
// C# insecure deserialization — the polymorphic BCL formatters that can
|
|
13349
|
+
// instantiate arbitrary types named in the payload (CWE-502, cognium-ai#318).
|
|
13350
|
+
// Each of these classes exists only to deserialize and is unsafe on untrusted
|
|
13351
|
+
// input; class-scoped, so no collision with safe JSON APIs (System.Text.Json /
|
|
13352
|
+
// Newtonsoft-default, which are intentionally NOT sinks).
|
|
13228
13353
|
{ method: "Deserialize", class: "BinaryFormatter", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
13229
13354
|
{ method: "Deserialize", class: "NetDataContractSerializer", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
13355
|
+
{ method: "Deserialize", class: "SoapFormatter", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
13356
|
+
{ method: "Deserialize", class: "LosFormatter", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
13357
|
+
{ method: "Deserialize", class: "ObjectStateFormatter", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0], languages: ["csharp"] },
|
|
13230
13358
|
// C# XSS — raw HTML output (CWE-79).
|
|
13231
13359
|
{ method: "Raw", class: "Html", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13232
13360
|
{ method: "Write", class: "Response", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13233
13361
|
{ method: "HtmlString", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13362
|
+
// Blazor `new MarkupString(x)` renders its argument as raw HTML (the framework's
|
|
13363
|
+
// documented "trusted markup" escape hatch) — attacker-controlled input is XSS. (ca#275)
|
|
13364
|
+
{ method: "MarkupString", class: "constructor", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13365
|
+
// `String.Format(fmt, …)` with an attacker-controlled FORMAT string — CWE-134.
|
|
13366
|
+
// Taint-gated on arg 0 (the format), so ordinary `String.Format("...", user)` where
|
|
13367
|
+
// only an argument is tainted never fires. .NET composite formatting can't corrupt
|
|
13368
|
+
// memory, so medium (FormatException DoS / unintended arg access), unlike C printf.
|
|
13369
|
+
{ method: "Format", class: "String", type: "format_string", cwe: "CWE-134", severity: "medium", arg_positions: [0], languages: ["csharp"] },
|
|
13234
13370
|
// C# LDAP injection — System.DirectoryServices (CWE-90). The user-built
|
|
13235
13371
|
// filter is the constructor argument.
|
|
13236
13372
|
{ method: "DirectorySearcher", type: "ldap_injection", cwe: "CWE-90", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
@@ -13251,14 +13387,37 @@ var DEFAULT_SINKS = [
|
|
|
13251
13387
|
// cognium-dev#273/#275). `BsonDocument.Parse(userJson)` deserializes an
|
|
13252
13388
|
// attacker-controlled query document. Class-scoped (static receiver resolves).
|
|
13253
13389
|
{ method: "Parse", class: "BsonDocument", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13390
|
+
// C# log injection — Microsoft.Extensions.Logging `ILogger` (CWE-117,
|
|
13391
|
+
// cognium-ai#318). Only the message TEMPLATE (arg[0]) is the injectable
|
|
13392
|
+
// position; the structured form `LogInformation("… {Id}", id)` keeps taint in
|
|
13393
|
+
// later args (the logger renders them as data), so arg_positions:[0] does not
|
|
13394
|
+
// flag it. Mirrors the Java `Logger` sinks; severity low.
|
|
13395
|
+
{ method: "LogInformation", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0], languages: ["csharp"] },
|
|
13396
|
+
{ method: "LogWarning", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0], languages: ["csharp"] },
|
|
13397
|
+
{ method: "LogError", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0], languages: ["csharp"] },
|
|
13398
|
+
{ method: "LogDebug", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0], languages: ["csharp"] },
|
|
13399
|
+
{ method: "LogCritical", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0], languages: ["csharp"] },
|
|
13400
|
+
{ method: "LogTrace", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0], languages: ["csharp"] },
|
|
13401
|
+
// Generic `ILogger.Log(logLevel, message, …)` — class-scoped (`Log` alone is
|
|
13402
|
+
// too generic); the message is arg[1].
|
|
13403
|
+
{ method: "Log", class: "ILogger", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [1], languages: ["csharp"] },
|
|
13254
13404
|
// C# XPath injection — System.Xml.XPath (CWE-643). Distinctive selector methods.
|
|
13255
13405
|
{ method: "SelectSingleNode", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13256
13406
|
{ method: "SelectNodes", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13257
13407
|
{ method: "Compile", class: "XPathExpression", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13408
|
+
// XPathNavigator.Select/Evaluate — class-scoped (both names collide with LINQ
|
|
13409
|
+
// `.Select`/`.Evaluate`, so they must resolve to an XPathNavigator receiver).
|
|
13410
|
+
{ method: "Select", class: "XPathNavigator", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13411
|
+
{ method: "Evaluate", class: "XPathNavigator", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13258
13412
|
// C# XXE — untrusted XML into a parser without DTD hardening (CWE-611).
|
|
13259
13413
|
{ method: "LoadXml", type: "xxe", cwe: "CWE-611", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13260
13414
|
{ method: "Load", class: "XmlDocument", type: "xxe", cwe: "CWE-611", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13261
13415
|
{ method: "Load", class: "XDocument", type: "xxe", cwe: "CWE-611", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13416
|
+
// `new XmlTextReader(input)` — its DtdProcessing defaults to Parse (resolves
|
|
13417
|
+
// external entities), unlike `XmlReader.Create` (Prohibit). CWE-611,
|
|
13418
|
+
// cognium-ai#318. The 4.7.0 XmlResolver=null / DtdProcessing=Prohibit
|
|
13419
|
+
// hardening still suppresses the safe shape.
|
|
13420
|
+
{ method: "XmlTextReader", type: "xxe", cwe: "CWE-611", severity: "high", arg_positions: [0], languages: ["csharp"] },
|
|
13262
13421
|
// Python SQLi — asyncpg Connection.*
|
|
13263
13422
|
{ method: "execute", class: "Connection", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0] },
|
|
13264
13423
|
{ method: "fetch", class: "Connection", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0] },
|
|
@@ -14576,6 +14735,57 @@ function isSafeJSChildProcessCall(call, pattern, language) {
|
|
|
14576
14735
|
if (SHELL_PROGRAMS.has(program)) return false;
|
|
14577
14736
|
return true;
|
|
14578
14737
|
}
|
|
14738
|
+
var CSHARP_SHELL_PROGRAMS = /* @__PURE__ */ new Set([
|
|
14739
|
+
"sh",
|
|
14740
|
+
"bash",
|
|
14741
|
+
"zsh",
|
|
14742
|
+
"dash",
|
|
14743
|
+
"ash",
|
|
14744
|
+
"ksh",
|
|
14745
|
+
"cmd",
|
|
14746
|
+
"powershell",
|
|
14747
|
+
"pwsh"
|
|
14748
|
+
]);
|
|
14749
|
+
function isConstNonShellExe(raw) {
|
|
14750
|
+
if (!raw) return false;
|
|
14751
|
+
const t = raw.trim();
|
|
14752
|
+
if (!/^@?"[^"]*"$/.test(t)) return false;
|
|
14753
|
+
const program = (t.replace(/^@?"|"$/g, "").split(/[\\/]/).pop() ?? "").toLowerCase().replace(/\.exe$/, "");
|
|
14754
|
+
return !CSHARP_SHELL_PROGRAMS.has(program);
|
|
14755
|
+
}
|
|
14756
|
+
var PSI_CTOR_EXE_RE = /\bnew\s+ProcessStartInfo\s*(?:<[^>]*>)?\s*\(\s*(@?"[^"]*")/;
|
|
14757
|
+
function processStartInfoExe(expr, sourceLines) {
|
|
14758
|
+
const inline = PSI_CTOR_EXE_RE.exec(expr);
|
|
14759
|
+
if (inline) return inline[1];
|
|
14760
|
+
if (sourceLines && /^[A-Za-z_]\w*$/.test(expr.trim())) {
|
|
14761
|
+
const varName = expr.trim();
|
|
14762
|
+
const assignRe = new RegExp(
|
|
14763
|
+
`\\b${varName}\\s*=\\s*new\\s+ProcessStartInfo\\s*(?:<[^>]*>)?\\s*\\(\\s*(@?"[^"]*")`
|
|
14764
|
+
);
|
|
14765
|
+
for (const line of sourceLines) {
|
|
14766
|
+
const m = assignRe.exec(line);
|
|
14767
|
+
if (m) return m[1];
|
|
14768
|
+
}
|
|
14769
|
+
}
|
|
14770
|
+
return null;
|
|
14771
|
+
}
|
|
14772
|
+
function isSafeCSharpProcessStartCall(call, pattern, language, sourceLines) {
|
|
14773
|
+
if (language !== "csharp") return false;
|
|
14774
|
+
if (pattern.type !== "command_injection") return false;
|
|
14775
|
+
const method = call.method_name;
|
|
14776
|
+
if (method !== "Start" && method !== "ProcessStartInfo") return false;
|
|
14777
|
+
if (call.arguments.length >= 2) {
|
|
14778
|
+
const fileArg = call.arguments.find((a) => a.position === 0);
|
|
14779
|
+
const raw = fileArg?.literal != null ? String(fileArg.literal) : fileArg?.expression;
|
|
14780
|
+
return isConstNonShellExe(raw);
|
|
14781
|
+
}
|
|
14782
|
+
if (method === "Start" && call.arguments.length === 1) {
|
|
14783
|
+
const arg0 = call.arguments.find((a) => a.position === 0);
|
|
14784
|
+
const expr = (arg0?.expression ?? "").trim();
|
|
14785
|
+
return isConstNonShellExe(processStartInfoExe(expr, sourceLines));
|
|
14786
|
+
}
|
|
14787
|
+
return false;
|
|
14788
|
+
}
|
|
14579
14789
|
function isSafeRustCommandCall(call, pattern, language) {
|
|
14580
14790
|
if (language !== "rust") return false;
|
|
14581
14791
|
if (pattern.type !== "command_injection") return false;
|
|
@@ -14831,6 +15041,9 @@ function findSinks(calls, patterns, typeHierarchy, language, sourceLines, types)
|
|
|
14831
15041
|
if (isSafeJSChildProcessCall(call, pattern, language)) {
|
|
14832
15042
|
continue;
|
|
14833
15043
|
}
|
|
15044
|
+
if (isSafeCSharpProcessStartCall(call, pattern, language, sourceLines)) {
|
|
15045
|
+
continue;
|
|
15046
|
+
}
|
|
14834
15047
|
if (pattern.safe_if_class_literal_at !== void 0 && argIsClassLiteral(call, pattern.safe_if_class_literal_at, types)) {
|
|
14835
15048
|
continue;
|
|
14836
15049
|
}
|