cognium-dev 3.168.0 → 3.173.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 +225 -95
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -6861,33 +6861,33 @@ function detectLanguage2(tree) {
|
|
|
6861
6861
|
return "python";
|
|
6862
6862
|
return jsScore > javaScore ? "javascript" : "java";
|
|
6863
6863
|
}
|
|
6864
|
-
function extractImports(tree, language) {
|
|
6864
|
+
function extractImports(tree, language, cache) {
|
|
6865
6865
|
const effectiveLanguage = language ?? detectLanguage2(tree);
|
|
6866
6866
|
const isJavaScript = effectiveLanguage === "javascript" || effectiveLanguage === "typescript" || effectiveLanguage === "tsx";
|
|
6867
6867
|
const isPython = effectiveLanguage === "python";
|
|
6868
6868
|
const isRust = effectiveLanguage === "rust";
|
|
6869
6869
|
if (effectiveLanguage === "go") {
|
|
6870
|
-
return extractGoImports(tree);
|
|
6870
|
+
return extractGoImports(tree, cache);
|
|
6871
6871
|
}
|
|
6872
6872
|
if (isRust) {
|
|
6873
|
-
return extractRustImports(tree);
|
|
6873
|
+
return extractRustImports(tree, cache);
|
|
6874
6874
|
}
|
|
6875
6875
|
if (isPython) {
|
|
6876
|
-
return extractPythonImports(tree);
|
|
6876
|
+
return extractPythonImports(tree, cache);
|
|
6877
6877
|
}
|
|
6878
6878
|
if (isJavaScript) {
|
|
6879
|
-
return extractJavaScriptImports(tree);
|
|
6879
|
+
return extractJavaScriptImports(tree, cache);
|
|
6880
6880
|
}
|
|
6881
|
-
return extractJavaImports(tree);
|
|
6881
|
+
return extractJavaImports(tree, cache);
|
|
6882
6882
|
}
|
|
6883
|
-
function extractJavaScriptImports(tree) {
|
|
6883
|
+
function extractJavaScriptImports(tree, cache) {
|
|
6884
6884
|
const imports = [];
|
|
6885
|
-
const importStatements =
|
|
6885
|
+
const importStatements = getNodesFromCache(tree.rootNode, "import_statement", cache);
|
|
6886
6886
|
for (const importStmt of importStatements) {
|
|
6887
6887
|
const importInfos = extractJSImportInfo(importStmt);
|
|
6888
6888
|
imports.push(...importInfos);
|
|
6889
6889
|
}
|
|
6890
|
-
const exportStatements =
|
|
6890
|
+
const exportStatements = getNodesFromCache(tree.rootNode, "export_statement", cache);
|
|
6891
6891
|
for (const exportStmt of exportStatements) {
|
|
6892
6892
|
const sourceNode = exportStmt.childForFieldName("source");
|
|
6893
6893
|
if (!sourceNode)
|
|
@@ -6903,13 +6903,13 @@ function extractJavaScriptImports(tree) {
|
|
|
6903
6903
|
line_number: exportStmt.startPosition.row + 1
|
|
6904
6904
|
});
|
|
6905
6905
|
}
|
|
6906
|
-
const requireCalls = findRequireCalls(tree);
|
|
6906
|
+
const requireCalls = findRequireCalls(tree, cache);
|
|
6907
6907
|
imports.push(...requireCalls);
|
|
6908
6908
|
return imports;
|
|
6909
6909
|
}
|
|
6910
|
-
function extractJavaImports(tree) {
|
|
6910
|
+
function extractJavaImports(tree, cache) {
|
|
6911
6911
|
const imports = [];
|
|
6912
|
-
const importDecls =
|
|
6912
|
+
const importDecls = getNodesFromCache(tree.rootNode, "import_declaration", cache);
|
|
6913
6913
|
for (const importDecl of importDecls) {
|
|
6914
6914
|
const importInfo = extractJavaImportInfo(importDecl);
|
|
6915
6915
|
if (importInfo) {
|
|
@@ -7061,9 +7061,9 @@ function extractJSImportInfo(node) {
|
|
|
7061
7061
|
}
|
|
7062
7062
|
return imports;
|
|
7063
7063
|
}
|
|
7064
|
-
function findRequireCalls(tree) {
|
|
7064
|
+
function findRequireCalls(tree, cache) {
|
|
7065
7065
|
const imports = [];
|
|
7066
|
-
const callExpressions =
|
|
7066
|
+
const callExpressions = getNodesFromCache(tree.rootNode, "call_expression", cache);
|
|
7067
7067
|
for (const call of callExpressions) {
|
|
7068
7068
|
const funcNode = call.childForFieldName("function");
|
|
7069
7069
|
if (!funcNode || getNodeText(funcNode) !== "require")
|
|
@@ -7182,14 +7182,14 @@ function parseImportPath(fullPath, isWildcard) {
|
|
|
7182
7182
|
fromPackage: fullPath.substring(0, lastDot)
|
|
7183
7183
|
};
|
|
7184
7184
|
}
|
|
7185
|
-
function extractPythonImports(tree) {
|
|
7185
|
+
function extractPythonImports(tree, cache) {
|
|
7186
7186
|
const imports = [];
|
|
7187
|
-
const importStatements =
|
|
7187
|
+
const importStatements = getNodesFromCache(tree.rootNode, "import_statement", cache);
|
|
7188
7188
|
for (const stmt of importStatements) {
|
|
7189
7189
|
const importInfos = extractPythonImportStatement(stmt);
|
|
7190
7190
|
imports.push(...importInfos);
|
|
7191
7191
|
}
|
|
7192
|
-
const importFromStatements =
|
|
7192
|
+
const importFromStatements = getNodesFromCache(tree.rootNode, "import_from_statement", cache);
|
|
7193
7193
|
for (const stmt of importFromStatements) {
|
|
7194
7194
|
const importInfos = extractPythonFromImportStatement(stmt);
|
|
7195
7195
|
imports.push(...importInfos);
|
|
@@ -7285,9 +7285,9 @@ function extractPythonFromImportStatement(node) {
|
|
|
7285
7285
|
}
|
|
7286
7286
|
return imports;
|
|
7287
7287
|
}
|
|
7288
|
-
function extractRustImports(tree) {
|
|
7288
|
+
function extractRustImports(tree, cache) {
|
|
7289
7289
|
const imports = [];
|
|
7290
|
-
const useDecls =
|
|
7290
|
+
const useDecls = getNodesFromCache(tree.rootNode, "use_declaration", cache);
|
|
7291
7291
|
for (const useDecl of useDecls) {
|
|
7292
7292
|
const useImports = extractRustUseDecl(useDecl);
|
|
7293
7293
|
imports.push(...useImports);
|
|
@@ -7433,9 +7433,9 @@ function extractRustScopedUseList(node, lineNumber) {
|
|
|
7433
7433
|
}
|
|
7434
7434
|
return imports;
|
|
7435
7435
|
}
|
|
7436
|
-
function extractGoImports(tree) {
|
|
7436
|
+
function extractGoImports(tree, cache) {
|
|
7437
7437
|
const imports = [];
|
|
7438
|
-
const importDecls =
|
|
7438
|
+
const importDecls = getNodesFromCache(tree.rootNode, "import_declaration", cache);
|
|
7439
7439
|
for (const decl of importDecls) {
|
|
7440
7440
|
const singleSpec = findGoChildByType(decl, "import_spec");
|
|
7441
7441
|
if (singleSpec) {
|
|
@@ -7576,7 +7576,7 @@ function detectLanguage3(tree) {
|
|
|
7576
7576
|
}
|
|
7577
7577
|
return jsScore > javaScore ? "javascript" : "java";
|
|
7578
7578
|
}
|
|
7579
|
-
function buildCFG(tree, language) {
|
|
7579
|
+
function buildCFG(tree, language, cache) {
|
|
7580
7580
|
const effectiveLanguage = language ?? detectLanguage3(tree);
|
|
7581
7581
|
const isJavaScript = effectiveLanguage === "javascript" || effectiveLanguage === "typescript" || effectiveLanguage === "tsx";
|
|
7582
7582
|
const allBlocks = [];
|
|
@@ -7590,11 +7590,11 @@ function buildCFG(tree, language) {
|
|
|
7590
7590
|
}
|
|
7591
7591
|
if (isJavaScript) {
|
|
7592
7592
|
const functions = [
|
|
7593
|
-
...
|
|
7594
|
-
...
|
|
7595
|
-
...
|
|
7596
|
-
...
|
|
7597
|
-
...
|
|
7593
|
+
...getNodesFromCache(tree.rootNode, "function_declaration", cache),
|
|
7594
|
+
...getNodesFromCache(tree.rootNode, "arrow_function", cache),
|
|
7595
|
+
...getNodesFromCache(tree.rootNode, "method_definition", cache),
|
|
7596
|
+
...getNodesFromCache(tree.rootNode, "function", cache),
|
|
7597
|
+
...getNodesFromCache(tree.rootNode, "function_expression", cache)
|
|
7598
7598
|
];
|
|
7599
7599
|
for (const func2 of functions) {
|
|
7600
7600
|
const body2 = func2.childForFieldName("body");
|
|
@@ -7617,8 +7617,8 @@ function buildCFG(tree, language) {
|
|
|
7617
7617
|
}
|
|
7618
7618
|
} else {
|
|
7619
7619
|
const methods = [
|
|
7620
|
-
...
|
|
7621
|
-
...
|
|
7620
|
+
...getNodesFromCache(tree.rootNode, "method_declaration", cache),
|
|
7621
|
+
...getNodesFromCache(tree.rootNode, "constructor_declaration", cache)
|
|
7622
7622
|
];
|
|
7623
7623
|
for (const method of methods) {
|
|
7624
7624
|
const body2 = method.childForFieldName("body");
|
|
@@ -10507,7 +10507,51 @@ var DEFAULT_SOURCES = [
|
|
|
10507
10507
|
{ method: "recv", class: "TcpStream", type: "network_input", severity: "high", return_tainted: true },
|
|
10508
10508
|
{ method: "read", class: "TcpStream", type: "network_input", severity: "high", return_tainted: true },
|
|
10509
10509
|
{ method: "read_to_end", class: "TcpStream", type: "network_input", severity: "high", return_tainted: true },
|
|
10510
|
-
{ method: "read_to_string", class: "TcpStream", type: "network_input", severity: "high", return_tainted: true }
|
|
10510
|
+
{ method: "read_to_string", class: "TcpStream", type: "network_input", severity: "high", return_tainted: true },
|
|
10511
|
+
{ method_annotation: "Query", type: "http_body", severity: "high", languages: ["javascript", "typescript"] },
|
|
10512
|
+
{ method_annotation: "Mutation", type: "http_body", severity: "high", languages: ["javascript", "typescript"] },
|
|
10513
|
+
{ method_annotation: "Subscription", type: "http_body", severity: "high", languages: ["javascript", "typescript"] },
|
|
10514
|
+
{ method_annotation: "FieldResolver", type: "http_body", severity: "high", languages: ["javascript", "typescript"] },
|
|
10515
|
+
{ method_annotation: "ResolveField", type: "http_body", severity: "high", languages: ["javascript", "typescript"] },
|
|
10516
|
+
{ annotation: "Arg", type: "http_param", severity: "high", param_tainted: true, languages: ["javascript", "typescript"] },
|
|
10517
|
+
{ annotation: "Args", type: "http_param", severity: "high", param_tainted: true, languages: ["javascript", "typescript"] },
|
|
10518
|
+
{ method_annotation: "strawberry.field", type: "http_body", severity: "high", languages: ["python"] },
|
|
10519
|
+
{ method_annotation: "strawberry.mutation", type: "http_body", severity: "high", languages: ["python"] },
|
|
10520
|
+
{ method_annotation: "strawberry.subscription", type: "http_body", severity: "high", languages: ["python"] },
|
|
10521
|
+
{ method_annotation: "DgsQuery", type: "http_body", severity: "high", languages: ["java"] },
|
|
10522
|
+
{ method_annotation: "DgsMutation", type: "http_body", severity: "high", languages: ["java"] },
|
|
10523
|
+
{ method_annotation: "DgsSubscription", type: "http_body", severity: "high", languages: ["java"] },
|
|
10524
|
+
{ method_annotation: "DgsData", type: "http_body", severity: "high", languages: ["java"] },
|
|
10525
|
+
{ method_annotation: "GraphQLQuery", type: "http_body", severity: "high", languages: ["java"] },
|
|
10526
|
+
{ method_annotation: "GraphQLMutation", type: "http_body", severity: "high", languages: ["java"] },
|
|
10527
|
+
{ annotation: "InputArgument", type: "http_param", severity: "high", param_tainted: true, languages: ["java"] },
|
|
10528
|
+
{ annotation: "GraphQLArgument", type: "http_param", severity: "high", param_tainted: true, languages: ["java"] },
|
|
10529
|
+
{ method: "invocation_metadata", type: "http_header", severity: "high", return_tainted: true, languages: ["python"] },
|
|
10530
|
+
{ method: "get", class: "Metadata", type: "http_header", severity: "high", return_tainted: true, languages: ["javascript", "typescript"] },
|
|
10531
|
+
{ method: "getMap", class: "Metadata", type: "http_header", severity: "high", return_tainted: true, languages: ["javascript", "typescript"] },
|
|
10532
|
+
{ method: "FromIncomingContext", class: "metadata", type: "http_header", severity: "high", return_tainted: true, languages: ["go"] },
|
|
10533
|
+
{ method: "get", class: "Metadata", type: "http_header", severity: "high", return_tainted: true, languages: ["java"] },
|
|
10534
|
+
{ method: "get", class: "Redis", type: "db_input", severity: "medium", return_tainted: true, languages: ["python"] },
|
|
10535
|
+
{ method: "hget", class: "Redis", type: "db_input", severity: "medium", return_tainted: true, languages: ["python"] },
|
|
10536
|
+
{ method: "mget", class: "Redis", type: "db_input", severity: "medium", return_tainted: true, languages: ["python"] },
|
|
10537
|
+
{ method: "lrange", class: "Redis", type: "db_input", severity: "medium", return_tainted: true, languages: ["python"] },
|
|
10538
|
+
{ method: "get", class: "cache", type: "db_input", severity: "medium", return_tainted: true, languages: ["python"] },
|
|
10539
|
+
{ method: "get_many", class: "cache", type: "db_input", severity: "medium", return_tainted: true, languages: ["python"] },
|
|
10540
|
+
{ method: "get", class: "Redis", type: "db_input", severity: "medium", return_tainted: true, languages: ["javascript", "typescript"] },
|
|
10541
|
+
{ method: "hget", class: "Redis", type: "db_input", severity: "medium", return_tainted: true, languages: ["javascript", "typescript"] },
|
|
10542
|
+
{ method: "mget", class: "Redis", type: "db_input", severity: "medium", return_tainted: true, languages: ["javascript", "typescript"] },
|
|
10543
|
+
{ method: "get", class: "Jedis", type: "db_input", severity: "medium", return_tainted: true, languages: ["java"] },
|
|
10544
|
+
{ method: "hget", class: "Jedis", type: "db_input", severity: "medium", return_tainted: true, languages: ["java"] },
|
|
10545
|
+
{ method: "mget", class: "Jedis", type: "db_input", severity: "medium", return_tainted: true, languages: ["java"] },
|
|
10546
|
+
{ method: "decode", class: "jwt", type: "http_header", severity: "high", return_tainted: true, languages: ["python"] },
|
|
10547
|
+
{ method: "get_unverified_claims", class: "jwt", type: "http_header", severity: "high", return_tainted: true, languages: ["python"] },
|
|
10548
|
+
{ method: "get_unverified_header", class: "jwt", type: "http_header", severity: "high", return_tainted: true, languages: ["python"] },
|
|
10549
|
+
{ method: "decode", class: "jwt", type: "http_header", severity: "high", return_tainted: true, languages: ["javascript", "typescript"] },
|
|
10550
|
+
{ method: "decode", class: "jsonwebtoken", type: "http_header", severity: "high", return_tainted: true, languages: ["javascript", "typescript"] },
|
|
10551
|
+
{ method: "decodeJwt", class: "jose", type: "http_header", severity: "high", return_tainted: true, languages: ["javascript", "typescript"] },
|
|
10552
|
+
{ method: "decodeProtectedHeader", class: "jose", type: "http_header", severity: "high", return_tainted: true, languages: ["javascript", "typescript"] },
|
|
10553
|
+
{ method: "decode", class: "JWT", type: "http_header", severity: "high", return_tainted: true, languages: ["java"] },
|
|
10554
|
+
{ method: "ParseUnverified", class: "jwt", type: "http_header", severity: "high", return_tainted: true, languages: ["go"] }
|
|
10511
10555
|
];
|
|
10512
10556
|
var DEFAULT_SINKS = [
|
|
10513
10557
|
{ method: "executeQuery", class: "Statement", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0] },
|
|
@@ -11995,6 +12039,9 @@ function findSources(calls, types, patterns, sourceLines, language) {
|
|
|
11995
12039
|
for (const param of method.parameters) {
|
|
11996
12040
|
for (const pattern of patterns) {
|
|
11997
12041
|
if (pattern.annotation && pattern.param_tainted) {
|
|
12042
|
+
if (pattern.languages && pattern.languages.length > 0 && language !== undefined && !pattern.languages.includes(language)) {
|
|
12043
|
+
continue;
|
|
12044
|
+
}
|
|
11998
12045
|
if (matchesAnnotation(param.annotations, pattern.annotation)) {
|
|
11999
12046
|
const paramLine = param.line ?? method.start_line;
|
|
12000
12047
|
sources.push({
|
|
@@ -12016,6 +12063,9 @@ function findSources(calls, types, patterns, sourceLines, language) {
|
|
|
12016
12063
|
for (const pattern of patterns) {
|
|
12017
12064
|
if (!pattern.method_annotation)
|
|
12018
12065
|
continue;
|
|
12066
|
+
if (pattern.languages && pattern.languages.length > 0 && language !== undefined && !pattern.languages.includes(language)) {
|
|
12067
|
+
continue;
|
|
12068
|
+
}
|
|
12019
12069
|
if (!matchesAnnotation(method.annotations, pattern.method_annotation))
|
|
12020
12070
|
continue;
|
|
12021
12071
|
for (const param of method.parameters) {
|
|
@@ -12269,7 +12319,7 @@ function isParameterizedQueryCall(call, pattern) {
|
|
|
12269
12319
|
const secondArg = call.arguments.find((a) => a.position === 1);
|
|
12270
12320
|
if (secondArg?.expression) {
|
|
12271
12321
|
const expr = secondArg.expression.trim();
|
|
12272
|
-
if (expr.startsWith("[")) {
|
|
12322
|
+
if (expr.startsWith("[") && !/^\[\s*\]$/.test(expr)) {
|
|
12273
12323
|
return true;
|
|
12274
12324
|
}
|
|
12275
12325
|
}
|
|
@@ -12757,52 +12807,75 @@ function matchesSourcePattern(call, pattern) {
|
|
|
12757
12807
|
}
|
|
12758
12808
|
return false;
|
|
12759
12809
|
}
|
|
12810
|
+
var JS_SOURCE_PATTERN_CACHE = new WeakMap;
|
|
12811
|
+
var JS_FALLBACK_COMPILED = (() => {
|
|
12812
|
+
const bases = [
|
|
12813
|
+
{ base: "req\\.params", sourceType: "http_param" },
|
|
12814
|
+
{ base: "req\\.query", sourceType: "http_param" },
|
|
12815
|
+
{ base: "req\\.body", sourceType: "http_body" },
|
|
12816
|
+
{ base: "req\\.headers", sourceType: "http_header" },
|
|
12817
|
+
{ base: "req\\.cookies", sourceType: "http_cookie" },
|
|
12818
|
+
{ base: "req\\.url", sourceType: "http_path" },
|
|
12819
|
+
{ base: "req\\.path", sourceType: "http_path" },
|
|
12820
|
+
{ base: "req\\.originalUrl", sourceType: "http_path" },
|
|
12821
|
+
{ base: "req\\.file", sourceType: "file_input" },
|
|
12822
|
+
{ base: "req\\.files", sourceType: "file_input" },
|
|
12823
|
+
{ base: "request\\.params", sourceType: "http_param" },
|
|
12824
|
+
{ base: "request\\.query", sourceType: "http_param" },
|
|
12825
|
+
{ base: "request\\.body", sourceType: "http_body" },
|
|
12826
|
+
{ base: "request\\.headers", sourceType: "http_header" },
|
|
12827
|
+
{ base: "process\\.env", sourceType: "env_input" },
|
|
12828
|
+
{ base: "process\\.argv", sourceType: "io_input" },
|
|
12829
|
+
{ base: "ctx\\.query", sourceType: "http_param" },
|
|
12830
|
+
{ base: "ctx\\.params", sourceType: "http_param" },
|
|
12831
|
+
{ base: "ctx\\.request", sourceType: "http_body" }
|
|
12832
|
+
];
|
|
12833
|
+
const exact = [];
|
|
12834
|
+
const contained = [];
|
|
12835
|
+
for (const { base, sourceType } of bases) {
|
|
12836
|
+
exact.push({ pattern: new RegExp(`^${base}\\b`), sourceType });
|
|
12837
|
+
contained.push({ pattern: new RegExp(`\\b${base}\\b`), sourceType });
|
|
12838
|
+
}
|
|
12839
|
+
return { exact, contained };
|
|
12840
|
+
})();
|
|
12841
|
+
function compileJsSourcePatterns(sourcePatterns) {
|
|
12842
|
+
const cached = JS_SOURCE_PATTERN_CACHE.get(sourcePatterns);
|
|
12843
|
+
if (cached)
|
|
12844
|
+
return cached;
|
|
12845
|
+
const exact = [];
|
|
12846
|
+
const contained = [];
|
|
12847
|
+
for (const sp of sourcePatterns) {
|
|
12848
|
+
if (sp.property && sp.object && sp.property_tainted) {
|
|
12849
|
+
exact.push({
|
|
12850
|
+
pattern: new RegExp(`^${sp.object}\\.${sp.property}\\b`),
|
|
12851
|
+
sourceType: sp.type
|
|
12852
|
+
});
|
|
12853
|
+
contained.push({
|
|
12854
|
+
pattern: new RegExp(`\\b${sp.object}\\.${sp.property}\\b`),
|
|
12855
|
+
sourceType: sp.type
|
|
12856
|
+
});
|
|
12857
|
+
}
|
|
12858
|
+
}
|
|
12859
|
+
const compiled = { exact, contained };
|
|
12860
|
+
JS_SOURCE_PATTERN_CACHE.set(sourcePatterns, compiled);
|
|
12861
|
+
return compiled;
|
|
12862
|
+
}
|
|
12760
12863
|
function isJavaScriptTaintedArgument(argExpression, sourcePatterns) {
|
|
12761
|
-
|
|
12762
|
-
|
|
12763
|
-
|
|
12764
|
-
|
|
12765
|
-
|
|
12766
|
-
const exactRegex = new RegExp(`^${sp.object}\\.${sp.property}\\b`);
|
|
12767
|
-
exactPatterns.push({ pattern: exactRegex, sourceType: sp.type });
|
|
12768
|
-
const containedRegex = new RegExp(`\\b${sp.object}\\.${sp.property}\\b`);
|
|
12769
|
-
containedPatterns.push({ pattern: containedRegex, sourceType: sp.type });
|
|
12770
|
-
}
|
|
12771
|
-
}
|
|
12772
|
-
}
|
|
12773
|
-
if (exactPatterns.length === 0) {
|
|
12774
|
-
const basePatterns = [
|
|
12775
|
-
{ base: "req\\.params", sourceType: "http_param" },
|
|
12776
|
-
{ base: "req\\.query", sourceType: "http_param" },
|
|
12777
|
-
{ base: "req\\.body", sourceType: "http_body" },
|
|
12778
|
-
{ base: "req\\.headers", sourceType: "http_header" },
|
|
12779
|
-
{ base: "req\\.cookies", sourceType: "http_cookie" },
|
|
12780
|
-
{ base: "req\\.url", sourceType: "http_path" },
|
|
12781
|
-
{ base: "req\\.path", sourceType: "http_path" },
|
|
12782
|
-
{ base: "req\\.originalUrl", sourceType: "http_path" },
|
|
12783
|
-
{ base: "req\\.file", sourceType: "file_input" },
|
|
12784
|
-
{ base: "req\\.files", sourceType: "file_input" },
|
|
12785
|
-
{ base: "request\\.params", sourceType: "http_param" },
|
|
12786
|
-
{ base: "request\\.query", sourceType: "http_param" },
|
|
12787
|
-
{ base: "request\\.body", sourceType: "http_body" },
|
|
12788
|
-
{ base: "request\\.headers", sourceType: "http_header" },
|
|
12789
|
-
{ base: "process\\.env", sourceType: "env_input" },
|
|
12790
|
-
{ base: "process\\.argv", sourceType: "io_input" },
|
|
12791
|
-
{ base: "ctx\\.query", sourceType: "http_param" },
|
|
12792
|
-
{ base: "ctx\\.params", sourceType: "http_param" },
|
|
12793
|
-
{ base: "ctx\\.request", sourceType: "http_body" }
|
|
12794
|
-
];
|
|
12795
|
-
for (const { base, sourceType } of basePatterns) {
|
|
12796
|
-
exactPatterns.push({ pattern: new RegExp(`^${base}\\b`), sourceType });
|
|
12797
|
-
containedPatterns.push({ pattern: new RegExp(`\\b${base}\\b`), sourceType });
|
|
12864
|
+
let compiled;
|
|
12865
|
+
if (sourcePatterns && sourcePatterns.length > 0) {
|
|
12866
|
+
compiled = compileJsSourcePatterns(sourcePatterns);
|
|
12867
|
+
if (compiled.exact.length === 0) {
|
|
12868
|
+
compiled = JS_FALLBACK_COMPILED;
|
|
12798
12869
|
}
|
|
12870
|
+
} else {
|
|
12871
|
+
compiled = JS_FALLBACK_COMPILED;
|
|
12799
12872
|
}
|
|
12800
|
-
for (const { pattern, sourceType } of
|
|
12873
|
+
for (const { pattern, sourceType } of compiled.exact) {
|
|
12801
12874
|
if (pattern.test(argExpression)) {
|
|
12802
12875
|
return { isTainted: true, sourceType };
|
|
12803
12876
|
}
|
|
12804
12877
|
}
|
|
12805
|
-
for (const { pattern, sourceType } of
|
|
12878
|
+
for (const { pattern, sourceType } of compiled.contained) {
|
|
12806
12879
|
if (pattern.test(argExpression)) {
|
|
12807
12880
|
return { isTainted: true, sourceType };
|
|
12808
12881
|
}
|
|
@@ -15934,6 +16007,20 @@ function walkBackwardDefs(startDefId, chainsByToDef, defById, options = {}) {
|
|
|
15934
16007
|
return { visited, lines, hopCapReached };
|
|
15935
16008
|
}
|
|
15936
16009
|
|
|
16010
|
+
// ../circle-ir/dist/analysis/sanitizer-index.js
|
|
16011
|
+
var SANITIZER_SET_CACHE = new WeakMap;
|
|
16012
|
+
function getSanitizesSet(san) {
|
|
16013
|
+
let s = SANITIZER_SET_CACHE.get(san);
|
|
16014
|
+
if (!s) {
|
|
16015
|
+
s = new Set(san.sanitizes);
|
|
16016
|
+
SANITIZER_SET_CACHE.set(san, s);
|
|
16017
|
+
}
|
|
16018
|
+
return s;
|
|
16019
|
+
}
|
|
16020
|
+
function sanitizerCoversSink(san, sinkType) {
|
|
16021
|
+
return getSanitizesSet(san).has(sinkType);
|
|
16022
|
+
}
|
|
16023
|
+
|
|
15937
16024
|
// ../circle-ir/dist/analysis/taint-propagation.js
|
|
15938
16025
|
function buildSanitizersByLine(sanitizers) {
|
|
15939
16026
|
const out2 = new Map;
|
|
@@ -16155,7 +16242,7 @@ function checkSanitized(fromLine, toLine, sinkType, sanitizersByLine, ctx) {
|
|
|
16155
16242
|
if (sanitizersAtTarget && sanitizersAtTarget.length > 0) {
|
|
16156
16243
|
for (const san of sanitizersAtTarget) {
|
|
16157
16244
|
if (isKnownSinkType) {
|
|
16158
|
-
if (san
|
|
16245
|
+
if (sanitizerCoversSink(san, sinkType)) {
|
|
16159
16246
|
return { sanitized: true, sanitizer: san };
|
|
16160
16247
|
}
|
|
16161
16248
|
} else if (san.sanitizes.length > 0) {
|
|
@@ -16175,7 +16262,7 @@ function checkSanitized(fromLine, toLine, sinkType, sanitizersByLine, ctx) {
|
|
|
16175
16262
|
continue;
|
|
16176
16263
|
for (const san of sansAtLine) {
|
|
16177
16264
|
if (isKnownSinkType) {
|
|
16178
|
-
if (san
|
|
16265
|
+
if (sanitizerCoversSink(san, sinkType)) {
|
|
16179
16266
|
return { sanitized: true, sanitizer: san };
|
|
16180
16267
|
}
|
|
16181
16268
|
} else if (san.sanitizes.length > 0) {
|
|
@@ -23193,7 +23280,7 @@ class CrossFilePass {
|
|
|
23193
23280
|
for (const san of sinkIR.taint.sanitizers ?? []) {
|
|
23194
23281
|
if (san.line < lo || san.line > hi)
|
|
23195
23282
|
continue;
|
|
23196
|
-
if (san
|
|
23283
|
+
if (sanitizerCoversSink(san, sinkTypeStr)) {
|
|
23197
23284
|
return false;
|
|
23198
23285
|
}
|
|
23199
23286
|
}
|
|
@@ -23202,7 +23289,7 @@ class CrossFilePass {
|
|
|
23202
23289
|
for (const san of sinkIR.taint.sanitizers ?? []) {
|
|
23203
23290
|
if (san.line !== tp.sink.line)
|
|
23204
23291
|
continue;
|
|
23205
|
-
if (san
|
|
23292
|
+
if (sanitizerCoversSink(san, sinkTypeStr)) {
|
|
23206
23293
|
return false;
|
|
23207
23294
|
}
|
|
23208
23295
|
}
|
|
@@ -32083,7 +32170,7 @@ function filterSanitizedSinks(sinks, sanitizers, calls) {
|
|
|
32083
32170
|
if (!lineSanitizers || lineSanitizers.length === 0)
|
|
32084
32171
|
return true;
|
|
32085
32172
|
for (const san of lineSanitizers) {
|
|
32086
|
-
if (san
|
|
32173
|
+
if (sanitizerCoversSink(san, sink.type)) {
|
|
32087
32174
|
const lineCalls = callsByLine.get(sink.line) ?? [];
|
|
32088
32175
|
for (const call of lineCalls) {
|
|
32089
32176
|
for (const arg of call.arguments) {
|
|
@@ -32573,15 +32660,25 @@ class TaintPropagationPass {
|
|
|
32573
32660
|
confidence: flow.confidence,
|
|
32574
32661
|
sanitized: flow.sanitized
|
|
32575
32662
|
}));
|
|
32663
|
+
const flowKey = (x) => `${x.source_line}|${x.sink_line}|${x.sink_type}`;
|
|
32664
|
+
const flowKeys = new Set;
|
|
32665
|
+
for (const x of flows)
|
|
32666
|
+
flowKeys.add(flowKey(x));
|
|
32667
|
+
const pushIfNew = (f) => {
|
|
32668
|
+
const k = flowKey(f);
|
|
32669
|
+
if (flowKeys.has(k))
|
|
32670
|
+
return false;
|
|
32671
|
+
flowKeys.add(k);
|
|
32672
|
+
flows.push(f);
|
|
32673
|
+
return true;
|
|
32674
|
+
};
|
|
32576
32675
|
const arrayFlows = detectArrayElementFlows(calls, sources, sinks, constProp.taintedArrayElements, constProp.unreachableLines, types) ?? [];
|
|
32577
32676
|
for (const f of arrayFlows) {
|
|
32578
|
-
|
|
32579
|
-
flows.push(f);
|
|
32580
|
-
}
|
|
32677
|
+
pushIfNew(f);
|
|
32581
32678
|
}
|
|
32582
32679
|
const collectionFlows = detectCollectionFlows(calls, sources, sinks, constProp.tainted, constProp.unreachableLines, ctx.code, types) ?? [];
|
|
32583
32680
|
for (const f of collectionFlows) {
|
|
32584
|
-
if (
|
|
32681
|
+
if (flowKeys.has(flowKey(f)))
|
|
32585
32682
|
continue;
|
|
32586
32683
|
const flowForCheck = {
|
|
32587
32684
|
source: { line: f.source_line },
|
|
@@ -32599,17 +32696,15 @@ class TaintPropagationPass {
|
|
|
32599
32696
|
}
|
|
32600
32697
|
if (isFP)
|
|
32601
32698
|
continue;
|
|
32602
|
-
|
|
32699
|
+
pushIfNew(f);
|
|
32603
32700
|
}
|
|
32604
32701
|
const paramFlows = detectParameterSinkFlows(types, calls, sources, sinks, constProp.unreachableLines, constProp.tainted, ctx.code) ?? [];
|
|
32605
32702
|
for (const f of paramFlows) {
|
|
32606
|
-
|
|
32607
|
-
flows.push(f);
|
|
32608
|
-
}
|
|
32703
|
+
pushIfNew(f);
|
|
32609
32704
|
}
|
|
32610
32705
|
const exprScanFlows = detectExpressionScanFlows(calls, sources, sinks, sanitizers, constProp.unreachableLines, constProp.tainted, ctx.code, ctx.language) ?? [];
|
|
32611
32706
|
for (const f of exprScanFlows) {
|
|
32612
|
-
if (
|
|
32707
|
+
if (flowKeys.has(flowKey(f)))
|
|
32613
32708
|
continue;
|
|
32614
32709
|
const flowForCheck = {
|
|
32615
32710
|
source: { line: f.source_line },
|
|
@@ -32627,7 +32722,7 @@ class TaintPropagationPass {
|
|
|
32627
32722
|
}
|
|
32628
32723
|
if (isFP)
|
|
32629
32724
|
continue;
|
|
32630
|
-
|
|
32725
|
+
pushIfNew(f);
|
|
32631
32726
|
}
|
|
32632
32727
|
const sanitizedNames = constProp.sanitizedVars;
|
|
32633
32728
|
let finalFlows = sanitizedNames.size === 0 ? flows : flows.filter((f) => {
|
|
@@ -32660,7 +32755,7 @@ class TaintPropagationPass {
|
|
|
32660
32755
|
if (!sansAtLine)
|
|
32661
32756
|
continue;
|
|
32662
32757
|
for (const san of sansAtLine) {
|
|
32663
|
-
if (san
|
|
32758
|
+
if (sanitizerCoversSink(san, f.sink_type)) {
|
|
32664
32759
|
return false;
|
|
32665
32760
|
}
|
|
32666
32761
|
}
|
|
@@ -32670,7 +32765,7 @@ class TaintPropagationPass {
|
|
|
32670
32765
|
const sansAtSink = sanitizersByLine.get(f.sink_line);
|
|
32671
32766
|
if (sansAtSink && sansAtSink.length > 0) {
|
|
32672
32767
|
for (const san of sansAtSink) {
|
|
32673
|
-
if (san
|
|
32768
|
+
if (sanitizerCoversSink(san, f.sink_type)) {
|
|
32674
32769
|
return false;
|
|
32675
32770
|
}
|
|
32676
32771
|
}
|
|
@@ -32696,7 +32791,7 @@ class TaintPropagationPass {
|
|
|
32696
32791
|
if (!sansAtLine || sansAtLine.length === 0)
|
|
32697
32792
|
continue;
|
|
32698
32793
|
for (const san of sansAtLine) {
|
|
32699
|
-
if (san
|
|
32794
|
+
if (sanitizerCoversSink(san, f.sink_type)) {
|
|
32700
32795
|
return false;
|
|
32701
32796
|
}
|
|
32702
32797
|
}
|
|
@@ -34239,7 +34334,7 @@ class InterproceduralPass {
|
|
|
34239
34334
|
if (!sansAtLine)
|
|
34240
34335
|
continue;
|
|
34241
34336
|
for (const san of sansAtLine) {
|
|
34242
|
-
if (san
|
|
34337
|
+
if (sanitizerCoversSink(san, f.sink_type)) {
|
|
34243
34338
|
sanitizedSinkKeys.add(`${f.sink_line}:${f.sink_type}`);
|
|
34244
34339
|
return false;
|
|
34245
34340
|
}
|
|
@@ -34251,7 +34346,7 @@ class InterproceduralPass {
|
|
|
34251
34346
|
if (!sansAtSink || sansAtSink.length === 0)
|
|
34252
34347
|
return true;
|
|
34253
34348
|
for (const san of sansAtSink) {
|
|
34254
|
-
if (san
|
|
34349
|
+
if (sanitizerCoversSink(san, f.sink_type)) {
|
|
34255
34350
|
return false;
|
|
34256
34351
|
}
|
|
34257
34352
|
}
|
|
@@ -43489,7 +43584,9 @@ function getNodeTypesForLanguage(language) {
|
|
|
43489
43584
|
"jsx_self_closing_element",
|
|
43490
43585
|
"jsx_opening_element",
|
|
43491
43586
|
"jsx_attribute",
|
|
43492
|
-
"jsx_expression"
|
|
43587
|
+
"jsx_expression",
|
|
43588
|
+
"function",
|
|
43589
|
+
"function_expression"
|
|
43493
43590
|
]);
|
|
43494
43591
|
case "bash":
|
|
43495
43592
|
return new Set([
|
|
@@ -43543,7 +43640,9 @@ function getNodeTypesForLanguage(language) {
|
|
|
43543
43640
|
"field_declaration",
|
|
43544
43641
|
"import_declaration",
|
|
43545
43642
|
"interface_declaration",
|
|
43546
|
-
"enum_declaration"
|
|
43643
|
+
"enum_declaration",
|
|
43644
|
+
"package_declaration",
|
|
43645
|
+
"local_variable_declaration"
|
|
43547
43646
|
]);
|
|
43548
43647
|
}
|
|
43549
43648
|
}
|
|
@@ -43601,10 +43700,21 @@ async function analyze(code, filePath, language, options = {}) {
|
|
|
43601
43700
|
}
|
|
43602
43701
|
}
|
|
43603
43702
|
logger.debug("Analyzing file", { filePath, language, parseGrammar, codeLength: code.length });
|
|
43703
|
+
const phaseTimingEnabled = globalThis.__circleIrPassTiming === true;
|
|
43704
|
+
const phaseStart = () => phaseTimingEnabled ? Date.now() : 0;
|
|
43705
|
+
const phaseEnd = (label, t0) => {
|
|
43706
|
+
if (!phaseTimingEnabled)
|
|
43707
|
+
return;
|
|
43708
|
+
console.error(`[phase-timing] ${label} ${Date.now() - t0}ms file=${filePath}`);
|
|
43709
|
+
};
|
|
43710
|
+
const tParse = phaseStart();
|
|
43604
43711
|
const tree = await parse(code, parseGrammar);
|
|
43712
|
+
phaseEnd("parse", tParse);
|
|
43605
43713
|
try {
|
|
43606
43714
|
logger.trace("Parsed AST", { rootNodeType: tree.rootNode.type });
|
|
43715
|
+
const tParseStatus = phaseStart();
|
|
43607
43716
|
const parseStatus = extractParseStatus(tree);
|
|
43717
|
+
phaseEnd("extractParseStatus", tParseStatus);
|
|
43608
43718
|
if (parseStatus.has_errors) {
|
|
43609
43719
|
logger.warn("Partial parse — IR may be incomplete", {
|
|
43610
43720
|
filePath,
|
|
@@ -43613,18 +43723,37 @@ async function analyze(code, filePath, language, options = {}) {
|
|
|
43613
43723
|
firstErrorLine: parseStatus.error_locations[0]?.line
|
|
43614
43724
|
});
|
|
43615
43725
|
}
|
|
43726
|
+
const tCollect = phaseStart();
|
|
43616
43727
|
const nodeCache = collectAllNodes(tree.rootNode, getNodeTypesForLanguage(language));
|
|
43728
|
+
phaseEnd("collectAllNodes", tCollect);
|
|
43729
|
+
const tMeta = phaseStart();
|
|
43617
43730
|
const meta = extractMeta(code, tree, filePath, language);
|
|
43618
43731
|
if (options.projectProfile !== undefined) {
|
|
43619
43732
|
meta.projectProfile = makeProfileResolver2(options.projectProfile)(filePath);
|
|
43620
43733
|
}
|
|
43734
|
+
phaseEnd("extractMeta", tMeta);
|
|
43735
|
+
const tTypes = phaseStart();
|
|
43621
43736
|
const types = extractTypes(tree, nodeCache, language);
|
|
43737
|
+
phaseEnd("extractTypes", tTypes);
|
|
43738
|
+
const tCalls = phaseStart();
|
|
43622
43739
|
const calls = extractCalls(tree, nodeCache, language);
|
|
43623
|
-
|
|
43740
|
+
phaseEnd("extractCalls", tCalls);
|
|
43741
|
+
const tImports = phaseStart();
|
|
43742
|
+
const imports = extractImports(tree, language, nodeCache);
|
|
43743
|
+
phaseEnd("extractImports", tImports);
|
|
43744
|
+
const tExports = phaseStart();
|
|
43624
43745
|
const exports = extractExports(types);
|
|
43625
|
-
|
|
43746
|
+
phaseEnd("extractExports", tExports);
|
|
43747
|
+
const tCFG = phaseStart();
|
|
43748
|
+
const cfg = buildCFG(tree, language, nodeCache);
|
|
43749
|
+
phaseEnd("buildCFG", tCFG);
|
|
43750
|
+
const tDFG = phaseStart();
|
|
43626
43751
|
const dfg = buildDFG(tree, nodeCache, language);
|
|
43752
|
+
phaseEnd("buildDFG", tDFG);
|
|
43753
|
+
const tRuntime = phaseStart();
|
|
43627
43754
|
const runtimeRegistrations = extractRuntimeRegistrations(tree, nodeCache, language, imports);
|
|
43755
|
+
phaseEnd("extractRuntimeRegistrations", tRuntime);
|
|
43756
|
+
const tGraph = phaseStart();
|
|
43628
43757
|
const graph = new CodeGraph({
|
|
43629
43758
|
meta,
|
|
43630
43759
|
types,
|
|
@@ -43637,6 +43766,7 @@ async function analyze(code, filePath, language, options = {}) {
|
|
|
43637
43766
|
unresolved: [],
|
|
43638
43767
|
enriched: {}
|
|
43639
43768
|
});
|
|
43769
|
+
phaseEnd("buildCodeGraph", tGraph);
|
|
43640
43770
|
const config = options.taintConfig ?? getDefaultConfig();
|
|
43641
43771
|
const disabledPasses = new Set(options.disabledPasses ?? []);
|
|
43642
43772
|
const passOpts = options.passOptions ?? {};
|
|
@@ -44595,7 +44725,7 @@ var colors = {
|
|
|
44595
44725
|
};
|
|
44596
44726
|
|
|
44597
44727
|
// src/version.ts
|
|
44598
|
-
var version = "3.
|
|
44728
|
+
var version = "3.173.0";
|
|
44599
44729
|
|
|
44600
44730
|
// src/formatters.ts
|
|
44601
44731
|
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.173.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.173.0"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@types/node": "^25.5.0",
|