cognium-dev 3.175.0 → 3.177.0
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/cli.js +325 -55
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -6725,8 +6725,16 @@ function extractGoCallInfo(node) {
|
|
|
6725
6725
|
if (funcNode.type === "selector_expression") {
|
|
6726
6726
|
const operand = funcNode.childForFieldName("operand");
|
|
6727
6727
|
const field = funcNode.childForFieldName("field");
|
|
6728
|
-
receiver = operand ? getNodeText(operand) : null;
|
|
6729
6728
|
methodName = field ? getNodeText(field) : getNodeText(funcNode);
|
|
6729
|
+
if (operand) {
|
|
6730
|
+
const opText = getNodeText(operand);
|
|
6731
|
+
if (operand.type === "identifier") {
|
|
6732
|
+
const resolved = resolveGoLocalReceiverType(opText, node);
|
|
6733
|
+
receiver = resolved !== null ? resolved : opText;
|
|
6734
|
+
} else {
|
|
6735
|
+
receiver = opText;
|
|
6736
|
+
}
|
|
6737
|
+
}
|
|
6730
6738
|
} else if (funcNode.type === "identifier") {
|
|
6731
6739
|
methodName = getNodeText(funcNode);
|
|
6732
6740
|
} else {
|
|
@@ -6806,6 +6814,89 @@ function findGoEnclosingFunction(node) {
|
|
|
6806
6814
|
}
|
|
6807
6815
|
return null;
|
|
6808
6816
|
}
|
|
6817
|
+
function resolveGoLocalReceiverType(operandName, callNode) {
|
|
6818
|
+
let cur = callNode.parent;
|
|
6819
|
+
while (cur) {
|
|
6820
|
+
if (cur.type === "method_declaration") {
|
|
6821
|
+
const receiver = cur.childForFieldName("receiver");
|
|
6822
|
+
if (receiver) {
|
|
6823
|
+
const t = extractGoParamTypeForName(receiver, operandName);
|
|
6824
|
+
if (t !== null)
|
|
6825
|
+
return t;
|
|
6826
|
+
}
|
|
6827
|
+
const params = cur.childForFieldName("parameters");
|
|
6828
|
+
if (params) {
|
|
6829
|
+
const t = extractGoParamTypeForName(params, operandName);
|
|
6830
|
+
if (t !== null)
|
|
6831
|
+
return t;
|
|
6832
|
+
}
|
|
6833
|
+
return null;
|
|
6834
|
+
}
|
|
6835
|
+
if (cur.type === "function_declaration" || cur.type === "func_literal") {
|
|
6836
|
+
const params = cur.childForFieldName("parameters");
|
|
6837
|
+
if (params) {
|
|
6838
|
+
const t = extractGoParamTypeForName(params, operandName);
|
|
6839
|
+
if (t !== null)
|
|
6840
|
+
return t;
|
|
6841
|
+
}
|
|
6842
|
+
return null;
|
|
6843
|
+
}
|
|
6844
|
+
cur = cur.parent;
|
|
6845
|
+
}
|
|
6846
|
+
return null;
|
|
6847
|
+
}
|
|
6848
|
+
function extractGoParamTypeForName(list, operandName) {
|
|
6849
|
+
for (let i2 = 0;i2 < list.namedChildCount; i2++) {
|
|
6850
|
+
const child = list.namedChild(i2);
|
|
6851
|
+
if (!child || child.type !== "parameter_declaration")
|
|
6852
|
+
continue;
|
|
6853
|
+
const typeNode = child.childForFieldName("type");
|
|
6854
|
+
if (!typeNode)
|
|
6855
|
+
continue;
|
|
6856
|
+
let matched = false;
|
|
6857
|
+
for (let j = 0;j < child.namedChildCount; j++) {
|
|
6858
|
+
const c = child.namedChild(j);
|
|
6859
|
+
if (!c)
|
|
6860
|
+
continue;
|
|
6861
|
+
if (c.type === "identifier" && getNodeText(c) === operandName) {
|
|
6862
|
+
matched = true;
|
|
6863
|
+
break;
|
|
6864
|
+
}
|
|
6865
|
+
if (c.type === "identifier_list") {
|
|
6866
|
+
for (let k = 0;k < c.namedChildCount; k++) {
|
|
6867
|
+
const id = c.namedChild(k);
|
|
6868
|
+
if (id && id.type === "identifier" && getNodeText(id) === operandName) {
|
|
6869
|
+
matched = true;
|
|
6870
|
+
break;
|
|
6871
|
+
}
|
|
6872
|
+
}
|
|
6873
|
+
if (matched)
|
|
6874
|
+
break;
|
|
6875
|
+
}
|
|
6876
|
+
}
|
|
6877
|
+
if (!matched)
|
|
6878
|
+
continue;
|
|
6879
|
+
return extractGoTypeLastSegment(typeNode);
|
|
6880
|
+
}
|
|
6881
|
+
return null;
|
|
6882
|
+
}
|
|
6883
|
+
function extractGoTypeLastSegment(typeNode) {
|
|
6884
|
+
if (typeNode.type === "pointer_type") {
|
|
6885
|
+
const inner = typeNode.namedChild(0);
|
|
6886
|
+
return inner ? extractGoTypeLastSegment(inner) : null;
|
|
6887
|
+
}
|
|
6888
|
+
if (typeNode.type === "qualified_type") {
|
|
6889
|
+
const name2 = typeNode.childForFieldName("name");
|
|
6890
|
+
if (name2)
|
|
6891
|
+
return getNodeText(name2);
|
|
6892
|
+
const last = typeNode.namedChild(typeNode.namedChildCount - 1);
|
|
6893
|
+
return last ? getNodeText(last) : null;
|
|
6894
|
+
}
|
|
6895
|
+
if (typeNode.type === "type_identifier" || typeNode.type === "identifier") {
|
|
6896
|
+
return getNodeText(typeNode);
|
|
6897
|
+
}
|
|
6898
|
+
return null;
|
|
6899
|
+
}
|
|
6809
6900
|
// ../circle-ir/dist/core/extractors/imports.js
|
|
6810
6901
|
function detectLanguage2(tree) {
|
|
6811
6902
|
const root = tree.rootNode;
|
|
@@ -7583,10 +7674,10 @@ function buildCFG(tree, language, cache) {
|
|
|
7583
7674
|
const allEdges = [];
|
|
7584
7675
|
let blockIdCounter = 0;
|
|
7585
7676
|
if (effectiveLanguage === "bash") {
|
|
7586
|
-
return buildBashCFG(tree, blockIdCounter);
|
|
7677
|
+
return buildBashCFG(tree, blockIdCounter, cache);
|
|
7587
7678
|
}
|
|
7588
7679
|
if (effectiveLanguage === "go") {
|
|
7589
|
-
return buildGoCFG(tree, blockIdCounter);
|
|
7680
|
+
return buildGoCFG(tree, blockIdCounter, cache);
|
|
7590
7681
|
}
|
|
7591
7682
|
if (isJavaScript) {
|
|
7592
7683
|
const functions = [
|
|
@@ -7946,11 +8037,11 @@ function processSwitchStatement(stmt, startId, blocks, edges, isJavaScript) {
|
|
|
7946
8037
|
nextId: currentId
|
|
7947
8038
|
};
|
|
7948
8039
|
}
|
|
7949
|
-
function buildBashCFG(tree, startId) {
|
|
8040
|
+
function buildBashCFG(tree, startId, cache) {
|
|
7950
8041
|
const allBlocks = [];
|
|
7951
8042
|
const allEdges = [];
|
|
7952
8043
|
let blockIdCounter = startId;
|
|
7953
|
-
const functions =
|
|
8044
|
+
const functions = getNodesFromCache(tree.rootNode, "function_definition", cache);
|
|
7954
8045
|
for (const func2 of functions) {
|
|
7955
8046
|
const body2 = func2.childForFieldName("body");
|
|
7956
8047
|
if (!body2)
|
|
@@ -8068,12 +8159,12 @@ function isStatement(node, isJavaScript) {
|
|
|
8068
8159
|
]);
|
|
8069
8160
|
return isJavaScript ? jsStatementTypes.has(node.type) : javaStatementTypes.has(node.type);
|
|
8070
8161
|
}
|
|
8071
|
-
function buildGoCFG(tree, blockIdCounter) {
|
|
8162
|
+
function buildGoCFG(tree, blockIdCounter, cache) {
|
|
8072
8163
|
const allBlocks = [];
|
|
8073
8164
|
const allEdges = [];
|
|
8074
8165
|
const functions = [
|
|
8075
|
-
...
|
|
8076
|
-
...
|
|
8166
|
+
...getNodesFromCache(tree.rootNode, "function_declaration", cache),
|
|
8167
|
+
...getNodesFromCache(tree.rootNode, "method_declaration", cache)
|
|
8077
8168
|
];
|
|
8078
8169
|
for (const func2 of functions) {
|
|
8079
8170
|
const body2 = func2.childForFieldName("body");
|
|
@@ -10568,6 +10659,40 @@ var OPEN_REDIRECT_FRAMEWORK_SINKS = [
|
|
|
10568
10659
|
{ method: "Redirect", class: "Context", type: "open_redirect", cwe: "CWE-601", severity: "medium", arg_positions: [1], languages: ["go"] },
|
|
10569
10660
|
{ method: "Redirect", class: "Ctx", type: "open_redirect", cwe: "CWE-601", severity: "medium", arg_positions: [0], languages: ["go"] }
|
|
10570
10661
|
];
|
|
10662
|
+
var DESERIALIZATION_FRAMEWORK_SINKS = [
|
|
10663
|
+
{ method: "loads", class: "pickle", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0], languages: ["python"] },
|
|
10664
|
+
{ method: "load", class: "pickle", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0], languages: ["python"] },
|
|
10665
|
+
{ method: "loads", class: "cPickle", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0], languages: ["python"] },
|
|
10666
|
+
{ method: "load", class: "cPickle", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0], languages: ["python"] },
|
|
10667
|
+
{ method: "loads", class: "marshal", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0], languages: ["python"] },
|
|
10668
|
+
{ method: "load", class: "marshal", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0], languages: ["python"] },
|
|
10669
|
+
{ method: "loads", class: "dill", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0], languages: ["python"] },
|
|
10670
|
+
{ method: "load", class: "dill", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0], languages: ["python"] },
|
|
10671
|
+
{ method: "decode", class: "jsonpickle", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0], languages: ["python"] },
|
|
10672
|
+
{ method: "Decode", class: "Decoder", type: "deserialization", cwe: "CWE-502", severity: "high", arg_positions: [0], languages: ["go"] },
|
|
10673
|
+
{ method: "Unmarshal", class: "yaml", type: "deserialization", cwe: "CWE-502", severity: "high", arg_positions: [0], languages: ["go"] },
|
|
10674
|
+
{ method: "unserialize", class: "nodeSerialize", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0], languages: ["javascript", "typescript"] }
|
|
10675
|
+
];
|
|
10676
|
+
var NOSQL_FRAMEWORK_SINKS = [
|
|
10677
|
+
{ method: "find", class: "Collection", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["python"] },
|
|
10678
|
+
{ method: "find_one", class: "Collection", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["python"] },
|
|
10679
|
+
{ method: "aggregate", class: "Collection", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["python"] },
|
|
10680
|
+
{ method: "update_one", class: "Collection", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0, 1], languages: ["python"] },
|
|
10681
|
+
{ method: "update_many", class: "Collection", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0, 1], languages: ["python"] },
|
|
10682
|
+
{ method: "delete_one", class: "Collection", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["python"] },
|
|
10683
|
+
{ method: "delete_many", class: "Collection", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["python"] },
|
|
10684
|
+
{ method: "count_documents", class: "Collection", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["python"] },
|
|
10685
|
+
{ method: "find", class: "MongoTemplate", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["java"] },
|
|
10686
|
+
{ method: "findOne", class: "MongoTemplate", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["java"] },
|
|
10687
|
+
{ method: "findAll", class: "MongoTemplate", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["java"] },
|
|
10688
|
+
{ method: "find", class: "MongoCollection", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["java"] },
|
|
10689
|
+
{ method: "aggregate", class: "MongoCollection", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["java"] },
|
|
10690
|
+
{ method: "Find", class: "Collection", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [1], languages: ["go"] },
|
|
10691
|
+
{ method: "FindOne", class: "Collection", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [1], languages: ["go"] },
|
|
10692
|
+
{ method: "UpdateOne", class: "Collection", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [1, 2], languages: ["go"] },
|
|
10693
|
+
{ method: "UpdateMany", class: "Collection", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [1, 2], languages: ["go"] },
|
|
10694
|
+
{ method: "DeleteOne", class: "Collection", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [1], languages: ["go"] }
|
|
10695
|
+
];
|
|
10571
10696
|
var TRUST_BOUNDARY_FRAMEWORK_SINKS = [
|
|
10572
10697
|
{ method: "set", class: "cache", type: "trust_boundary", cwe: "CWE-501", severity: "medium", arg_positions: [1], languages: ["python"] },
|
|
10573
10698
|
{ method: "set_many", class: "cache", type: "trust_boundary", cwe: "CWE-501", severity: "medium", arg_positions: [0], languages: ["python"] },
|
|
@@ -11653,7 +11778,9 @@ var DEFAULT_SINKS = [
|
|
|
11653
11778
|
{ method: "Generate", class: "LLM", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["go"] },
|
|
11654
11779
|
{ method: "GenerateContent", class: "Model", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["go"] },
|
|
11655
11780
|
...OPEN_REDIRECT_FRAMEWORK_SINKS,
|
|
11656
|
-
...TRUST_BOUNDARY_FRAMEWORK_SINKS
|
|
11781
|
+
...TRUST_BOUNDARY_FRAMEWORK_SINKS,
|
|
11782
|
+
...DESERIALIZATION_FRAMEWORK_SINKS,
|
|
11783
|
+
...NOSQL_FRAMEWORK_SINKS
|
|
11657
11784
|
];
|
|
11658
11785
|
var DEFAULT_SANITIZERS = [
|
|
11659
11786
|
{ method: "setString", class: "PreparedStatement", removes: ["sql_injection"] },
|
|
@@ -11948,6 +12075,84 @@ var DEFAULT_HEADER_RULES = [
|
|
|
11948
12075
|
note: "Fires when the value is not a string literal (likely reflected from request)"
|
|
11949
12076
|
}
|
|
11950
12077
|
];
|
|
12078
|
+
// ../circle-ir/dist/analysis/arg-type-resolver.js
|
|
12079
|
+
function findEnclosingType(callInMethod, types) {
|
|
12080
|
+
if (!callInMethod)
|
|
12081
|
+
return null;
|
|
12082
|
+
for (const t of types) {
|
|
12083
|
+
for (const m of t.methods) {
|
|
12084
|
+
if (m.name === callInMethod)
|
|
12085
|
+
return t;
|
|
12086
|
+
}
|
|
12087
|
+
}
|
|
12088
|
+
return null;
|
|
12089
|
+
}
|
|
12090
|
+
function resolveIdentifierType(name2, callInMethod, types) {
|
|
12091
|
+
if (!name2)
|
|
12092
|
+
return null;
|
|
12093
|
+
const enclosing = findEnclosingType(callInMethod, types);
|
|
12094
|
+
if (enclosing) {
|
|
12095
|
+
for (const m of enclosing.methods) {
|
|
12096
|
+
if (m.name !== callInMethod)
|
|
12097
|
+
continue;
|
|
12098
|
+
for (const p of m.parameters) {
|
|
12099
|
+
if (p.name === name2 && p.type)
|
|
12100
|
+
return p.type;
|
|
12101
|
+
}
|
|
12102
|
+
}
|
|
12103
|
+
for (const f of enclosing.fields) {
|
|
12104
|
+
if (f.name === name2 && f.type)
|
|
12105
|
+
return f.type;
|
|
12106
|
+
}
|
|
12107
|
+
return null;
|
|
12108
|
+
}
|
|
12109
|
+
for (const t of types) {
|
|
12110
|
+
for (const m of t.methods) {
|
|
12111
|
+
for (const p of m.parameters) {
|
|
12112
|
+
if (p.name === name2 && p.type)
|
|
12113
|
+
return p.type;
|
|
12114
|
+
}
|
|
12115
|
+
}
|
|
12116
|
+
for (const f of t.fields) {
|
|
12117
|
+
if (f.name === name2 && f.type)
|
|
12118
|
+
return f.type;
|
|
12119
|
+
}
|
|
12120
|
+
}
|
|
12121
|
+
return null;
|
|
12122
|
+
}
|
|
12123
|
+
function resolveCallReturnType(calleeName, callInMethod, types) {
|
|
12124
|
+
if (!calleeName)
|
|
12125
|
+
return null;
|
|
12126
|
+
const enclosing = findEnclosingType(callInMethod, types);
|
|
12127
|
+
if (enclosing) {
|
|
12128
|
+
for (const m of enclosing.methods) {
|
|
12129
|
+
if (m.name === calleeName && m.return_type)
|
|
12130
|
+
return m.return_type;
|
|
12131
|
+
}
|
|
12132
|
+
}
|
|
12133
|
+
for (const t of types) {
|
|
12134
|
+
for (const m of t.methods) {
|
|
12135
|
+
if (m.name === calleeName && m.return_type)
|
|
12136
|
+
return m.return_type;
|
|
12137
|
+
}
|
|
12138
|
+
}
|
|
12139
|
+
return null;
|
|
12140
|
+
}
|
|
12141
|
+
function isBoundedClassType(rawType) {
|
|
12142
|
+
if (!rawType)
|
|
12143
|
+
return false;
|
|
12144
|
+
const stripped = rawType.trim().replace(/^(?:java\.lang\.)+/, "");
|
|
12145
|
+
return /^Class(?:\s*<[\s\S]*>)?$/.test(stripped);
|
|
12146
|
+
}
|
|
12147
|
+
function isArgvContainerType(rawType) {
|
|
12148
|
+
if (!rawType)
|
|
12149
|
+
return false;
|
|
12150
|
+
const s = rawType.trim().replace(/^(?:java\.util\.|java\.lang\.)+/, "");
|
|
12151
|
+
if (/^String\s*(?:\[\s*\]|\.\.\.)$/.test(s))
|
|
12152
|
+
return true;
|
|
12153
|
+
return /^(?:List|ArrayList|LinkedList|Collection|Iterable|Deque|Queue)\s*<\s*(?:String|CharSequence|java\.lang\.String)\b/.test(s);
|
|
12154
|
+
}
|
|
12155
|
+
|
|
11951
12156
|
// ../circle-ir/dist/analysis/taint-matcher.js
|
|
11952
12157
|
var PYTHON_TAINTED_PATTERNS = [
|
|
11953
12158
|
{ pattern: /\brequest\.args\b/, sourceType: "http_param" },
|
|
@@ -11971,7 +12176,7 @@ function analyzeTaint(calls, types, config = getDefaultConfig(), typeHierarchy,
|
|
|
11971
12176
|
const sources = findSources(calls, types, config.sources, sourceLines, language);
|
|
11972
12177
|
let sinkPatterns = expandPromisifyAliases(config.sinks, sourceLines, language);
|
|
11973
12178
|
sinkPatterns = expandIndirectEvalAliases(sinkPatterns, sourceLines, language);
|
|
11974
|
-
const sinks = findSinks(calls, sinkPatterns, typeHierarchy, language, sourceLines);
|
|
12179
|
+
const sinks = findSinks(calls, sinkPatterns, typeHierarchy, language, sourceLines, types);
|
|
11975
12180
|
const sanitizers = findSanitizers(calls, types, config.sanitizers, sourceLines);
|
|
11976
12181
|
return { sources, sinks, sanitizers };
|
|
11977
12182
|
}
|
|
@@ -12088,11 +12293,9 @@ function attachSourceLineCode(sources, sinks, code) {
|
|
|
12088
12293
|
}
|
|
12089
12294
|
function findSources(calls, types, patterns, sourceLines, language) {
|
|
12090
12295
|
const sources = [];
|
|
12296
|
+
const patternsForLanguage = language === undefined ? patterns : patterns.filter((p) => !p.languages || p.languages.length === 0 || p.languages.includes(language));
|
|
12091
12297
|
for (const call of calls) {
|
|
12092
|
-
for (const pattern of
|
|
12093
|
-
if (pattern.languages && pattern.languages.length > 0 && language !== undefined && !pattern.languages.includes(language)) {
|
|
12094
|
-
continue;
|
|
12095
|
-
}
|
|
12298
|
+
for (const pattern of patternsForLanguage) {
|
|
12096
12299
|
if (matchesSourcePattern(call, pattern)) {
|
|
12097
12300
|
sources.push({
|
|
12098
12301
|
type: pattern.type,
|
|
@@ -12108,11 +12311,8 @@ function findSources(calls, types, patterns, sourceLines, language) {
|
|
|
12108
12311
|
for (const type of types) {
|
|
12109
12312
|
for (const method of type.methods) {
|
|
12110
12313
|
for (const param of method.parameters) {
|
|
12111
|
-
for (const pattern of
|
|
12314
|
+
for (const pattern of patternsForLanguage) {
|
|
12112
12315
|
if (pattern.annotation && pattern.param_tainted) {
|
|
12113
|
-
if (pattern.languages && pattern.languages.length > 0 && language !== undefined && !pattern.languages.includes(language)) {
|
|
12114
|
-
continue;
|
|
12115
|
-
}
|
|
12116
12316
|
if (matchesAnnotation(param.annotations, pattern.annotation)) {
|
|
12117
12317
|
const paramLine = param.line ?? method.start_line;
|
|
12118
12318
|
sources.push({
|
|
@@ -12131,12 +12331,9 @@ function findSources(calls, types, patterns, sourceLines, language) {
|
|
|
12131
12331
|
}
|
|
12132
12332
|
for (const type of types) {
|
|
12133
12333
|
for (const method of type.methods) {
|
|
12134
|
-
for (const pattern of
|
|
12334
|
+
for (const pattern of patternsForLanguage) {
|
|
12135
12335
|
if (!pattern.method_annotation)
|
|
12136
12336
|
continue;
|
|
12137
|
-
if (pattern.languages && pattern.languages.length > 0 && language !== undefined && !pattern.languages.includes(language)) {
|
|
12138
|
-
continue;
|
|
12139
|
-
}
|
|
12140
12337
|
if (!matchesAnnotation(method.annotations, pattern.method_annotation))
|
|
12141
12338
|
continue;
|
|
12142
12339
|
for (const param of method.parameters) {
|
|
@@ -12587,7 +12784,7 @@ function isSafeRustCommandCall(call, pattern, language) {
|
|
|
12587
12784
|
return false;
|
|
12588
12785
|
}
|
|
12589
12786
|
var CLASS_LITERAL_RE = /^(?:[A-Za-z_][\w]*\.)*[A-Z][\w]*(?:\[\])*\.class$/;
|
|
12590
|
-
function argIsClassLiteral(call, position) {
|
|
12787
|
+
function argIsClassLiteral(call, position, types) {
|
|
12591
12788
|
const arg = call.arguments.find((a) => a.position === position);
|
|
12592
12789
|
if (!arg)
|
|
12593
12790
|
return false;
|
|
@@ -12596,7 +12793,28 @@ function argIsClassLiteral(call, position) {
|
|
|
12596
12793
|
return false;
|
|
12597
12794
|
if (CLASS_LITERAL_RE.test(expr))
|
|
12598
12795
|
return true;
|
|
12599
|
-
|
|
12796
|
+
if (TYPE_TOKEN_RE.test(expr))
|
|
12797
|
+
return true;
|
|
12798
|
+
if (!types || types.length === 0)
|
|
12799
|
+
return false;
|
|
12800
|
+
const argExpr = (arg.expression ?? "").trim();
|
|
12801
|
+
const varName = arg.variable ?? "";
|
|
12802
|
+
const isBareIdentifier = varName !== "" && argExpr === varName && !/[(.]/.test(argExpr);
|
|
12803
|
+
if (isBareIdentifier) {
|
|
12804
|
+
const t = resolveIdentifierType(varName, call.in_method, types);
|
|
12805
|
+
if (isBoundedClassType(t))
|
|
12806
|
+
return true;
|
|
12807
|
+
}
|
|
12808
|
+
const isCallExpr = varName !== "" && new RegExp(`^${escapeRe(varName)}\\s*\\(`).test(argExpr);
|
|
12809
|
+
if (isCallExpr) {
|
|
12810
|
+
const t = resolveCallReturnType(varName, call.in_method, types);
|
|
12811
|
+
if (isBoundedClassType(t))
|
|
12812
|
+
return true;
|
|
12813
|
+
}
|
|
12814
|
+
return false;
|
|
12815
|
+
}
|
|
12816
|
+
function escapeRe(s) {
|
|
12817
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
12600
12818
|
}
|
|
12601
12819
|
var TYPE_TOKEN_RE = /^new\s+(?:TypeReference|TypeToken)\s*<[\s\S]*>\s*\(\s*\)\s*\{\s*\}$/;
|
|
12602
12820
|
function argIsStringLiteral(call, position) {
|
|
@@ -12779,10 +12997,11 @@ function isSafeJinjaRenderCall(call, pattern, language, sourceLines) {
|
|
|
12779
12997
|
}
|
|
12780
12998
|
return false;
|
|
12781
12999
|
}
|
|
12782
|
-
function findSinks(calls, patterns, typeHierarchy, language, sourceLines) {
|
|
13000
|
+
function findSinks(calls, patterns, typeHierarchy, language, sourceLines, types) {
|
|
13001
|
+
const patternsForLanguage = language === undefined ? patterns : patterns.filter((p) => !p.languages || p.languages.length === 0 || p.languages.includes(language));
|
|
12783
13002
|
const sinkMap = new Map;
|
|
12784
13003
|
for (const call of calls) {
|
|
12785
|
-
for (const pattern of
|
|
13004
|
+
for (const pattern of patternsForLanguage) {
|
|
12786
13005
|
if (matchesSinkPattern(call, pattern, typeHierarchy, language)) {
|
|
12787
13006
|
if (isParameterizedQueryCall(call, pattern)) {
|
|
12788
13007
|
continue;
|
|
@@ -12799,7 +13018,7 @@ function findSinks(calls, patterns, typeHierarchy, language, sourceLines) {
|
|
|
12799
13018
|
if (isSafeJSChildProcessCall(call, pattern, language)) {
|
|
12800
13019
|
continue;
|
|
12801
13020
|
}
|
|
12802
|
-
if (pattern.safe_if_class_literal_at !== undefined && argIsClassLiteral(call, pattern.safe_if_class_literal_at)) {
|
|
13021
|
+
if (pattern.safe_if_class_literal_at !== undefined && argIsClassLiteral(call, pattern.safe_if_class_literal_at, types)) {
|
|
12803
13022
|
continue;
|
|
12804
13023
|
}
|
|
12805
13024
|
if (pattern.safe_if_string_literal_at !== undefined && argIsStringLiteral(call, pattern.safe_if_string_literal_at)) {
|
|
@@ -13184,7 +13403,21 @@ function matchesAnnotation(annotations, targetAnnotation) {
|
|
|
13184
13403
|
}
|
|
13185
13404
|
return false;
|
|
13186
13405
|
}
|
|
13406
|
+
var RECEIVER_MIGHT_BE_CLASS_CACHE = new Map;
|
|
13407
|
+
var RECEIVER_MIGHT_BE_CLASS_CACHE_CAP = 1e4;
|
|
13187
13408
|
function receiverMightBeClass(receiver, className) {
|
|
13409
|
+
const key = receiver + "\x00" + className;
|
|
13410
|
+
const cached = RECEIVER_MIGHT_BE_CLASS_CACHE.get(key);
|
|
13411
|
+
if (cached !== undefined)
|
|
13412
|
+
return cached;
|
|
13413
|
+
const result = receiverMightBeClassImpl(receiver, className);
|
|
13414
|
+
if (RECEIVER_MIGHT_BE_CLASS_CACHE.size >= RECEIVER_MIGHT_BE_CLASS_CACHE_CAP) {
|
|
13415
|
+
RECEIVER_MIGHT_BE_CLASS_CACHE.clear();
|
|
13416
|
+
}
|
|
13417
|
+
RECEIVER_MIGHT_BE_CLASS_CACHE.set(key, result);
|
|
13418
|
+
return result;
|
|
13419
|
+
}
|
|
13420
|
+
function receiverMightBeClassImpl(receiver, className) {
|
|
13188
13421
|
if (className.startsWith("*") && className.length > 1) {
|
|
13189
13422
|
const suffix = className.slice(1).toLowerCase();
|
|
13190
13423
|
let simpleReceiver = receiver;
|
|
@@ -16040,8 +16273,16 @@ class AnalysisPipeline {
|
|
|
16040
16273
|
}
|
|
16041
16274
|
}
|
|
16042
16275
|
// ../circle-ir/dist/analysis/dfg-walk.js
|
|
16276
|
+
var walkBackwardDefsMemo = new WeakMap;
|
|
16043
16277
|
function walkBackwardDefs(startDefId, chainsByToDef, defById, options = {}) {
|
|
16044
16278
|
const maxHops = options.maxHops ?? 32;
|
|
16279
|
+
let perFile = walkBackwardDefsMemo.get(chainsByToDef);
|
|
16280
|
+
if (perFile !== undefined) {
|
|
16281
|
+
const key = `${startDefId}|${maxHops}`;
|
|
16282
|
+
const hit = perFile.get(key);
|
|
16283
|
+
if (hit !== undefined)
|
|
16284
|
+
return hit;
|
|
16285
|
+
}
|
|
16045
16286
|
const visited = new Set;
|
|
16046
16287
|
const lines = new Set;
|
|
16047
16288
|
let hopCapReached = false;
|
|
@@ -16075,7 +16316,13 @@ function walkBackwardDefs(startDefId, chainsByToDef, defById, options = {}) {
|
|
|
16075
16316
|
queue.push(fromId);
|
|
16076
16317
|
}
|
|
16077
16318
|
}
|
|
16078
|
-
|
|
16319
|
+
const result = { visited, lines, hopCapReached };
|
|
16320
|
+
if (perFile === undefined) {
|
|
16321
|
+
perFile = new Map;
|
|
16322
|
+
walkBackwardDefsMemo.set(chainsByToDef, perFile);
|
|
16323
|
+
}
|
|
16324
|
+
perFile.set(`${startDefId}|${maxHops}`, result);
|
|
16325
|
+
return result;
|
|
16079
16326
|
}
|
|
16080
16327
|
|
|
16081
16328
|
// ../circle-ir/dist/analysis/sanitizer-index.js
|
|
@@ -16922,12 +17169,12 @@ class ConstantPropagator {
|
|
|
16922
17169
|
this.constructorParamPositions.clear();
|
|
16923
17170
|
this.safePatternFieldsCache = null;
|
|
16924
17171
|
this.isTaintedExpressionCache = null;
|
|
16925
|
-
this.
|
|
17172
|
+
const prePassMethods = this.collectClassFieldsAndMethods(tree.rootNode);
|
|
16926
17173
|
for (const methodName of sanitizerMethods) {
|
|
16927
17174
|
this.methodReturnsSanitized.add(methodName);
|
|
16928
17175
|
}
|
|
16929
17176
|
this.evaluator = new ExpressionEvaluator(this.source, (name2) => this.lookupSymbol(name2));
|
|
16930
|
-
this.analyzeMethodReturns(
|
|
17177
|
+
this.analyzeMethodReturns(prePassMethods);
|
|
16931
17178
|
this.seedPythonModuleConstants(tree.rootNode);
|
|
16932
17179
|
this.visit(tree.rootNode);
|
|
16933
17180
|
this.refineTaintFromConstants();
|
|
@@ -16979,8 +17226,7 @@ class ConstantPropagator {
|
|
|
16979
17226
|
isLineReachable(line) {
|
|
16980
17227
|
return !this.unreachableLines.has(line);
|
|
16981
17228
|
}
|
|
16982
|
-
analyzeMethodReturns(
|
|
16983
|
-
const methods = this.findAllMethods(root);
|
|
17229
|
+
analyzeMethodReturns(methods) {
|
|
16984
17230
|
for (const method of methods) {
|
|
16985
17231
|
const methodName = this.getMethodName(method);
|
|
16986
17232
|
if (!methodName)
|
|
@@ -17245,12 +17491,16 @@ class ConstantPropagator {
|
|
|
17245
17491
|
};
|
|
17246
17492
|
return findAssignments(methodBody);
|
|
17247
17493
|
}
|
|
17248
|
-
|
|
17494
|
+
collectClassFieldsAndMethods(root) {
|
|
17495
|
+
const methods = [];
|
|
17249
17496
|
const stack = [root];
|
|
17250
17497
|
while (stack.length > 0) {
|
|
17251
17498
|
const n = stack.pop();
|
|
17252
17499
|
if (!n)
|
|
17253
17500
|
continue;
|
|
17501
|
+
if (n.type === "method_declaration" || n.type === "function_declaration") {
|
|
17502
|
+
methods.push(n);
|
|
17503
|
+
}
|
|
17254
17504
|
if (n.type === "class_body") {
|
|
17255
17505
|
for (const child of n.children) {
|
|
17256
17506
|
if (child.type === "field_declaration") {
|
|
@@ -17264,14 +17514,17 @@ class ConstantPropagator {
|
|
|
17264
17514
|
}
|
|
17265
17515
|
}
|
|
17266
17516
|
}
|
|
17267
|
-
|
|
17517
|
+
if (child)
|
|
17518
|
+
stack.push(child);
|
|
17268
17519
|
}
|
|
17269
17520
|
continue;
|
|
17270
17521
|
}
|
|
17271
17522
|
for (const child of n.children) {
|
|
17272
|
-
|
|
17523
|
+
if (child)
|
|
17524
|
+
stack.push(child);
|
|
17273
17525
|
}
|
|
17274
17526
|
}
|
|
17527
|
+
return methods;
|
|
17275
17528
|
}
|
|
17276
17529
|
fieldDeclHasPrimitiveLiteralValue(node) {
|
|
17277
17530
|
const primitive = new Set([
|
|
@@ -17408,23 +17661,6 @@ class ConstantPropagator {
|
|
|
17408
17661
|
this.symbols.set(name2, value);
|
|
17409
17662
|
}
|
|
17410
17663
|
}
|
|
17411
|
-
findAllMethods(node) {
|
|
17412
|
-
const methods = [];
|
|
17413
|
-
const stack = [node];
|
|
17414
|
-
while (stack.length > 0) {
|
|
17415
|
-
const n = stack.pop();
|
|
17416
|
-
if (!n)
|
|
17417
|
-
continue;
|
|
17418
|
-
if (n.type === "method_declaration" || n.type === "function_declaration") {
|
|
17419
|
-
methods.push(n);
|
|
17420
|
-
}
|
|
17421
|
-
for (const child of n.children) {
|
|
17422
|
-
if (child)
|
|
17423
|
-
stack.push(child);
|
|
17424
|
-
}
|
|
17425
|
-
}
|
|
17426
|
-
return methods;
|
|
17427
|
-
}
|
|
17428
17664
|
getMethodName(method) {
|
|
17429
17665
|
const nameNode = method.childForFieldName("name");
|
|
17430
17666
|
if (nameNode) {
|
|
@@ -30796,6 +31032,9 @@ class MyBatisAnnotationSqlSinkPass {
|
|
|
30796
31032
|
}
|
|
30797
31033
|
|
|
30798
31034
|
// ../circle-ir/dist/analysis/passes/sink-filter-pass.js
|
|
31035
|
+
function escapeReSf(s) {
|
|
31036
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
31037
|
+
}
|
|
30799
31038
|
var JS_XSS_SANITIZERS = [
|
|
30800
31039
|
/\bDOMPurify\.sanitize\s*\(/,
|
|
30801
31040
|
/\bsanitizeHtml\s*\(/,
|
|
@@ -30845,6 +31084,12 @@ var DATA_PARSER_TYPES = new Set([
|
|
|
30845
31084
|
"OptionParser",
|
|
30846
31085
|
"CmdLineParser"
|
|
30847
31086
|
]);
|
|
31087
|
+
var JAVA_EVAL_PARSER_DENYLIST = new Set([
|
|
31088
|
+
"GroovyShell",
|
|
31089
|
+
"GroovyClassLoader",
|
|
31090
|
+
"ScriptEngine",
|
|
31091
|
+
"CronParser"
|
|
31092
|
+
]);
|
|
30848
31093
|
var COMPILED_TEMPLATE_TYPES = new Set([
|
|
30849
31094
|
"Template",
|
|
30850
31095
|
"JetTemplate",
|
|
@@ -31314,8 +31559,13 @@ class SinkFilterPass {
|
|
|
31314
31559
|
const method = sink.method ?? receiverMatch?.[2];
|
|
31315
31560
|
if (method === "parse" && receiver) {
|
|
31316
31561
|
const recvType = resolveJavaReceiverType(receiver, sink.line, sourceLines);
|
|
31317
|
-
if (recvType
|
|
31318
|
-
|
|
31562
|
+
if (recvType) {
|
|
31563
|
+
if (DATA_PARSER_TYPES.has(recvType))
|
|
31564
|
+
return false;
|
|
31565
|
+
if (recvType.endsWith("Parser") && !JAVA_EVAL_PARSER_DENYLIST.has(recvType)) {
|
|
31566
|
+
return false;
|
|
31567
|
+
}
|
|
31568
|
+
}
|
|
31319
31569
|
}
|
|
31320
31570
|
if ((method === "render" || method === "process" || method === "merge" || method === "renderTo") && receiver) {
|
|
31321
31571
|
const recvType = resolveJavaReceiverType(receiver, sink.line, sourceLines);
|
|
@@ -31425,6 +31675,8 @@ class SinkFilterPass {
|
|
|
31425
31675
|
if (language === "java") {
|
|
31426
31676
|
const sourceLines = ctx.code.split(`
|
|
31427
31677
|
`);
|
|
31678
|
+
const irCalls = ctx.graph.ir.calls;
|
|
31679
|
+
const irTypes = ctx.graph.ir.types;
|
|
31428
31680
|
filtered = filtered.filter((sink) => {
|
|
31429
31681
|
if (sink.type !== "command_injection")
|
|
31430
31682
|
return true;
|
|
@@ -31435,6 +31687,24 @@ class SinkFilterPass {
|
|
|
31435
31687
|
return true;
|
|
31436
31688
|
if (PROCESS_BUILDER_ARGV_FORM_RE.test(sinkLineText))
|
|
31437
31689
|
return false;
|
|
31690
|
+
const ctorCall = irCalls.find((c) => c.method_name === "ProcessBuilder" && c.location.line === sink.line && (c.receiver === null || c.receiver === undefined));
|
|
31691
|
+
if (!ctorCall || ctorCall.arguments.length === 0)
|
|
31692
|
+
return true;
|
|
31693
|
+
const arg0 = ctorCall.arguments[0];
|
|
31694
|
+
if (!arg0)
|
|
31695
|
+
return true;
|
|
31696
|
+
const argExpr = (arg0.expression ?? "").trim();
|
|
31697
|
+
const varName = arg0.variable ?? "";
|
|
31698
|
+
if (varName !== "" && argExpr === varName && !/[(.]/.test(argExpr)) {
|
|
31699
|
+
const t = resolveIdentifierType(varName, ctorCall.in_method, irTypes);
|
|
31700
|
+
if (isArgvContainerType(t))
|
|
31701
|
+
return false;
|
|
31702
|
+
}
|
|
31703
|
+
if (varName !== "" && new RegExp(`^${escapeReSf(varName)}\\s*\\(`).test(argExpr)) {
|
|
31704
|
+
const t = resolveCallReturnType(varName, ctorCall.in_method, irTypes);
|
|
31705
|
+
if (isArgvContainerType(t))
|
|
31706
|
+
return false;
|
|
31707
|
+
}
|
|
31438
31708
|
return true;
|
|
31439
31709
|
});
|
|
31440
31710
|
}
|
|
@@ -44796,7 +45066,7 @@ var colors = {
|
|
|
44796
45066
|
};
|
|
44797
45067
|
|
|
44798
45068
|
// src/version.ts
|
|
44799
|
-
var version = "3.
|
|
45069
|
+
var version = "3.177.0";
|
|
44800
45070
|
|
|
44801
45071
|
// src/formatters.ts
|
|
44802
45072
|
var LIBRARY_API_SURFACE_TAG2 = "library-api-surface:caller-responsibility";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cognium-dev",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.177.0",
|
|
4
4
|
"description": "Static Application Security Testing CLI for detecting security vulnerabilities via taint tracking",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
68
|
"@cognium/project-profile-detect": "^1.1.0",
|
|
69
|
-
"circle-ir": "^3.
|
|
69
|
+
"circle-ir": "^3.177.0"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@types/node": "^25.5.0",
|