cognium-dev 4.9.17 → 4.9.20
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 +943 -216
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -3232,7 +3232,7 @@ var Query = class {
|
|
|
3232
3232
|
}
|
|
3233
3233
|
};
|
|
3234
3234
|
|
|
3235
|
-
//
|
|
3235
|
+
// ../circle-ir/dist/core/parser.js
|
|
3236
3236
|
var nodeModules = null;
|
|
3237
3237
|
var moduleDir = null;
|
|
3238
3238
|
async function getNodeModules() {
|
|
@@ -3472,7 +3472,7 @@ async function getDefaultLanguagePath(language) {
|
|
|
3472
3472
|
}
|
|
3473
3473
|
return `wasm/tree-sitter-${language}.wasm`;
|
|
3474
3474
|
}
|
|
3475
|
-
//
|
|
3475
|
+
// ../circle-ir/dist/core/extractors/meta.js
|
|
3476
3476
|
function extractMeta(code, tree, filePath, language) {
|
|
3477
3477
|
const loc = countLinesOfCode(code);
|
|
3478
3478
|
const hash = computeHash(code);
|
|
@@ -3554,7 +3554,7 @@ function extractPackage(tree, language) {
|
|
|
3554
3554
|
}
|
|
3555
3555
|
return null;
|
|
3556
3556
|
}
|
|
3557
|
-
//
|
|
3557
|
+
// ../circle-ir/dist/core/extractors/types.js
|
|
3558
3558
|
function detectLanguage(tree) {
|
|
3559
3559
|
const root = tree.rootNode;
|
|
3560
3560
|
const jsNodeTypes = new Set([
|
|
@@ -5222,7 +5222,7 @@ function findChildByType(node, type) {
|
|
|
5222
5222
|
}
|
|
5223
5223
|
return null;
|
|
5224
5224
|
}
|
|
5225
|
-
//
|
|
5225
|
+
// ../circle-ir/dist/core/extractors/calls.js
|
|
5226
5226
|
function detectLanguageFromTree(tree, cache) {
|
|
5227
5227
|
const rustStructs = getNodesFromCache(tree.rootNode, "struct_item", cache);
|
|
5228
5228
|
const rustImpls = getNodesFromCache(tree.rootNode, "impl_item", cache);
|
|
@@ -6055,6 +6055,14 @@ function buildResolutionContext(tree, cache) {
|
|
|
6055
6055
|
}
|
|
6056
6056
|
}
|
|
6057
6057
|
}
|
|
6058
|
+
const resourceDecls = getNodesFromCache(tree.rootNode, "resource", cache);
|
|
6059
|
+
for (const res of resourceDecls) {
|
|
6060
|
+
const typeNode = res.childForFieldName("type");
|
|
6061
|
+
const nameNode = res.childForFieldName("name");
|
|
6062
|
+
if (typeNode && nameNode) {
|
|
6063
|
+
context.localVarTypes.set(getNodeText(nameNode), getNodeText(typeNode));
|
|
6064
|
+
}
|
|
6065
|
+
}
|
|
6058
6066
|
const imports = getNodesFromCache(tree.rootNode, "import_declaration", cache);
|
|
6059
6067
|
for (const imp of imports) {
|
|
6060
6068
|
const text = getNodeText(imp);
|
|
@@ -7336,7 +7344,7 @@ function extractGoTypeLastSegment(typeNode) {
|
|
|
7336
7344
|
}
|
|
7337
7345
|
return null;
|
|
7338
7346
|
}
|
|
7339
|
-
//
|
|
7347
|
+
// ../circle-ir/dist/core/extractors/imports.js
|
|
7340
7348
|
function detectLanguage2(tree) {
|
|
7341
7349
|
const root = tree.rootNode;
|
|
7342
7350
|
const jsNodeTypes = new Set([
|
|
@@ -8023,7 +8031,7 @@ function findGoChildByType(node, type) {
|
|
|
8023
8031
|
}
|
|
8024
8032
|
return null;
|
|
8025
8033
|
}
|
|
8026
|
-
//
|
|
8034
|
+
// ../circle-ir/dist/core/extractors/exports.js
|
|
8027
8035
|
function extractExports(types) {
|
|
8028
8036
|
const exports = [];
|
|
8029
8037
|
for (const type of types) {
|
|
@@ -8076,7 +8084,7 @@ function getVisibilityFromModifiers(modifiers) {
|
|
|
8076
8084
|
}
|
|
8077
8085
|
return "package";
|
|
8078
8086
|
}
|
|
8079
|
-
//
|
|
8087
|
+
// ../circle-ir/dist/core/extractors/cfg.js
|
|
8080
8088
|
function detectLanguage3(tree) {
|
|
8081
8089
|
const root = tree.rootNode;
|
|
8082
8090
|
const jsNodeTypes = new Set([
|
|
@@ -8725,7 +8733,7 @@ function isGoStatement(node) {
|
|
|
8725
8733
|
]);
|
|
8726
8734
|
return goStatementTypes.has(node.type);
|
|
8727
8735
|
}
|
|
8728
|
-
//
|
|
8736
|
+
// ../circle-ir/dist/core/extractors/dfg.js
|
|
8729
8737
|
function detectLanguage4(tree) {
|
|
8730
8738
|
const root = tree.rootNode;
|
|
8731
8739
|
const jsNodeTypes = new Set([
|
|
@@ -8796,6 +8804,7 @@ function buildCSharpDFG(tree, cache) {
|
|
|
8796
8804
|
];
|
|
8797
8805
|
for (const method of methods) {
|
|
8798
8806
|
scopeStack.push(new Map);
|
|
8807
|
+
const methodDefStart = defs.length;
|
|
8799
8808
|
const params = method.childForFieldName("parameters");
|
|
8800
8809
|
if (params) {
|
|
8801
8810
|
for (const def of extractParameterDefs(params, defIdCounter)) {
|
|
@@ -8825,6 +8834,7 @@ function buildCSharpDFG(tree, cache) {
|
|
|
8825
8834
|
}
|
|
8826
8835
|
}
|
|
8827
8836
|
const bodyUses = extractUses(body2, useIdCounter, scopeStack, false);
|
|
8837
|
+
resolveReassignedUses(defs.slice(methodDefStart), bodyUses.uses);
|
|
8828
8838
|
uses.push(...bodyUses.uses);
|
|
8829
8839
|
useIdCounter = bodyUses.nextId;
|
|
8830
8840
|
}
|
|
@@ -9547,6 +9557,38 @@ function findReachingDef(name2, scopeStack) {
|
|
|
9547
9557
|
}
|
|
9548
9558
|
return null;
|
|
9549
9559
|
}
|
|
9560
|
+
function resolveReassignedUses(methodDefs, methodUses) {
|
|
9561
|
+
const defsByVar = new Map;
|
|
9562
|
+
for (const def of methodDefs) {
|
|
9563
|
+
if (def.kind !== "local" && def.kind !== "param")
|
|
9564
|
+
continue;
|
|
9565
|
+
const existing = defsByVar.get(def.variable);
|
|
9566
|
+
if (existing)
|
|
9567
|
+
existing.push(def);
|
|
9568
|
+
else
|
|
9569
|
+
defsByVar.set(def.variable, [def]);
|
|
9570
|
+
}
|
|
9571
|
+
for (const list of defsByVar.values()) {
|
|
9572
|
+
if (list.length > 1)
|
|
9573
|
+
list.sort((a, b) => a.line - b.line || a.id - b.id);
|
|
9574
|
+
}
|
|
9575
|
+
for (const use of methodUses) {
|
|
9576
|
+
const list = defsByVar.get(use.variable);
|
|
9577
|
+
if (!list || list.length < 2)
|
|
9578
|
+
continue;
|
|
9579
|
+
let strictlyBefore;
|
|
9580
|
+
let sameLine;
|
|
9581
|
+
for (const def of list) {
|
|
9582
|
+
if (def.line < use.line)
|
|
9583
|
+
strictlyBefore = def;
|
|
9584
|
+
else if (def.line === use.line)
|
|
9585
|
+
sameLine = def;
|
|
9586
|
+
}
|
|
9587
|
+
const reaching = strictlyBefore ?? sameLine;
|
|
9588
|
+
if (reaching)
|
|
9589
|
+
use.def_id = reaching.id;
|
|
9590
|
+
}
|
|
9591
|
+
}
|
|
9550
9592
|
function computeChains(defs, uses) {
|
|
9551
9593
|
const chains = [];
|
|
9552
9594
|
const defById = new Map;
|
|
@@ -10246,7 +10288,7 @@ function extractGoAddressableVarName(node) {
|
|
|
10246
10288
|
}
|
|
10247
10289
|
return null;
|
|
10248
10290
|
}
|
|
10249
|
-
//
|
|
10291
|
+
// ../circle-ir/dist/core/extractors/runtime-registrations.js
|
|
10250
10292
|
var HTTP_VERB_METHODS = new Set([
|
|
10251
10293
|
"get",
|
|
10252
10294
|
"post",
|
|
@@ -10994,7 +11036,7 @@ function parseDistributedSliceAttribute(attrItem) {
|
|
|
10994
11036
|
}
|
|
10995
11037
|
};
|
|
10996
11038
|
}
|
|
10997
|
-
//
|
|
11039
|
+
// ../circle-ir/dist/analysis/config-loader.js
|
|
10998
11040
|
var DEFAULT_SOURCES = [
|
|
10999
11041
|
{ method: "getParameter", class: "HttpServletRequest", type: "http_param", severity: "high", return_tainted: true },
|
|
11000
11042
|
{ method: "getParameterValues", class: "HttpServletRequest", type: "http_param", severity: "high", return_tainted: true },
|
|
@@ -11086,12 +11128,6 @@ var DEFAULT_SOURCES = [
|
|
|
11086
11128
|
{ method: "getBody", class: "Exchange", type: "http_body", severity: "high", return_tainted: true },
|
|
11087
11129
|
{ method: "getIn", class: "Exchange", type: "http_body", severity: "high", return_tainted: true },
|
|
11088
11130
|
{ method: "getHeader", class: "Message", type: "http_header", severity: "high", return_tainted: true },
|
|
11089
|
-
{ method: "getFileName", type: "file_input", severity: "high", return_tainted: true },
|
|
11090
|
-
{ method: "getName", class: "File", type: "file_input", severity: "high", return_tainted: true },
|
|
11091
|
-
{ method: "getPath", class: "File", type: "file_input", severity: "high", return_tainted: true },
|
|
11092
|
-
{ method: "getAbsolutePath", class: "File", type: "file_input", severity: "high", return_tainted: true },
|
|
11093
|
-
{ method: "toString", class: "Path", type: "file_input", severity: "medium", return_tainted: true },
|
|
11094
|
-
{ method: "getFileName", class: "Path", type: "file_input", severity: "high", return_tainted: true },
|
|
11095
11131
|
{ method: "getOriginalFilename", class: "MultipartFile", type: "file_input", severity: "high", return_tainted: true },
|
|
11096
11132
|
{ method: "getName", class: "MultipartFile", type: "file_input", severity: "high", return_tainted: true },
|
|
11097
11133
|
{ method: "getSubmittedFileName", class: "Part", type: "file_input", severity: "high", return_tainted: true },
|
|
@@ -11162,7 +11198,6 @@ var DEFAULT_SOURCES = [
|
|
|
11162
11198
|
{ method: "refreshUsersAndGroups", type: "io_input", severity: "high", return_tainted: true },
|
|
11163
11199
|
{ method: "getScriptPath", type: "io_input", severity: "critical", return_tainted: true },
|
|
11164
11200
|
{ method: "getFilePathSuffix", type: "io_input", severity: "high", return_tainted: true },
|
|
11165
|
-
{ method: "getPath", type: "file_input", severity: "high", return_tainted: true },
|
|
11166
11201
|
{ method: "contentAsString", type: "file_input", severity: "critical", return_tainted: true },
|
|
11167
11202
|
{ method: "readAsString", type: "file_input", severity: "critical", return_tainted: true },
|
|
11168
11203
|
{ method: "content", type: "file_input", severity: "high", return_tainted: true },
|
|
@@ -11533,8 +11568,8 @@ var DEFAULT_SINKS = [
|
|
|
11533
11568
|
{ method: "selectByExample", class: "*Mapper", type: "mybatis_mapper_call", cwe: "CWE-89", severity: "medium", arg_positions: [0], languages: ["java"] },
|
|
11534
11569
|
{ method: "exec", class: "Runtime", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1] },
|
|
11535
11570
|
{ method: "start", class: "ProcessBuilder", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [] },
|
|
11536
|
-
{ method: "ProcessBuilder", class: "constructor", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
11537
|
-
{ method: "command", class: "ProcessBuilder", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
11571
|
+
{ method: "ProcessBuilder", class: "constructor", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1, 2, 3, 4, 5, 6, 7] },
|
|
11572
|
+
{ method: "command", class: "ProcessBuilder", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1, 2, 3, 4, 5, 6, 7] },
|
|
11538
11573
|
{ method: "execute", class: "DefaultExecutor", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
11539
11574
|
{ method: "CommandLine", class: "constructor", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
11540
11575
|
{ method: "parse", class: "CommandLine", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
@@ -12335,7 +12370,6 @@ var DEFAULT_SINKS = [
|
|
|
12335
12370
|
{ method: "fatal", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
12336
12371
|
{ method: "log", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [1, 2, 3, 4] },
|
|
12337
12372
|
{ method: "exception", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
12338
|
-
{ method: "command", class: "ProcessBuilder", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
12339
12373
|
{ method: "step", class: "StepExecution", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
12340
12374
|
{ method: "invokeMethod", class: "Script", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1] },
|
|
12341
12375
|
{ method: "evaluate", class: "Script", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
|
|
@@ -13097,7 +13131,33 @@ var DEFAULT_HEADER_RULES = [
|
|
|
13097
13131
|
note: "Fires when the value is not a string literal (likely reflected from request)"
|
|
13098
13132
|
}
|
|
13099
13133
|
];
|
|
13100
|
-
//
|
|
13134
|
+
// ../circle-ir/dist/analysis/literal-expression.js
|
|
13135
|
+
function isProvablyLiteralExpression(expr) {
|
|
13136
|
+
let e = (expr ?? "").trim();
|
|
13137
|
+
if (e.length === 0)
|
|
13138
|
+
return false;
|
|
13139
|
+
e = e.replace(/\/\/.*$/, "").replace(/;\s*$/, "").trim();
|
|
13140
|
+
if (e.length === 0)
|
|
13141
|
+
return false;
|
|
13142
|
+
if (e.includes("${"))
|
|
13143
|
+
return false;
|
|
13144
|
+
if (/[+]\s*$/.test(e))
|
|
13145
|
+
return false;
|
|
13146
|
+
const stripped = e.replace(/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|`(?:[^`\\$]|\\.)*`/g, "");
|
|
13147
|
+
if (/["'`]/.test(stripped))
|
|
13148
|
+
return false;
|
|
13149
|
+
return /^[\s+()]*$/.test(stripped);
|
|
13150
|
+
}
|
|
13151
|
+
var DOM_ASSIGNMENT_SINK_METHODS = new Set([
|
|
13152
|
+
"innerHTML",
|
|
13153
|
+
"outerHTML",
|
|
13154
|
+
"cssText",
|
|
13155
|
+
"src",
|
|
13156
|
+
"href",
|
|
13157
|
+
"textContent"
|
|
13158
|
+
]);
|
|
13159
|
+
|
|
13160
|
+
// ../circle-ir/dist/analysis/arg-type-resolver.js
|
|
13101
13161
|
function findEnclosingType(callInMethod, types) {
|
|
13102
13162
|
if (!callInMethod)
|
|
13103
13163
|
return null;
|
|
@@ -13175,7 +13235,7 @@ function isArgvContainerType(rawType) {
|
|
|
13175
13235
|
return /^(?:List|ArrayList|LinkedList|Collection|Iterable|Deque|Queue)\s*<\s*(?:String|CharSequence|java\.lang\.String)\b/.test(s);
|
|
13176
13236
|
}
|
|
13177
13237
|
|
|
13178
|
-
//
|
|
13238
|
+
// ../circle-ir/dist/analysis/taint-matcher.js
|
|
13179
13239
|
var PYTHON_TAINTED_PATTERNS = [
|
|
13180
13240
|
{ pattern: /\brequest\.args\b/, sourceType: "http_param" },
|
|
13181
13241
|
{ pattern: /\brequest\.form\b/, sourceType: "http_body" },
|
|
@@ -14050,7 +14110,7 @@ function isCSharpSsrfHostAllowlistGuarded(call, pattern, language, sourceLines)
|
|
|
14050
14110
|
if (!guards)
|
|
14051
14111
|
continue;
|
|
14052
14112
|
for (const g of guards) {
|
|
14053
|
-
if (g.i
|
|
14113
|
+
if (g.i > sinkIdx || checked.has(g))
|
|
14054
14114
|
continue;
|
|
14055
14115
|
checked.add(g);
|
|
14056
14116
|
const block = csThenBlock(sourceLines, g.i, g.rest);
|
|
@@ -14193,6 +14253,21 @@ function isRegexReceiver(receiver, sourceLines) {
|
|
|
14193
14253
|
const decl = new RegExp(`(?:const|let|var)\\s+${escapeRe(r)}\\s*=\\s*(?:/|(?:new\\s+)?RegExp\\s*\\()`);
|
|
14194
14254
|
return sourceLines.some((l) => decl.test(l));
|
|
14195
14255
|
}
|
|
14256
|
+
function isDeclaredFunctionReference(arg, sourceLines) {
|
|
14257
|
+
if (arg.literal !== null && arg.literal !== undefined)
|
|
14258
|
+
return false;
|
|
14259
|
+
if (!sourceLines)
|
|
14260
|
+
return false;
|
|
14261
|
+
const name2 = (arg.expression ?? "").trim();
|
|
14262
|
+
if (!/^[A-Za-z_$][\w$]*$/.test(name2))
|
|
14263
|
+
return false;
|
|
14264
|
+
const n = escapeRe(name2);
|
|
14265
|
+
const decls = [
|
|
14266
|
+
new RegExp(`\\bfunction\\s+${n}\\s*\\(`),
|
|
14267
|
+
new RegExp(`\\b(?:const|let|var)\\s+${n}\\s*=\\s*(?:async\\s+)?(?:function\\b|\\(|[A-Za-z_$][\\w$]*\\s*=>)`)
|
|
14268
|
+
];
|
|
14269
|
+
return sourceLines.some((l) => decls.some((re) => re.test(l)));
|
|
14270
|
+
}
|
|
14196
14271
|
function isFunctionCallbackArgument(arg) {
|
|
14197
14272
|
if (arg.literal !== null && arg.literal !== undefined)
|
|
14198
14273
|
return false;
|
|
@@ -14396,11 +14471,17 @@ function findSinks(calls, patterns, typeHierarchy, language, sourceLines, types)
|
|
|
14396
14471
|
}
|
|
14397
14472
|
if (pattern.type === "code_injection" && (call.method_name === "setInterval" || call.method_name === "setTimeout" || call.method_name === "setImmediate")) {
|
|
14398
14473
|
const firstArg = call.arguments.find((a) => a.position === 0);
|
|
14399
|
-
if (firstArg && isFunctionCallbackArgument(firstArg)) {
|
|
14474
|
+
if (firstArg && (isFunctionCallbackArgument(firstArg) || isDeclaredFunctionReference(firstArg, sourceLines))) {
|
|
14400
14475
|
continue;
|
|
14401
14476
|
}
|
|
14402
14477
|
}
|
|
14403
|
-
if (pattern.type === "
|
|
14478
|
+
if (pattern.type === "xss" && (language === "javascript" || language === "typescript") && DOM_ASSIGNMENT_SINK_METHODS.has(call.method_name) && call.arguments.length > 0) {
|
|
14479
|
+
const rhs = call.arguments.find((a) => a.position === 0);
|
|
14480
|
+
if (rhs && isProvablyLiteralExpression(rhs.expression ?? "")) {
|
|
14481
|
+
continue;
|
|
14482
|
+
}
|
|
14483
|
+
}
|
|
14484
|
+
if ((pattern.type === "command_injection" || pattern.type === "sql_injection") && call.method_name === "exec" && (language === "javascript" || language === "typescript") && isRegexReceiver(call.receiver, sourceLines)) {
|
|
14404
14485
|
continue;
|
|
14405
14486
|
}
|
|
14406
14487
|
if (pattern.type === "code_injection" && language === "python" && call.method_name === "compile" && call.receiver && call.receiver !== "builtins") {
|
|
@@ -15216,7 +15297,7 @@ function formatSanitizerMethod(call) {
|
|
|
15216
15297
|
return `${call.method_name}()`;
|
|
15217
15298
|
}
|
|
15218
15299
|
|
|
15219
|
-
//
|
|
15300
|
+
// ../circle-ir/dist/analysis/unresolved.js
|
|
15220
15301
|
function detectUnresolved(calls, types, dfg) {
|
|
15221
15302
|
const unresolved = [];
|
|
15222
15303
|
unresolved.push(...detectVirtualDispatch(calls));
|
|
@@ -15380,7 +15461,7 @@ function formatCallCode(call) {
|
|
|
15380
15461
|
}
|
|
15381
15462
|
return `${call.method_name}(${args2})`;
|
|
15382
15463
|
}
|
|
15383
|
-
//
|
|
15464
|
+
// ../circle-ir/dist/analysis/non-executable-lines.js
|
|
15384
15465
|
function isNonExecutableSourceLine(sourceCode, line, language) {
|
|
15385
15466
|
if (!sourceCode || line < 1)
|
|
15386
15467
|
return false;
|
|
@@ -15440,7 +15521,7 @@ function isNonExecutablePython(trimmed) {
|
|
|
15440
15521
|
return false;
|
|
15441
15522
|
}
|
|
15442
15523
|
|
|
15443
|
-
//
|
|
15524
|
+
// ../circle-ir/dist/analysis/sanitizer-index.js
|
|
15444
15525
|
var SANITIZER_SET_CACHE = new WeakMap;
|
|
15445
15526
|
function getSanitizesSet(san) {
|
|
15446
15527
|
let s = SANITIZER_SET_CACHE.get(san);
|
|
@@ -15454,7 +15535,7 @@ function sanitizerCoversSink(san, sinkType) {
|
|
|
15454
15535
|
return getSanitizesSet(san).has(sinkType);
|
|
15455
15536
|
}
|
|
15456
15537
|
|
|
15457
|
-
//
|
|
15538
|
+
// ../circle-ir/dist/analysis/dfg-walk.js
|
|
15458
15539
|
var walkBackwardDefsMemo = new WeakMap;
|
|
15459
15540
|
function walkBackwardDefs(startDefId, chainsByToDef, defById, options = {}) {
|
|
15460
15541
|
const maxHops = options.maxHops ?? 32;
|
|
@@ -15507,7 +15588,7 @@ function walkBackwardDefs(startDefId, chainsByToDef, defById, options = {}) {
|
|
|
15507
15588
|
return result;
|
|
15508
15589
|
}
|
|
15509
15590
|
|
|
15510
|
-
//
|
|
15591
|
+
// ../circle-ir/dist/analysis/findings.js
|
|
15511
15592
|
function canSourceReachSink(sourceType, sinkType) {
|
|
15512
15593
|
const sourceToSinkMapping = {
|
|
15513
15594
|
http_param: ["sql_injection", "command_injection", "path_traversal", "xss", "xpath_injection", "ldap_injection", "ssrf", "mybatis_mapper_call", "code_injection", "crlf", "mass_assignment", "open_redirect", "trust_boundary", "deserialization", "xxe", "log_injection", "format_string", "nosql_injection", "prompt_injection"],
|
|
@@ -15538,7 +15619,7 @@ function sourceSemanticsAllowed(source, sinkType) {
|
|
|
15538
15619
|
return true;
|
|
15539
15620
|
}
|
|
15540
15621
|
|
|
15541
|
-
//
|
|
15622
|
+
// ../circle-ir/dist/analysis/findings-instrumentation.js
|
|
15542
15623
|
var instrumentEnabled = false;
|
|
15543
15624
|
function setFindingsInstrumentation(enabled) {
|
|
15544
15625
|
instrumentEnabled = enabled;
|
|
@@ -15601,7 +15682,7 @@ function emitFindingsInstrumentation(filePath, findings, taint) {
|
|
|
15601
15682
|
};
|
|
15602
15683
|
console.error(`[findings-summary] ${JSON.stringify(summary)}`);
|
|
15603
15684
|
}
|
|
15604
|
-
//
|
|
15685
|
+
// ../circle-ir/dist/graph/code-graph.js
|
|
15605
15686
|
class CodeGraph {
|
|
15606
15687
|
ir;
|
|
15607
15688
|
constructor(ir) {
|
|
@@ -15811,7 +15892,7 @@ class CodeGraph {
|
|
|
15811
15892
|
return result;
|
|
15812
15893
|
}
|
|
15813
15894
|
}
|
|
15814
|
-
//
|
|
15895
|
+
// ../circle-ir/dist/resolution/type-hierarchy.js
|
|
15815
15896
|
class TypeHierarchyResolver {
|
|
15816
15897
|
types = new Map;
|
|
15817
15898
|
nameToFqn = new Map;
|
|
@@ -16383,7 +16464,7 @@ function registerCommonLibraries(resolver) {
|
|
|
16383
16464
|
resolver.registerFactoryReturnType("HttpClients", "createSystem", "org.apache.http.impl.client.CloseableHttpClient");
|
|
16384
16465
|
resolver.registerFactoryReturnType("HttpClients", "createMinimal", "org.apache.http.impl.client.MinimalHttpClient");
|
|
16385
16466
|
}
|
|
16386
|
-
//
|
|
16467
|
+
// ../circle-ir/dist/resolution/symbol-table.js
|
|
16387
16468
|
class SymbolTable {
|
|
16388
16469
|
exports = new Map;
|
|
16389
16470
|
nameToFqns = new Map;
|
|
@@ -16606,7 +16687,7 @@ class SymbolTable {
|
|
|
16606
16687
|
return "package";
|
|
16607
16688
|
}
|
|
16608
16689
|
}
|
|
16609
|
-
//
|
|
16690
|
+
// ../circle-ir/dist/resolution/cross-file.js
|
|
16610
16691
|
function buildFileIndex(ir) {
|
|
16611
16692
|
const callsByLine = new Map;
|
|
16612
16693
|
for (const c of ir.calls) {
|
|
@@ -17104,10 +17185,12 @@ class CrossFileResolver {
|
|
|
17104
17185
|
}
|
|
17105
17186
|
return callers;
|
|
17106
17187
|
}
|
|
17107
|
-
findCrossFileTaintFlows() {
|
|
17188
|
+
findCrossFileTaintFlows(deadline) {
|
|
17108
17189
|
const flows = [];
|
|
17109
17190
|
const seen = new Set;
|
|
17110
17191
|
for (const [filePath, ir] of this.fileIRs) {
|
|
17192
|
+
if (deadline?.())
|
|
17193
|
+
break;
|
|
17111
17194
|
for (const source of ir.taint.sources) {
|
|
17112
17195
|
if (source.type === "interprocedural_param")
|
|
17113
17196
|
continue;
|
|
@@ -17182,11 +17265,13 @@ class CrossFileResolver {
|
|
|
17182
17265
|
}
|
|
17183
17266
|
return flows;
|
|
17184
17267
|
}
|
|
17185
|
-
findInterproceduralTaintPaths() {
|
|
17268
|
+
findInterproceduralTaintPaths(deadline) {
|
|
17186
17269
|
const paths = [];
|
|
17187
17270
|
const seen = new Set;
|
|
17188
17271
|
const methodIndex = this.buildMethodIndex();
|
|
17189
17272
|
for (const [callerFile, callerIR] of this.fileIRs) {
|
|
17273
|
+
if (deadline?.())
|
|
17274
|
+
break;
|
|
17190
17275
|
const callerIdx = this.getFileIndex(callerIR);
|
|
17191
17276
|
for (const type of callerIR.types) {
|
|
17192
17277
|
for (const method of type.methods) {
|
|
@@ -17325,7 +17410,7 @@ class CrossFileResolver {
|
|
|
17325
17410
|
}
|
|
17326
17411
|
return paths;
|
|
17327
17412
|
}
|
|
17328
|
-
findFieldBindingTaintPaths() {
|
|
17413
|
+
findFieldBindingTaintPaths(deadline) {
|
|
17329
17414
|
const paths = [];
|
|
17330
17415
|
const seen = new Set;
|
|
17331
17416
|
if (this.fieldTaintInfo.size === 0)
|
|
@@ -17333,6 +17418,8 @@ class CrossFileResolver {
|
|
|
17333
17418
|
const fieldExprRe = /^(\w+)\.(\w+)$/;
|
|
17334
17419
|
const methodIndex = this.buildMethodIndex();
|
|
17335
17420
|
for (const [callerFile, callerIR] of this.fileIRs) {
|
|
17421
|
+
if (deadline?.())
|
|
17422
|
+
break;
|
|
17336
17423
|
const callerIdx = this.getFileIndex(callerIR);
|
|
17337
17424
|
for (const type of callerIR.types) {
|
|
17338
17425
|
const callerTypeFqn = callerIR.meta.package ? `${callerIR.meta.package}.${type.name}` : type.name;
|
|
@@ -17694,7 +17781,7 @@ class CrossFileResolver {
|
|
|
17694
17781
|
return this.fieldTaintInfo.get(`${typeFqn}.${fieldName}`);
|
|
17695
17782
|
}
|
|
17696
17783
|
}
|
|
17697
|
-
//
|
|
17784
|
+
// ../circle-ir/dist/graph/project-graph.js
|
|
17698
17785
|
class ProjectGraph {
|
|
17699
17786
|
files = new Map;
|
|
17700
17787
|
_symbolTable = null;
|
|
@@ -17746,7 +17833,7 @@ class ProjectGraph {
|
|
|
17746
17833
|
return this._resolver;
|
|
17747
17834
|
}
|
|
17748
17835
|
}
|
|
17749
|
-
//
|
|
17836
|
+
// ../circle-ir/dist/graph/analysis-pass.js
|
|
17750
17837
|
class AnalysisPipeline {
|
|
17751
17838
|
passes = [];
|
|
17752
17839
|
add(pass) {
|
|
@@ -17793,7 +17880,7 @@ class AnalysisPipeline {
|
|
|
17793
17880
|
return { results, findings };
|
|
17794
17881
|
}
|
|
17795
17882
|
}
|
|
17796
|
-
//
|
|
17883
|
+
// ../circle-ir/dist/analysis/taint-propagation.js
|
|
17797
17884
|
function buildSanitizersByLine(sanitizers) {
|
|
17798
17885
|
const out2 = new Map;
|
|
17799
17886
|
for (const san of sanitizers) {
|
|
@@ -18068,7 +18155,7 @@ function checkSanitized(fromLine, toLine, sinkType, sanitizersByLine, ctx) {
|
|
|
18068
18155
|
function buildTaintFlow(source, sink, taintInfo) {
|
|
18069
18156
|
const path = [];
|
|
18070
18157
|
path.push({
|
|
18071
|
-
variable: taintInfo.variable,
|
|
18158
|
+
variable: source.variable ?? taintInfo.variable,
|
|
18072
18159
|
line: source.line,
|
|
18073
18160
|
type: "source",
|
|
18074
18161
|
description: `Tainted data enters via ${source.type}`
|
|
@@ -18095,7 +18182,7 @@ function buildTaintFlow(source, sink, taintInfo) {
|
|
|
18095
18182
|
confidence: taintInfo.confidence * 0.9
|
|
18096
18183
|
};
|
|
18097
18184
|
}
|
|
18098
|
-
//
|
|
18185
|
+
// ../circle-ir/dist/analysis/constant-propagation/ast-utils.js
|
|
18099
18186
|
function isKnown(cv) {
|
|
18100
18187
|
return cv.type !== "unknown";
|
|
18101
18188
|
}
|
|
@@ -18112,7 +18199,7 @@ function getNodeLine(node) {
|
|
|
18112
18199
|
return node.startPosition.row + 1;
|
|
18113
18200
|
}
|
|
18114
18201
|
|
|
18115
|
-
//
|
|
18202
|
+
// ../circle-ir/dist/analysis/constant-propagation/evaluator.js
|
|
18116
18203
|
class ExpressionEvaluator {
|
|
18117
18204
|
source;
|
|
18118
18205
|
getSymbol;
|
|
@@ -18382,7 +18469,7 @@ class ExpressionEvaluator {
|
|
|
18382
18469
|
}
|
|
18383
18470
|
}
|
|
18384
18471
|
|
|
18385
|
-
//
|
|
18472
|
+
// ../circle-ir/dist/analysis/constant-propagation/patterns.js
|
|
18386
18473
|
var TAINT_PATTERNS = [
|
|
18387
18474
|
"request.getParameter",
|
|
18388
18475
|
"request.getHeader",
|
|
@@ -18577,7 +18664,7 @@ var PROPAGATOR_METHODS = new Set([
|
|
|
18577
18664
|
"decodeRequestString"
|
|
18578
18665
|
]);
|
|
18579
18666
|
|
|
18580
|
-
//
|
|
18667
|
+
// ../circle-ir/dist/analysis/constant-propagation/propagator.js
|
|
18581
18668
|
class ConstantPropagator {
|
|
18582
18669
|
symbols = new Map;
|
|
18583
18670
|
tainted = new Set;
|
|
@@ -20434,7 +20521,7 @@ class ConstantPropagator {
|
|
|
20434
20521
|
}
|
|
20435
20522
|
}
|
|
20436
20523
|
|
|
20437
|
-
//
|
|
20524
|
+
// ../circle-ir/dist/analysis/constant-propagation/index.js
|
|
20438
20525
|
function analyzeConstantPropagation(tree, sourceCode, options = {}) {
|
|
20439
20526
|
const propagator = new ConstantPropagator;
|
|
20440
20527
|
return propagator.analyze(tree, sourceCode, options.additionalTaintPatterns ?? [], options.sanitizerMethods ?? [], options.taintedParameters ?? []);
|
|
@@ -20522,7 +20609,7 @@ function normalizeCondition(cond) {
|
|
|
20522
20609
|
}
|
|
20523
20610
|
return normalized;
|
|
20524
20611
|
}
|
|
20525
|
-
//
|
|
20612
|
+
// ../circle-ir/dist/utils/logger.js
|
|
20526
20613
|
var LOG_LEVELS = {
|
|
20527
20614
|
trace: 0,
|
|
20528
20615
|
debug: 1,
|
|
@@ -20594,7 +20681,7 @@ var logger = {
|
|
|
20594
20681
|
}
|
|
20595
20682
|
};
|
|
20596
20683
|
|
|
20597
|
-
//
|
|
20684
|
+
// ../circle-ir/dist/analysis/per-file-finding-cap.js
|
|
20598
20685
|
var DEFAULT_PER_FILE_FINDING_CAP = 1000;
|
|
20599
20686
|
var SATURATED_FILE_RULE_ID = "saturated-file";
|
|
20600
20687
|
function applyPerFileFindingCap(filePath, findings, cap) {
|
|
@@ -20630,7 +20717,7 @@ function applyPerFileFindingCap(filePath, findings, cap) {
|
|
|
20630
20717
|
return [advisory];
|
|
20631
20718
|
}
|
|
20632
20719
|
|
|
20633
|
-
//
|
|
20720
|
+
// ../circle-ir/dist/analysis/confidence-filter.js
|
|
20634
20721
|
function applyConfidenceFilter(findings, includeSpeculative) {
|
|
20635
20722
|
if (includeSpeculative)
|
|
20636
20723
|
return findings;
|
|
@@ -20640,7 +20727,7 @@ function isHighConfidence(finding) {
|
|
|
20640
20727
|
return finding.confidence === undefined || finding.confidence === "high";
|
|
20641
20728
|
}
|
|
20642
20729
|
|
|
20643
|
-
//
|
|
20730
|
+
// ../circle-ir/dist/analysis/library-api-surface-downgrade.js
|
|
20644
20731
|
var LIBRARY_API_SURFACE_TAG = "library-api-surface:caller-responsibility";
|
|
20645
20732
|
function applyLibraryApiSurfaceDowngrade(findings) {
|
|
20646
20733
|
return findings.map((f) => {
|
|
@@ -20657,7 +20744,7 @@ function applyLibraryApiSurfaceDowngrade(findings) {
|
|
|
20657
20744
|
});
|
|
20658
20745
|
}
|
|
20659
20746
|
|
|
20660
|
-
//
|
|
20747
|
+
// ../circle-ir/dist/analysis/note-coalescer.js
|
|
20661
20748
|
var CLICKJACKING_PAIR = new Set(["missing-x-frame-options", "missing-csp-frame-ancestors"]);
|
|
20662
20749
|
function levelRank(level) {
|
|
20663
20750
|
return level === "error" ? 0 : level === "warning" ? 1 : 2;
|
|
@@ -20721,7 +20808,7 @@ function coalesceNoteLevelFindings(findings) {
|
|
|
20721
20808
|
return out2;
|
|
20722
20809
|
}
|
|
20723
20810
|
|
|
20724
|
-
//
|
|
20811
|
+
// ../circle-ir/dist/analysis/entry-point-detection.js
|
|
20725
20812
|
var TIER_1_METHOD_ANNOTATIONS = new Set([
|
|
20726
20813
|
"RequestMapping",
|
|
20727
20814
|
"GetMapping",
|
|
@@ -21378,7 +21465,7 @@ function methodIsRuntimeRegistrationHandler(method, regs) {
|
|
|
21378
21465
|
return false;
|
|
21379
21466
|
}
|
|
21380
21467
|
|
|
21381
|
-
//
|
|
21468
|
+
// ../circle-ir/dist/analysis/require-entry-path.js
|
|
21382
21469
|
var RULE_ID_REQUIRE_ENTRY_PATH = "require-entry-path";
|
|
21383
21470
|
var MAX_VISITED_METHODS = 2000;
|
|
21384
21471
|
var TAINT_FLOW_RULE_IDS = new Set([
|
|
@@ -21767,7 +21854,7 @@ function normalizeDisabled(input) {
|
|
|
21767
21854
|
return new Set(input);
|
|
21768
21855
|
}
|
|
21769
21856
|
|
|
21770
|
-
//
|
|
21857
|
+
// ../circle-ir/dist/analysis/project-profile-transform.js
|
|
21771
21858
|
var DOWNGRADE_ELIGIBLE_RULE_IDS = new Set([
|
|
21772
21859
|
"code_injection",
|
|
21773
21860
|
"template_injection",
|
|
@@ -21829,7 +21916,7 @@ function applyProjectProfileTransform(findings, resolveProfile) {
|
|
|
21829
21916
|
});
|
|
21830
21917
|
}
|
|
21831
21918
|
|
|
21832
|
-
//
|
|
21919
|
+
// ../circle-ir/dist/languages/registry.js
|
|
21833
21920
|
class DefaultLanguageRegistry {
|
|
21834
21921
|
plugins = new Map;
|
|
21835
21922
|
extensionMap = new Map;
|
|
@@ -21876,7 +21963,7 @@ function registerLanguage(plugin) {
|
|
|
21876
21963
|
function getLanguagePlugin(language) {
|
|
21877
21964
|
return getLanguageRegistry().get(language);
|
|
21878
21965
|
}
|
|
21879
|
-
//
|
|
21966
|
+
// ../circle-ir/dist/languages/plugins/base.js
|
|
21880
21967
|
class BaseLanguagePlugin {
|
|
21881
21968
|
parser = null;
|
|
21882
21969
|
async initialize(parser) {
|
|
@@ -21937,7 +22024,7 @@ class BaseLanguagePlugin {
|
|
|
21937
22024
|
}
|
|
21938
22025
|
}
|
|
21939
22026
|
|
|
21940
|
-
//
|
|
22027
|
+
// ../circle-ir/dist/languages/plugins/java.js
|
|
21941
22028
|
class JavaPlugin extends BaseLanguagePlugin {
|
|
21942
22029
|
id = "java";
|
|
21943
22030
|
name = "Java";
|
|
@@ -22194,7 +22281,7 @@ class JavaPlugin extends BaseLanguagePlugin {
|
|
|
22194
22281
|
}
|
|
22195
22282
|
}
|
|
22196
22283
|
|
|
22197
|
-
//
|
|
22284
|
+
// ../circle-ir/dist/languages/plugins/javascript.js
|
|
22198
22285
|
class JavaScriptPlugin extends BaseLanguagePlugin {
|
|
22199
22286
|
id = "javascript";
|
|
22200
22287
|
name = "JavaScript/TypeScript";
|
|
@@ -22860,7 +22947,7 @@ class JavaScriptPlugin extends BaseLanguagePlugin {
|
|
|
22860
22947
|
}
|
|
22861
22948
|
}
|
|
22862
22949
|
|
|
22863
|
-
//
|
|
22950
|
+
// ../circle-ir/dist/languages/plugins/python.js
|
|
22864
22951
|
class PythonPlugin extends BaseLanguagePlugin {
|
|
22865
22952
|
id = "python";
|
|
22866
22953
|
name = "Python";
|
|
@@ -23136,7 +23223,7 @@ class PythonPlugin extends BaseLanguagePlugin {
|
|
|
23136
23223
|
}
|
|
23137
23224
|
}
|
|
23138
23225
|
|
|
23139
|
-
//
|
|
23226
|
+
// ../circle-ir/dist/languages/plugins/rust.js
|
|
23140
23227
|
class RustPlugin extends BaseLanguagePlugin {
|
|
23141
23228
|
id = "rust";
|
|
23142
23229
|
name = "Rust";
|
|
@@ -23369,7 +23456,7 @@ class RustPlugin extends BaseLanguagePlugin {
|
|
|
23369
23456
|
}
|
|
23370
23457
|
}
|
|
23371
23458
|
|
|
23372
|
-
//
|
|
23459
|
+
// ../circle-ir/dist/languages/plugins/bash.js
|
|
23373
23460
|
class BashPlugin extends BaseLanguagePlugin {
|
|
23374
23461
|
id = "bash";
|
|
23375
23462
|
name = "Bash/Shell";
|
|
@@ -23575,7 +23662,7 @@ class BashPlugin extends BaseLanguagePlugin {
|
|
|
23575
23662
|
}
|
|
23576
23663
|
}
|
|
23577
23664
|
|
|
23578
|
-
//
|
|
23665
|
+
// ../circle-ir/dist/languages/plugins/html.js
|
|
23579
23666
|
class HtmlPlugin extends BaseLanguagePlugin {
|
|
23580
23667
|
id = "html";
|
|
23581
23668
|
name = "HTML";
|
|
@@ -23640,7 +23727,7 @@ class HtmlPlugin extends BaseLanguagePlugin {
|
|
|
23640
23727
|
}
|
|
23641
23728
|
}
|
|
23642
23729
|
|
|
23643
|
-
//
|
|
23730
|
+
// ../circle-ir/dist/languages/plugins/vue.js
|
|
23644
23731
|
class VuePlugin extends BaseLanguagePlugin {
|
|
23645
23732
|
id = "vue";
|
|
23646
23733
|
name = "Vue";
|
|
@@ -23705,7 +23792,7 @@ class VuePlugin extends BaseLanguagePlugin {
|
|
|
23705
23792
|
}
|
|
23706
23793
|
}
|
|
23707
23794
|
|
|
23708
|
-
//
|
|
23795
|
+
// ../circle-ir/dist/languages/plugins/go.js
|
|
23709
23796
|
class GoPlugin extends BaseLanguagePlugin {
|
|
23710
23797
|
id = "go";
|
|
23711
23798
|
name = "Go";
|
|
@@ -23930,6 +24017,54 @@ class GoPlugin extends BaseLanguagePlugin {
|
|
|
23930
24017
|
severity: "high",
|
|
23931
24018
|
argPositions: [0]
|
|
23932
24019
|
},
|
|
24020
|
+
{
|
|
24021
|
+
method: "Create",
|
|
24022
|
+
class: "os",
|
|
24023
|
+
type: "path_traversal",
|
|
24024
|
+
cwe: "CWE-22",
|
|
24025
|
+
severity: "high",
|
|
24026
|
+
argPositions: [0]
|
|
24027
|
+
},
|
|
24028
|
+
{
|
|
24029
|
+
method: "OpenFile",
|
|
24030
|
+
class: "os",
|
|
24031
|
+
type: "path_traversal",
|
|
24032
|
+
cwe: "CWE-22",
|
|
24033
|
+
severity: "high",
|
|
24034
|
+
argPositions: [0]
|
|
24035
|
+
},
|
|
24036
|
+
{
|
|
24037
|
+
method: "Remove",
|
|
24038
|
+
class: "os",
|
|
24039
|
+
type: "path_traversal",
|
|
24040
|
+
cwe: "CWE-22",
|
|
24041
|
+
severity: "high",
|
|
24042
|
+
argPositions: [0]
|
|
24043
|
+
},
|
|
24044
|
+
{
|
|
24045
|
+
method: "RemoveAll",
|
|
24046
|
+
class: "os",
|
|
24047
|
+
type: "path_traversal",
|
|
24048
|
+
cwe: "CWE-22",
|
|
24049
|
+
severity: "high",
|
|
24050
|
+
argPositions: [0]
|
|
24051
|
+
},
|
|
24052
|
+
{
|
|
24053
|
+
method: "ReadFile",
|
|
24054
|
+
class: "ioutil",
|
|
24055
|
+
type: "path_traversal",
|
|
24056
|
+
cwe: "CWE-22",
|
|
24057
|
+
severity: "high",
|
|
24058
|
+
argPositions: [0]
|
|
24059
|
+
},
|
|
24060
|
+
{
|
|
24061
|
+
method: "WriteFile",
|
|
24062
|
+
class: "ioutil",
|
|
24063
|
+
type: "path_traversal",
|
|
24064
|
+
cwe: "CWE-22",
|
|
24065
|
+
severity: "high",
|
|
24066
|
+
argPositions: [0]
|
|
24067
|
+
},
|
|
23933
24068
|
{
|
|
23934
24069
|
method: "Fprintf",
|
|
23935
24070
|
class: "fmt",
|
|
@@ -24354,7 +24489,7 @@ class GoPlugin extends BaseLanguagePlugin {
|
|
|
24354
24489
|
}
|
|
24355
24490
|
}
|
|
24356
24491
|
|
|
24357
|
-
//
|
|
24492
|
+
// ../circle-ir/dist/languages/plugins/csharp.js
|
|
24358
24493
|
class CSharpPlugin extends BaseLanguagePlugin {
|
|
24359
24494
|
id = "csharp";
|
|
24360
24495
|
name = "C#";
|
|
@@ -24413,7 +24548,7 @@ class CSharpPlugin extends BaseLanguagePlugin {
|
|
|
24413
24548
|
}
|
|
24414
24549
|
}
|
|
24415
24550
|
|
|
24416
|
-
//
|
|
24551
|
+
// ../circle-ir/dist/languages/plugins/index.js
|
|
24417
24552
|
function registerBuiltinPlugins() {
|
|
24418
24553
|
registerLanguage(new JavaPlugin);
|
|
24419
24554
|
registerLanguage(new JavaScriptPlugin);
|
|
@@ -24425,7 +24560,7 @@ function registerBuiltinPlugins() {
|
|
|
24425
24560
|
registerLanguage(new GoPlugin);
|
|
24426
24561
|
registerLanguage(new CSharpPlugin);
|
|
24427
24562
|
}
|
|
24428
|
-
//
|
|
24563
|
+
// ../circle-ir/dist/analysis/passes/cross-file-pass.js
|
|
24429
24564
|
class CrossFilePass {
|
|
24430
24565
|
run(projectGraph, sourceLines, options = {}) {
|
|
24431
24566
|
const resolver = projectGraph.resolver;
|
|
@@ -24436,7 +24571,8 @@ class CrossFilePass {
|
|
|
24436
24571
|
logger.info("cross-file: starting", { files: fileCount, budgetMs });
|
|
24437
24572
|
const phase1Start = Date.now();
|
|
24438
24573
|
logger.debug("cross-file: phase 1/4 starting (findCrossFileTaintFlows)");
|
|
24439
|
-
const flows = resolver.findCrossFileTaintFlows();
|
|
24574
|
+
const flows = resolver.findCrossFileTaintFlows(budgetExceeded);
|
|
24575
|
+
let phase1Truncated = budgetExceeded();
|
|
24440
24576
|
logger.info("cross-file: phase 1/4 done", {
|
|
24441
24577
|
flows: flows.length,
|
|
24442
24578
|
elapsedMs: Date.now() - phase1Start
|
|
@@ -24486,7 +24622,7 @@ class CrossFilePass {
|
|
|
24486
24622
|
confidence: 0.7
|
|
24487
24623
|
}];
|
|
24488
24624
|
});
|
|
24489
|
-
let exceeded =
|
|
24625
|
+
let exceeded = phase1Truncated;
|
|
24490
24626
|
const ipPaths = [];
|
|
24491
24627
|
if (budgetExceeded()) {
|
|
24492
24628
|
exceeded = true;
|
|
@@ -24498,7 +24634,7 @@ class CrossFilePass {
|
|
|
24498
24634
|
} else {
|
|
24499
24635
|
const phase2Start = Date.now();
|
|
24500
24636
|
logger.debug("cross-file: phase 2/4 starting (findInterproceduralTaintPaths)");
|
|
24501
|
-
const phase2 = resolver.findInterproceduralTaintPaths();
|
|
24637
|
+
const phase2 = resolver.findInterproceduralTaintPaths(budgetExceeded);
|
|
24502
24638
|
ipPaths.push(...phase2);
|
|
24503
24639
|
logger.info("cross-file: phase 2/4 done", {
|
|
24504
24640
|
paths: phase2.length,
|
|
@@ -24515,7 +24651,7 @@ class CrossFilePass {
|
|
|
24515
24651
|
} else if (!exceeded) {
|
|
24516
24652
|
const phase3Start = Date.now();
|
|
24517
24653
|
logger.debug("cross-file: phase 3/4 starting (findFieldBindingTaintPaths)");
|
|
24518
|
-
const phase3 = resolver.findFieldBindingTaintPaths();
|
|
24654
|
+
const phase3 = resolver.findFieldBindingTaintPaths(budgetExceeded);
|
|
24519
24655
|
ipPaths.push(...phase3);
|
|
24520
24656
|
logger.info("cross-file: phase 3/4 done", {
|
|
24521
24657
|
paths: phase3.length,
|
|
@@ -24751,7 +24887,7 @@ function findCrossInstanceAliasingPaths(projectGraph, _sourceLines) {
|
|
|
24751
24887
|
return paths;
|
|
24752
24888
|
}
|
|
24753
24889
|
|
|
24754
|
-
//
|
|
24890
|
+
// ../circle-ir/dist/analysis/html/html-extractor.js
|
|
24755
24891
|
var EVENT_HANDLER_ATTRS = new Set([
|
|
24756
24892
|
"onclick",
|
|
24757
24893
|
"ondblclick",
|
|
@@ -24906,7 +25042,7 @@ function stripQuotes2(text) {
|
|
|
24906
25042
|
return text;
|
|
24907
25043
|
}
|
|
24908
25044
|
|
|
24909
|
-
//
|
|
25045
|
+
// ../circle-ir/dist/analysis/html/html-attribute-security-pass.js
|
|
24910
25046
|
function runHtmlAttributeSecurityChecks(rootNode, filePath) {
|
|
24911
25047
|
const findings = [];
|
|
24912
25048
|
walkForSecurityChecks(rootNode, filePath, findings);
|
|
@@ -25132,7 +25268,7 @@ function truncate(s, maxLen) {
|
|
|
25132
25268
|
return s.length > maxLen ? s.slice(0, maxLen) + "..." : s;
|
|
25133
25269
|
}
|
|
25134
25270
|
|
|
25135
|
-
//
|
|
25271
|
+
// ../circle-ir/dist/analysis/html/vue-template-xss-pass.js
|
|
25136
25272
|
var DANGEROUS_BINDINGS = new Set([
|
|
25137
25273
|
"v-html",
|
|
25138
25274
|
"v-bind:innerhtml",
|
|
@@ -25252,7 +25388,7 @@ function collectTaintedNames(blocks) {
|
|
|
25252
25388
|
return names;
|
|
25253
25389
|
}
|
|
25254
25390
|
|
|
25255
|
-
//
|
|
25391
|
+
// ../circle-ir/dist/analysis/html/html-merge.js
|
|
25256
25392
|
function mergeHtmlResults(htmlMeta, scriptResults, attributeFindings) {
|
|
25257
25393
|
const allTypes = [];
|
|
25258
25394
|
const allCalls = [];
|
|
@@ -25402,7 +25538,7 @@ function mergeHtmlResults(htmlMeta, scriptResults, attributeFindings) {
|
|
|
25402
25538
|
};
|
|
25403
25539
|
}
|
|
25404
25540
|
|
|
25405
|
-
//
|
|
25541
|
+
// ../circle-ir/dist/analysis/passes/taint-matcher-pass.js
|
|
25406
25542
|
class TaintMatcherPass {
|
|
25407
25543
|
name = "taint-matcher";
|
|
25408
25544
|
category = "security";
|
|
@@ -25463,7 +25599,7 @@ class TaintMatcherPass {
|
|
|
25463
25599
|
}
|
|
25464
25600
|
}
|
|
25465
25601
|
|
|
25466
|
-
//
|
|
25602
|
+
// ../circle-ir/dist/analysis/passes/constant-propagation-pass.js
|
|
25467
25603
|
class ConstantPropagationPass {
|
|
25468
25604
|
tree;
|
|
25469
25605
|
name = "constant-propagation";
|
|
@@ -25493,7 +25629,7 @@ class ConstantPropagationPass {
|
|
|
25493
25629
|
}
|
|
25494
25630
|
}
|
|
25495
25631
|
|
|
25496
|
-
//
|
|
25632
|
+
// ../circle-ir/dist/analysis/passes/language-sources-pass.js
|
|
25497
25633
|
var JS_DOM_XSS_SINKS = [
|
|
25498
25634
|
{ pattern: /\.innerHTML\s*=/, type: "xss", cwe: "CWE-79", severity: "critical" },
|
|
25499
25635
|
{ pattern: /\.outerHTML\s*=/, type: "xss", cwe: "CWE-79", severity: "critical" },
|
|
@@ -25611,6 +25747,8 @@ class LanguageSourcesPass {
|
|
|
25611
25747
|
additionalSources.push(...findCSharpBindingAttributeSources(code, language));
|
|
25612
25748
|
additionalSources.push(...findCSharpMinimalApiSources(code, language));
|
|
25613
25749
|
additionalSources.push(...findGoArgvSources(code, language));
|
|
25750
|
+
additionalSources.push(...findGoArchiveEntrySources(code, language));
|
|
25751
|
+
additionalSources.push(...findGoMultipartUploadSources(code, language));
|
|
25614
25752
|
const jsDOMSinks = findJavaScriptDOMSinks(code, language);
|
|
25615
25753
|
for (const s of jsDOMSinks) {
|
|
25616
25754
|
const alreadyExists = additionalSinks.some((x) => x.line === s.line && x.cwe === s.cwe);
|
|
@@ -25681,6 +25819,7 @@ class LanguageSourcesPass {
|
|
|
25681
25819
|
if (language === "go") {
|
|
25682
25820
|
additionalSanitizers.push(...findGoMapAllowlistGuardSanitizers(code));
|
|
25683
25821
|
additionalSanitizers.push(...findGoHtmlTemplateImportSanitizers(code));
|
|
25822
|
+
additionalSanitizers.push(...findGoPathContainmentGuardSanitizers(code));
|
|
25684
25823
|
const goMisconfigFindings = findGoPatternFindings(code, graph.ir.meta.file);
|
|
25685
25824
|
for (const finding of goMisconfigFindings) {
|
|
25686
25825
|
ctx.addFinding(finding);
|
|
@@ -25718,6 +25857,7 @@ class LanguageSourcesPass {
|
|
|
25718
25857
|
additionalSanitizers.push(...findPythonUrlAllowlistRedirectSanitizers(code));
|
|
25719
25858
|
additionalSanitizers.push(...findPythonDefusedXmlSanitizers(code));
|
|
25720
25859
|
additionalSanitizers.push(...findPythonJinjaAutoescapeSanitizers(code));
|
|
25860
|
+
additionalSanitizers.push(...findCrlfWrapperFunctionSanitizers(code, "python"));
|
|
25721
25861
|
const pyMisconfigFindings = findPythonPatternFindings(code, graph.ir.meta.file);
|
|
25722
25862
|
for (const finding of pyMisconfigFindings) {
|
|
25723
25863
|
ctx.addFinding(finding);
|
|
@@ -25821,12 +25961,16 @@ class LanguageSourcesPass {
|
|
|
25821
25961
|
ctx.addFinding(finding);
|
|
25822
25962
|
}
|
|
25823
25963
|
}
|
|
25964
|
+
if (language === "csharp") {
|
|
25965
|
+
additionalSanitizers.push(...findCSharpFullPathStartsWithGuardSanitizers(code));
|
|
25966
|
+
}
|
|
25824
25967
|
if (language === "java") {
|
|
25825
25968
|
additionalSanitizers.push(...findJavaSafeJsonParseSanitizers(code));
|
|
25826
25969
|
additionalSanitizers.push(...findJavaPathNormalizeStartsWithGuardSanitizers(code));
|
|
25827
25970
|
additionalSanitizers.push(...findJavaPathGetFileNameSanitizers(code));
|
|
25828
25971
|
additionalSanitizers.push(...findJavaCanonicalPathStartsWithGuardSanitizers(code));
|
|
25829
25972
|
additionalSanitizers.push(...findJavaInlineCrlfStripLogSanitizers(code));
|
|
25973
|
+
additionalSanitizers.push(...findCrlfWrapperFunctionSanitizers(code, "java"));
|
|
25830
25974
|
additionalSanitizers.push(...findJavaArgvFormExecSanitizers(code));
|
|
25831
25975
|
for (const finding of findJavaPatternFindings(code, graph.ir.meta.file)) {
|
|
25832
25976
|
ctx.addFinding(finding);
|
|
@@ -26242,13 +26386,121 @@ function findGoArgvSources(sourceCode, language) {
|
|
|
26242
26386
|
}
|
|
26243
26387
|
return sources;
|
|
26244
26388
|
}
|
|
26389
|
+
function findGoArchiveEntrySources(sourceCode, language) {
|
|
26390
|
+
if (language !== "go")
|
|
26391
|
+
return [];
|
|
26392
|
+
if (!/\bimport\b[\s\S]{0,400}?archive\/(?:zip|tar)|"archive\/(?:zip|tar)"/.test(sourceCode))
|
|
26393
|
+
return [];
|
|
26394
|
+
const sources = [];
|
|
26395
|
+
const lines = sourceCode.split(`
|
|
26396
|
+
`);
|
|
26397
|
+
const entryVars = new Set;
|
|
26398
|
+
const zipRange = /\bfor\b[^;{]*?,\s*([A-Za-z_]\w*)\s*:?=\s*range\s+[A-Za-z_][\w.]*\.File\b/;
|
|
26399
|
+
const tarNext = /\b([A-Za-z_]\w*)\s*,\s*[A-Za-z_]\w*\s*:?=\s*[A-Za-z_][\w.]*\.Next\s*\(\s*\)/;
|
|
26400
|
+
for (const line of lines) {
|
|
26401
|
+
const z = zipRange.exec(line);
|
|
26402
|
+
if (z)
|
|
26403
|
+
entryVars.add(z[1]);
|
|
26404
|
+
const t = tarNext.exec(line);
|
|
26405
|
+
if (t)
|
|
26406
|
+
entryVars.add(t[1]);
|
|
26407
|
+
}
|
|
26408
|
+
if (entryVars.size === 0)
|
|
26409
|
+
return sources;
|
|
26410
|
+
const assignRe = /^\s*(?:var\s+)?([A-Za-z_]\w*)\s*(?::?=|=)\s*(.+?)\s*$/;
|
|
26411
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
26412
|
+
const m = assignRe.exec(lines[i2]);
|
|
26413
|
+
if (!m)
|
|
26414
|
+
continue;
|
|
26415
|
+
const [, lhs, rhs] = m;
|
|
26416
|
+
let matched = null;
|
|
26417
|
+
for (const v of entryVars) {
|
|
26418
|
+
if (new RegExp(`(?<![\\w.])${v}\\s*\\.\\s*Name\\b`).test(rhs)) {
|
|
26419
|
+
matched = v;
|
|
26420
|
+
break;
|
|
26421
|
+
}
|
|
26422
|
+
}
|
|
26423
|
+
if (!matched)
|
|
26424
|
+
continue;
|
|
26425
|
+
const lineNumber = i2 + 1;
|
|
26426
|
+
if (sources.some((sc) => sc.line === lineNumber && sc.variable === lhs))
|
|
26427
|
+
continue;
|
|
26428
|
+
sources.push({
|
|
26429
|
+
type: "file_input",
|
|
26430
|
+
location: `${lhs} derived from archive entry name ${matched}.Name (Zip/Tar Slip)`,
|
|
26431
|
+
severity: "high",
|
|
26432
|
+
line: lineNumber,
|
|
26433
|
+
confidence: 0.9,
|
|
26434
|
+
variable: lhs
|
|
26435
|
+
});
|
|
26436
|
+
}
|
|
26437
|
+
return sources;
|
|
26438
|
+
}
|
|
26439
|
+
function findGoMultipartUploadSources(sourceCode, language) {
|
|
26440
|
+
if (language !== "go")
|
|
26441
|
+
return [];
|
|
26442
|
+
if (!/\.\s*(?:FormFile|MultipartForm|MultipartReader)\b/.test(sourceCode))
|
|
26443
|
+
return [];
|
|
26444
|
+
const sources = [];
|
|
26445
|
+
const lines = sourceCode.split(`
|
|
26446
|
+
`);
|
|
26447
|
+
const headerVars = new Set;
|
|
26448
|
+
const formFileRe = /\b[A-Za-z_]\w*\s*,\s*([A-Za-z_]\w*)\s*(?:,\s*[A-Za-z_]\w*\s*)?:?=\s*[A-Za-z_][\w.]*\.\s*FormFile\s*\(/;
|
|
26449
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
26450
|
+
const m = formFileRe.exec(lines[i2]);
|
|
26451
|
+
if (!m)
|
|
26452
|
+
continue;
|
|
26453
|
+
const v = m[1];
|
|
26454
|
+
if (v === "_")
|
|
26455
|
+
continue;
|
|
26456
|
+
headerVars.add(v);
|
|
26457
|
+
sources.push({
|
|
26458
|
+
type: "http_param",
|
|
26459
|
+
location: `${v}.Filename from r.FormFile (client-supplied upload filename)`,
|
|
26460
|
+
severity: "high",
|
|
26461
|
+
line: i2 + 1,
|
|
26462
|
+
confidence: 0.9,
|
|
26463
|
+
variable: v
|
|
26464
|
+
});
|
|
26465
|
+
}
|
|
26466
|
+
const assignRe = /^\s*(?:var\s+)?([A-Za-z_]\w*)\s*(?::?=|=)\s*(.+?)\s*$/;
|
|
26467
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
26468
|
+
const m = assignRe.exec(lines[i2]);
|
|
26469
|
+
if (!m)
|
|
26470
|
+
continue;
|
|
26471
|
+
const [, lhs, rhs] = m;
|
|
26472
|
+
if (lhs === "_")
|
|
26473
|
+
continue;
|
|
26474
|
+
let matched = null;
|
|
26475
|
+
for (const v of headerVars) {
|
|
26476
|
+
if (new RegExp(`(?<![\\w.])${v}\\s*\\.\\s*Filename\\b`).test(rhs)) {
|
|
26477
|
+
matched = v;
|
|
26478
|
+
break;
|
|
26479
|
+
}
|
|
26480
|
+
}
|
|
26481
|
+
if (!matched)
|
|
26482
|
+
continue;
|
|
26483
|
+
const lineNumber = i2 + 1;
|
|
26484
|
+
if (sources.some((sc) => sc.line === lineNumber && sc.variable === lhs))
|
|
26485
|
+
continue;
|
|
26486
|
+
sources.push({
|
|
26487
|
+
type: "http_param",
|
|
26488
|
+
location: `${lhs} derived from upload filename ${matched}.Filename`,
|
|
26489
|
+
severity: "high",
|
|
26490
|
+
line: lineNumber,
|
|
26491
|
+
confidence: 0.9,
|
|
26492
|
+
variable: lhs
|
|
26493
|
+
});
|
|
26494
|
+
}
|
|
26495
|
+
return sources;
|
|
26496
|
+
}
|
|
26245
26497
|
function findCSharpRequestSources(sourceCode, language) {
|
|
26246
26498
|
if (language !== "csharp")
|
|
26247
26499
|
return [];
|
|
26248
26500
|
const sources = [];
|
|
26249
26501
|
const lines = sourceCode.split(`
|
|
26250
26502
|
`);
|
|
26251
|
-
const assignRe = /^\s*(?:var\s+|[A-Za-z_][\w.<>\[\]]*\s+)?([A-Za-z_]\w*)\s*=\s*(.+?);?\s*$/;
|
|
26503
|
+
const assignRe = /^\s*(?:await\s+)?(?:using\s*\(?\s*)?(?:var\s+|[A-Za-z_][\w.<>\[\]]*\s+)?([A-Za-z_]\w*)\s*=\s*(.+?);?\s*$/;
|
|
26252
26504
|
const requestReadRe = /\bRequest\s*\.\s*(?:Query|Form|Headers|Cookies|QueryString|RouteValues|Body|Files|Params)\b/;
|
|
26253
26505
|
const consoleReadRe = /\bConsole\s*\.\s*ReadLine\s*\(/;
|
|
26254
26506
|
const envReadRe = /\bEnvironment\s*\.\s*GetEnvironmentVariables?\s*(?:\(|\[)/;
|
|
@@ -26954,6 +27206,12 @@ function findPythonReflectionInvocationSinks(sourceCode, taintedVars) {
|
|
|
26954
27206
|
}
|
|
26955
27207
|
return sinks;
|
|
26956
27208
|
}
|
|
27209
|
+
function isProvablyLiteralDomAssignment(line) {
|
|
27210
|
+
const eq = line.indexOf("=");
|
|
27211
|
+
if (eq < 0)
|
|
27212
|
+
return false;
|
|
27213
|
+
return isProvablyLiteralExpression(line.slice(eq + 1));
|
|
27214
|
+
}
|
|
26957
27215
|
function findJavaScriptDOMSinks(sourceCode, language) {
|
|
26958
27216
|
if (!["javascript", "typescript"].includes(language))
|
|
26959
27217
|
return [];
|
|
@@ -26982,6 +27240,9 @@ function findJavaScriptDOMSinks(sourceCode, language) {
|
|
|
26982
27240
|
method = "cssText";
|
|
26983
27241
|
else if (line.includes("style.textContent"))
|
|
26984
27242
|
method = "textContent";
|
|
27243
|
+
if (DOM_ASSIGNMENT_SINK_METHODS.has(method) && isProvablyLiteralDomAssignment(line)) {
|
|
27244
|
+
continue;
|
|
27245
|
+
}
|
|
26985
27246
|
if (method === "document.write" || method === "document.writeln") {
|
|
26986
27247
|
const argMatch = line.match(/document\.write(?:ln)?\s*\(\s*([^)]*)\)/);
|
|
26987
27248
|
if (argMatch) {
|
|
@@ -27747,6 +28008,47 @@ function findGoMapAllowlistGuardSanitizers(code) {
|
|
|
27747
28008
|
}
|
|
27748
28009
|
return sanitizers;
|
|
27749
28010
|
}
|
|
28011
|
+
function findGoPathContainmentGuardSanitizers(code) {
|
|
28012
|
+
const sanitizers = [];
|
|
28013
|
+
const lines = code.split(`
|
|
28014
|
+
`);
|
|
28015
|
+
const REJECT = /\b(?:continue|break|return|panic|fmt\.Errorf|errors\.New)\b/;
|
|
28016
|
+
const guarded = new Map;
|
|
28017
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
28018
|
+
const line = lines[i2];
|
|
28019
|
+
const hp = /if\s*!\s*strings\s*\.\s*HasPrefix\s*\(\s*([A-Za-z_]\w*)\s*,/.exec(line);
|
|
28020
|
+
if (hp && guardRejects(lines, i2, REJECT, 4)) {
|
|
28021
|
+
if (!guarded.has(hp[1]))
|
|
28022
|
+
guarded.set(hp[1], i2 + 1);
|
|
28023
|
+
continue;
|
|
28024
|
+
}
|
|
28025
|
+
const rel = /([A-Za-z_]\w*)\s*,\s*[A-Za-z_]\w*\s*:?=\s*filepath\s*\.\s*Rel\s*\(\s*[A-Za-z_]\w*\s*,\s*([A-Za-z_]\w*)\s*\)/.exec(line);
|
|
28026
|
+
if (rel) {
|
|
28027
|
+
const window2 = lines.slice(i2, i2 + 5).join(`
|
|
28028
|
+
`);
|
|
28029
|
+
if (/\.\./.test(window2) && REJECT.test(window2)) {
|
|
28030
|
+
if (!guarded.has(rel[2]))
|
|
28031
|
+
guarded.set(rel[2], i2 + 1);
|
|
28032
|
+
}
|
|
28033
|
+
}
|
|
28034
|
+
}
|
|
28035
|
+
if (guarded.size === 0)
|
|
28036
|
+
return sanitizers;
|
|
28037
|
+
for (const [name2, guardLine] of guarded) {
|
|
28038
|
+
const useRe = new RegExp(`(?<![\\w.])${name2}(?![\\w])`);
|
|
28039
|
+
for (let l = guardLine;l < lines.length; l++) {
|
|
28040
|
+
if (!useRe.test(lines[l]))
|
|
28041
|
+
continue;
|
|
28042
|
+
sanitizers.push({
|
|
28043
|
+
type: "go_path_containment_guard",
|
|
28044
|
+
method: "strings.HasPrefix",
|
|
28045
|
+
line: l + 1,
|
|
28046
|
+
sanitizes: ["path_traversal"]
|
|
28047
|
+
});
|
|
28048
|
+
}
|
|
28049
|
+
}
|
|
28050
|
+
return sanitizers;
|
|
28051
|
+
}
|
|
27750
28052
|
function findGoHtmlTemplateImportSanitizers(code) {
|
|
27751
28053
|
const sanitizers = [];
|
|
27752
28054
|
const hasHtmlTemplate = /["\s]html\/template["\s]/.test(code);
|
|
@@ -28713,7 +29015,7 @@ function findJsPathResolveStartsWithGuardSanitizers(code) {
|
|
|
28713
29015
|
for (let l = c.line;l < Math.min(lines.length, c.line + 6); l++) {
|
|
28714
29016
|
if (!guardRe.test(lines[l]))
|
|
28715
29017
|
continue;
|
|
28716
|
-
if (
|
|
29018
|
+
if (guardRejects(lines, l, terminatorRe, 2)) {
|
|
28717
29019
|
guardLine = l + 1;
|
|
28718
29020
|
break;
|
|
28719
29021
|
}
|
|
@@ -28833,7 +29135,7 @@ function findJavaPathNormalizeStartsWithGuardSanitizers(code) {
|
|
|
28833
29135
|
for (let l = c.line;l < Math.min(lines.length, c.line + 6); l++) {
|
|
28834
29136
|
if (!guardRe.test(lines[l]))
|
|
28835
29137
|
continue;
|
|
28836
|
-
if (
|
|
29138
|
+
if (guardRejects(lines, l, terminatorRe, 2)) {
|
|
28837
29139
|
guardLine = l + 1;
|
|
28838
29140
|
break;
|
|
28839
29141
|
}
|
|
@@ -28871,18 +29173,7 @@ function findJavaCanonicalPathStartsWithGuardSanitizers(code) {
|
|
|
28871
29173
|
const m = guardRe.exec(lines[i2]);
|
|
28872
29174
|
if (!m)
|
|
28873
29175
|
continue;
|
|
28874
|
-
|
|
28875
|
-
if (!hasTerminator) {
|
|
28876
|
-
for (let j = i2 + 1;j < Math.min(lines.length, i2 + 6); j++) {
|
|
28877
|
-
if (terminatorRe.test(lines[j])) {
|
|
28878
|
-
hasTerminator = true;
|
|
28879
|
-
break;
|
|
28880
|
-
}
|
|
28881
|
-
if (lines[j].includes("}"))
|
|
28882
|
-
break;
|
|
28883
|
-
}
|
|
28884
|
-
}
|
|
28885
|
-
if (!hasTerminator)
|
|
29176
|
+
if (!guardRejects(lines, i2, terminatorRe, 6))
|
|
28886
29177
|
continue;
|
|
28887
29178
|
const guarded = new Set([m[1]]);
|
|
28888
29179
|
const mentions = (t) => {
|
|
@@ -28912,6 +29203,71 @@ function findJavaCanonicalPathStartsWithGuardSanitizers(code) {
|
|
|
28912
29203
|
}
|
|
28913
29204
|
return sanitizers;
|
|
28914
29205
|
}
|
|
29206
|
+
function guardRejects(lines, i2, terminatorRe, window2) {
|
|
29207
|
+
if (terminatorRe.test(lines[i2]))
|
|
29208
|
+
return true;
|
|
29209
|
+
const opens = (lines[i2].match(/\{/g) ?? []).length;
|
|
29210
|
+
const closes = (lines[i2].match(/\}/g) ?? []).length;
|
|
29211
|
+
if (opens > 0 && closes >= opens)
|
|
29212
|
+
return false;
|
|
29213
|
+
for (let j = i2 + 1;j < Math.min(lines.length, i2 + window2); j++) {
|
|
29214
|
+
if (terminatorRe.test(lines[j]))
|
|
29215
|
+
return true;
|
|
29216
|
+
if (lines[j].includes("}"))
|
|
29217
|
+
return false;
|
|
29218
|
+
}
|
|
29219
|
+
return false;
|
|
29220
|
+
}
|
|
29221
|
+
function findCSharpFullPathStartsWithGuardSanitizers(code) {
|
|
29222
|
+
const sanitizers = [];
|
|
29223
|
+
const lines = code.split(`
|
|
29224
|
+
`);
|
|
29225
|
+
const assignRe = /^\s*(?:(?:var|string)\s+)?([A-Za-z_]\w*)\s*=(?!=)\s*(.*)$/;
|
|
29226
|
+
const fullPathRe = /\bPath\s*\.\s*GetFullPath\s*\(/;
|
|
29227
|
+
const canonicalVars = new Set;
|
|
29228
|
+
for (const line of lines) {
|
|
29229
|
+
const a = assignRe.exec(line);
|
|
29230
|
+
if (a && fullPathRe.test(a[2]))
|
|
29231
|
+
canonicalVars.add(a[1]);
|
|
29232
|
+
}
|
|
29233
|
+
if (canonicalVars.size === 0)
|
|
29234
|
+
return sanitizers;
|
|
29235
|
+
const guardRe = /\bif\s*\(\s*!\s*([A-Za-z_]\w*)\s*\.\s*StartsWith\s*\(/;
|
|
29236
|
+
const terminatorRe = /\b(throw|return)\b/;
|
|
29237
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
29238
|
+
const m = guardRe.exec(lines[i2]);
|
|
29239
|
+
if (!m || !canonicalVars.has(m[1]))
|
|
29240
|
+
continue;
|
|
29241
|
+
if (!guardRejects(lines, i2, terminatorRe, 6))
|
|
29242
|
+
continue;
|
|
29243
|
+
const guarded = new Set([m[1]]);
|
|
29244
|
+
const mentions = (t) => {
|
|
29245
|
+
for (const n of guarded)
|
|
29246
|
+
if (new RegExp(`\\b${n}\\b`).test(t))
|
|
29247
|
+
return true;
|
|
29248
|
+
return false;
|
|
29249
|
+
};
|
|
29250
|
+
for (let l = 0;l < lines.length; l++) {
|
|
29251
|
+
const lt = lines[l];
|
|
29252
|
+
const a = assignRe.exec(lt);
|
|
29253
|
+
if (a) {
|
|
29254
|
+
if (mentions(a[2]))
|
|
29255
|
+
guarded.add(a[1]);
|
|
29256
|
+
else if (a[1] !== m[1])
|
|
29257
|
+
guarded.delete(a[1]);
|
|
29258
|
+
}
|
|
29259
|
+
if (mentions(lt)) {
|
|
29260
|
+
sanitizers.push({
|
|
29261
|
+
type: "csharp_fullpath_startswith_guard",
|
|
29262
|
+
method: "GetFullPath",
|
|
29263
|
+
line: l + 1,
|
|
29264
|
+
sanitizes: ["path_traversal", "external_taint_escape"]
|
|
29265
|
+
});
|
|
29266
|
+
}
|
|
29267
|
+
}
|
|
29268
|
+
}
|
|
29269
|
+
return sanitizers;
|
|
29270
|
+
}
|
|
28915
29271
|
function findJavaPathGetFileNameSanitizers(code) {
|
|
28916
29272
|
const sanitizers = [];
|
|
28917
29273
|
const lines = code.split(`
|
|
@@ -28955,6 +29311,41 @@ function findJavaPathGetFileNameSanitizers(code) {
|
|
|
28955
29311
|
}
|
|
28956
29312
|
return sanitizers;
|
|
28957
29313
|
}
|
|
29314
|
+
function findCrlfWrapperFunctionSanitizers(code, language) {
|
|
29315
|
+
const sanitizers = [];
|
|
29316
|
+
const lines = code.split(`
|
|
29317
|
+
`);
|
|
29318
|
+
const declRe = language === "java" ? /^\s*(?:public|private|protected)?\s*(?:static\s+)?(?:final\s+)?(?:String|CharSequence)\s+([A-Za-z_]\w*)\s*\(/ : /^\s*def\s+([A-Za-z_]\w*)\s*\(/;
|
|
29319
|
+
const stripRe = language === "java" ? /\.\s*replace(?:All)?\s*\(\s*(?:"[^"]*\\[rnt]|'\\[rnt]')/ : /(?:re\s*\.\s*sub\s*\(\s*r?["'][^"']*\\[rnt]|\.\s*replace\s*\(\s*["']\\[rnt])/;
|
|
29320
|
+
const bodyWindow = 10;
|
|
29321
|
+
const wrappers = new Set;
|
|
29322
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
29323
|
+
const m = declRe.exec(lines[i2]);
|
|
29324
|
+
if (!m)
|
|
29325
|
+
continue;
|
|
29326
|
+
const body2 = lines.slice(i2, Math.min(lines.length, i2 + bodyWindow)).join(`
|
|
29327
|
+
`);
|
|
29328
|
+
if (stripRe.test(body2))
|
|
29329
|
+
wrappers.add(m[1]);
|
|
29330
|
+
}
|
|
29331
|
+
if (wrappers.size === 0)
|
|
29332
|
+
return sanitizers;
|
|
29333
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
29334
|
+
for (const name2 of wrappers) {
|
|
29335
|
+
if (declRe.test(lines[i2]) && new RegExp(`\\b${name2}\\s*\\(`).test(lines[i2]))
|
|
29336
|
+
continue;
|
|
29337
|
+
if (!new RegExp(`\\b${name2}\\s*\\(`).test(lines[i2]))
|
|
29338
|
+
continue;
|
|
29339
|
+
sanitizers.push({
|
|
29340
|
+
type: language === "java" ? "java_wrapper_crlf_strip" : "python_wrapper_crlf_strip",
|
|
29341
|
+
method: name2,
|
|
29342
|
+
line: i2 + 1,
|
|
29343
|
+
sanitizes: ["log_injection", "external_taint_escape"]
|
|
29344
|
+
});
|
|
29345
|
+
}
|
|
29346
|
+
}
|
|
29347
|
+
return sanitizers;
|
|
29348
|
+
}
|
|
28958
29349
|
function findJavaInlineCrlfStripLogSanitizers(code) {
|
|
28959
29350
|
const sanitizers = [];
|
|
28960
29351
|
const lines = code.split(`
|
|
@@ -32550,7 +32941,7 @@ function findJsTemplateInjectionSstiFindings(code, file) {
|
|
|
32550
32941
|
return findings;
|
|
32551
32942
|
}
|
|
32552
32943
|
|
|
32553
|
-
//
|
|
32944
|
+
// ../circle-ir/dist/analysis/passes/source-semantics-pass.js
|
|
32554
32945
|
var DEMO_PATH_RE = /(?:^|\/)(?:demo|example|examples|samples|integration-tests|integration_tests)(?:\/|$)/i;
|
|
32555
32946
|
var CONST_STRING_ASSIGN_RE = /^\s*(?:final\s+|static\s+final\s+)?[A-Za-z_][\w.<>\[\]]*\s+[A-Za-z_]\w*\s*=\s*"[^"]*"\s*;?\s*$/;
|
|
32556
32947
|
var STATIC_FINAL_RE = /^\s*(?:public\s+|private\s+|protected\s+)?static\s+final\s+/;
|
|
@@ -32638,7 +33029,7 @@ class SourceSemanticsPass {
|
|
|
32638
33029
|
}
|
|
32639
33030
|
}
|
|
32640
33031
|
|
|
32641
|
-
//
|
|
33032
|
+
// ../circle-ir/dist/analysis/passes/library-profile-source-gate-pass.js
|
|
32642
33033
|
var SPECULATIVE_SOURCE_TYPES = new Set([
|
|
32643
33034
|
"interprocedural_param",
|
|
32644
33035
|
"constructor_field"
|
|
@@ -32663,7 +33054,7 @@ class LibraryProfileSourceGatePass {
|
|
|
32663
33054
|
droppedByType: {}
|
|
32664
33055
|
};
|
|
32665
33056
|
}
|
|
32666
|
-
const sources = graph.ir.taint.sources;
|
|
33057
|
+
const sources = ctx.hasResult("sink-filter") ? ctx.getResult("sink-filter").sources : graph.ir.taint.sources;
|
|
32667
33058
|
if (sources.length === 0) {
|
|
32668
33059
|
return {
|
|
32669
33060
|
profile,
|
|
@@ -32673,17 +33064,12 @@ class LibraryProfileSourceGatePass {
|
|
|
32673
33064
|
};
|
|
32674
33065
|
}
|
|
32675
33066
|
const droppedByType = {};
|
|
32676
|
-
const kept = [];
|
|
32677
33067
|
for (const src of sources) {
|
|
32678
33068
|
if (SPECULATIVE_SOURCE_TYPES.has(src.type)) {
|
|
32679
33069
|
droppedByType[src.type] = (droppedByType[src.type] ?? 0) + 1;
|
|
32680
|
-
continue;
|
|
32681
33070
|
}
|
|
32682
|
-
kept.push(src);
|
|
32683
33071
|
}
|
|
32684
|
-
const dropped =
|
|
32685
|
-
sources.length = 0;
|
|
32686
|
-
sources.push(...kept);
|
|
33072
|
+
const dropped = 0;
|
|
32687
33073
|
return {
|
|
32688
33074
|
profile,
|
|
32689
33075
|
applied: true,
|
|
@@ -32693,7 +33079,7 @@ class LibraryProfileSourceGatePass {
|
|
|
32693
33079
|
}
|
|
32694
33080
|
}
|
|
32695
33081
|
|
|
32696
|
-
//
|
|
33082
|
+
// ../circle-ir/dist/analysis/passes/mybatis-annotation-sql-sink-pass.js
|
|
32697
33083
|
var MYBATIS_SQL_ANNOTATIONS = new Set([
|
|
32698
33084
|
"Select",
|
|
32699
33085
|
"Update",
|
|
@@ -32920,7 +33306,7 @@ class MyBatisAnnotationSqlSinkPass {
|
|
|
32920
33306
|
}
|
|
32921
33307
|
}
|
|
32922
33308
|
|
|
32923
|
-
//
|
|
33309
|
+
// ../circle-ir/dist/analysis/passes/sink-filter-pass.js
|
|
32924
33310
|
function escapeReSf(s) {
|
|
32925
33311
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
32926
33312
|
}
|
|
@@ -33027,7 +33413,32 @@ var PROTOCOL_CLIENT_PACKAGES = [
|
|
|
33027
33413
|
"org.eclipse.paho"
|
|
33028
33414
|
];
|
|
33029
33415
|
var OS_EXEC_RECEIVER_RE = /\b(?:Runtime|ProcessBuilder|DefaultExecutor|Executor|Exec|Launcher|ProcStarter|ProcessExecutor|RuntimeUtil)\s*[.(]/;
|
|
33416
|
+
var JAVA_STDOUT_PRINT_RE = /\bSystem\s*\.\s*(?:out|err)\s*\.\s*(?:println|print|printf|write|append)\s*\(/;
|
|
33030
33417
|
var PROCESS_BUILDER_ARGV_FORM_RE = /\bnew\s+ProcessBuilder\s*\(\s*(?:Arrays\.asList\b|List\.of\b|Collections\.singletonList\b|new\s+ArrayList\b|new\s+String\s*\[\s*\]\s*\{|"[^"]*"\s*,)/;
|
|
33418
|
+
var PROCESS_BUILDER_COMMAND_ARGV_FORM_RE = /\.\s*command\s*\(\s*(?:Arrays\.asList\b|List\.of\b|Collections\.singletonList\b|new\s+ArrayList\b|new\s+String\s*\[\s*\]\s*\{|"[^"]*"\s*,)/;
|
|
33419
|
+
var SHELL_PROGRAMS = new Set([
|
|
33420
|
+
"sh",
|
|
33421
|
+
"bash",
|
|
33422
|
+
"zsh",
|
|
33423
|
+
"ksh",
|
|
33424
|
+
"dash",
|
|
33425
|
+
"ash",
|
|
33426
|
+
"csh",
|
|
33427
|
+
"tcsh",
|
|
33428
|
+
"fish",
|
|
33429
|
+
"cmd",
|
|
33430
|
+
"command",
|
|
33431
|
+
"powershell",
|
|
33432
|
+
"pwsh"
|
|
33433
|
+
]);
|
|
33434
|
+
var ARGV_FIRST_LITERAL_RE = /(?:\bnew\s+ProcessBuilder\s*\(|\.\s*command\s*\()\s*(?:Arrays\.asList\s*\(|List\.of\s*\(|Collections\.singletonList\s*\(|new\s+ArrayList\s*(?:<[^>]*>)?\s*\(\s*(?:Arrays\.asList\s*\()?|new\s+String\s*\[\s*\]\s*\{)?\s*"([^"]*)"/;
|
|
33435
|
+
function argvFirstLiteralIsShell(lineText) {
|
|
33436
|
+
const m = ARGV_FIRST_LITERAL_RE.exec(lineText);
|
|
33437
|
+
if (!m)
|
|
33438
|
+
return false;
|
|
33439
|
+
const base = m[1].split(/[\\/]/).pop().replace(/\.exe$/i, "").toLowerCase();
|
|
33440
|
+
return SHELL_PROGRAMS.has(base);
|
|
33441
|
+
}
|
|
33031
33442
|
var JAVA_THROW_STATEMENT_RE = /^\s*throw\s+new\s+\w+(?:Exception|Error)\b[^;]*;\s*(?:\/\/.*|\/\*.*)?$/;
|
|
33032
33443
|
var JEXL_ENGINE_TYPES = new Set(["JexlEngine", "Jexl", "JxltEngine"]);
|
|
33033
33444
|
var JEXL_EXPRESSION_TYPE_RE = /(?:Jexl)?(?:Expression|Script|Template)(?:Script)?$/;
|
|
@@ -33197,10 +33608,41 @@ function jsSsrfHostGuardedLines(code) {
|
|
|
33197
33608
|
}
|
|
33198
33609
|
return covered;
|
|
33199
33610
|
}
|
|
33611
|
+
var CSHARP_ALLOWLIST_STRIP_RE = /\bRegex\s*\.\s*Replace\s*\([^,]*,\s*@?"\[\^(?:[A-Za-z0-9_\- ]|\\w|\\d|\\s)+\]"\s*,\s*@?"[A-Za-z0-9_]?"\s*\)/;
|
|
33612
|
+
function isUnwrittenLocalMapKeyRead(code, source) {
|
|
33613
|
+
if (source.type !== "plugin_param")
|
|
33614
|
+
return false;
|
|
33615
|
+
const lines = code.split(`
|
|
33616
|
+
`);
|
|
33617
|
+
const lineText = lines[source.line - 1] ?? "";
|
|
33618
|
+
const read = /\b([A-Za-z_]\w*)\s*\.\s*get\s*\(\s*"([^"]*)"\s*\)/.exec(lineText);
|
|
33619
|
+
if (!read)
|
|
33620
|
+
return false;
|
|
33621
|
+
const [, recv, key] = read;
|
|
33622
|
+
const ctorRe = new RegExp(`\\b${recv}\\s*=\\s*new\\s+(?:Hash|Tree|LinkedHash|ConcurrentHash|Concurrent|Identity|Weak)?Map\\s*(?:<[^>]*>)?\\s*\\(`);
|
|
33623
|
+
if (!lines.some((l) => ctorRe.test(l)))
|
|
33624
|
+
return false;
|
|
33625
|
+
const escapeRe2 = new RegExp(`\\w\\s*\\([^)]*(?<![\\w.])${recv}(?![\\w.])[^)]*\\)`);
|
|
33626
|
+
for (const l of lines) {
|
|
33627
|
+
if (!escapeRe2.test(l))
|
|
33628
|
+
continue;
|
|
33629
|
+
const stripped = l.replace(new RegExp(`\\b${recv}\\s*\\.\\s*\\w+\\s*\\(`, "g"), "X(");
|
|
33630
|
+
if (escapeRe2.test(stripped))
|
|
33631
|
+
return false;
|
|
33632
|
+
}
|
|
33633
|
+
const putRe = new RegExp(`\\b${recv}\\s*\\.\\s*put\\s*\\(\\s*"${key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}"`);
|
|
33634
|
+
if (lines.some((l) => putRe.test(l)))
|
|
33635
|
+
return false;
|
|
33636
|
+
return true;
|
|
33637
|
+
}
|
|
33200
33638
|
var CSHARP_SANITIZER_RES = [
|
|
33201
33639
|
{ re: /\b(?:HtmlEncode|JavaScriptStringEncode)\s*\(/, type: "xss" },
|
|
33202
33640
|
{ re: /\bHtmlEncoder\s*\.\s*Encode\s*\(/, type: "xss" },
|
|
33203
|
-
{ re: /\bPath\s*\.\s*GetFileName\s*\(/, type: "path_traversal" }
|
|
33641
|
+
{ re: /\bPath\s*\.\s*GetFileName\s*\(/, type: "path_traversal" },
|
|
33642
|
+
{ re: CSHARP_ALLOWLIST_STRIP_RE, type: "ldap_injection" },
|
|
33643
|
+
{ re: CSHARP_ALLOWLIST_STRIP_RE, type: "xpath_injection" },
|
|
33644
|
+
{ re: CSHARP_ALLOWLIST_STRIP_RE, type: "command_injection" },
|
|
33645
|
+
{ re: CSHARP_ALLOWLIST_STRIP_RE, type: "sql_injection" }
|
|
33204
33646
|
];
|
|
33205
33647
|
function csharpSanitizedVarsByType(code) {
|
|
33206
33648
|
const lines = code.split(`
|
|
@@ -33444,6 +33886,24 @@ function hasJavaImportFromPackage(packagePrefix, sourceLines) {
|
|
|
33444
33886
|
}
|
|
33445
33887
|
return false;
|
|
33446
33888
|
}
|
|
33889
|
+
function hasSameOriginLiteralPrefix(lineText) {
|
|
33890
|
+
const m = lineText.match(/\(\s*(['"`])([^'"`]*)\1\s*(?:\+|,|\))/);
|
|
33891
|
+
const prefix = m?.[2];
|
|
33892
|
+
if (prefix === undefined) {
|
|
33893
|
+
const t = lineText.match(/\(\s*`([^`$]*)\$\{/);
|
|
33894
|
+
if (!t)
|
|
33895
|
+
return false;
|
|
33896
|
+
return isSameOriginQueryPrefix(t[1]);
|
|
33897
|
+
}
|
|
33898
|
+
return isSameOriginQueryPrefix(prefix);
|
|
33899
|
+
}
|
|
33900
|
+
function isSameOriginQueryPrefix(prefix) {
|
|
33901
|
+
if (!prefix.startsWith("/"))
|
|
33902
|
+
return false;
|
|
33903
|
+
if (prefix.startsWith("//"))
|
|
33904
|
+
return false;
|
|
33905
|
+
return prefix.includes("?");
|
|
33906
|
+
}
|
|
33447
33907
|
|
|
33448
33908
|
class SinkFilterPass {
|
|
33449
33909
|
name = "sink-filter";
|
|
@@ -33455,7 +33915,8 @@ class SinkFilterPass {
|
|
|
33455
33915
|
const constProp = ctx.getResult("constant-propagation");
|
|
33456
33916
|
const langSources = ctx.getResult("language-sources");
|
|
33457
33917
|
const mergedSources = [...taintMatcher.sources, ...langSources.additionalSources];
|
|
33458
|
-
const
|
|
33918
|
+
const executableSources = ctx.code && ctx.language ? mergedSources.filter((s) => !isNonExecutableSourceLine(ctx.code, s.line, ctx.language)) : mergedSources;
|
|
33919
|
+
const sources = ctx.code ? executableSources.filter((s) => !isUnwrittenLocalMapKeyRead(ctx.code, s)) : executableSources;
|
|
33459
33920
|
const sinks = [...taintMatcher.sinks];
|
|
33460
33921
|
for (const s of langSources.additionalSinks) {
|
|
33461
33922
|
if (!sinks.some((x) => x.line === s.line && x.cwe === s.cwe && x.type === s.type)) {
|
|
@@ -33608,6 +34069,9 @@ class SinkFilterPass {
|
|
|
33608
34069
|
if (setHeaderMatch) {
|
|
33609
34070
|
return false;
|
|
33610
34071
|
}
|
|
34072
|
+
if (sink.type === "open_redirect" && hasSameOriginLiteralPrefix(sinkLineText)) {
|
|
34073
|
+
return false;
|
|
34074
|
+
}
|
|
33611
34075
|
if (sink.method === "cookie" && sink.type === "crlf") {
|
|
33612
34076
|
return false;
|
|
33613
34077
|
}
|
|
@@ -33747,13 +34211,23 @@ class SinkFilterPass {
|
|
|
33747
34211
|
filtered = filtered.filter((sink) => {
|
|
33748
34212
|
if (sink.type !== "command_injection")
|
|
33749
34213
|
return true;
|
|
33750
|
-
if (sink.method !== "ProcessBuilder" && sink.method !== "start")
|
|
34214
|
+
if (sink.method !== "ProcessBuilder" && sink.method !== "start" && sink.method !== "command") {
|
|
33751
34215
|
return true;
|
|
34216
|
+
}
|
|
33752
34217
|
const sinkLineText = sourceLines[sink.line - 1] ?? "";
|
|
33753
|
-
|
|
34218
|
+
const isCtorLine = /\bnew\s+ProcessBuilder\s*\(/.test(sinkLineText);
|
|
34219
|
+
const isCommandLine = /\.\s*command\s*\(/.test(sinkLineText);
|
|
34220
|
+
if (!isCtorLine && !isCommandLine)
|
|
33754
34221
|
return true;
|
|
33755
|
-
if (
|
|
34222
|
+
if (argvFirstLiteralIsShell(sinkLineText))
|
|
34223
|
+
return true;
|
|
34224
|
+
if (isCtorLine && PROCESS_BUILDER_ARGV_FORM_RE.test(sinkLineText))
|
|
34225
|
+
return false;
|
|
34226
|
+
if (isCommandLine && PROCESS_BUILDER_COMMAND_ARGV_FORM_RE.test(sinkLineText)) {
|
|
33756
34227
|
return false;
|
|
34228
|
+
}
|
|
34229
|
+
if (!isCtorLine)
|
|
34230
|
+
return true;
|
|
33757
34231
|
const ctorCall = irCalls.find((c) => c.method_name === "ProcessBuilder" && c.location.line === sink.line && (c.receiver === null || c.receiver === undefined));
|
|
33758
34232
|
if (!ctorCall || ctorCall.arguments.length === 0)
|
|
33759
34233
|
return true;
|
|
@@ -34023,6 +34497,15 @@ class SinkFilterPass {
|
|
|
34023
34497
|
if (language === "java" && !HTML_CONTENT_TYPE_RE.test(ctx.code)) {
|
|
34024
34498
|
filtered = filtered.filter((sink) => !(sink.type === "xss" && sink.method === "body"));
|
|
34025
34499
|
}
|
|
34500
|
+
if (language === "java") {
|
|
34501
|
+
const sourceLines = ctx.code.split(`
|
|
34502
|
+
`);
|
|
34503
|
+
filtered = filtered.filter((sink) => {
|
|
34504
|
+
if (sink.type !== "xss" || sink.class !== undefined)
|
|
34505
|
+
return true;
|
|
34506
|
+
return !JAVA_STDOUT_PRINT_RE.test(sourceLines[sink.line - 1] ?? "");
|
|
34507
|
+
});
|
|
34508
|
+
}
|
|
34026
34509
|
if (language === "java") {
|
|
34027
34510
|
const guardedLines = javaTraversalRejectGuardedLines(ctx.code);
|
|
34028
34511
|
if (guardedLines.size > 0) {
|
|
@@ -34108,6 +34591,43 @@ class SinkFilterPass {
|
|
|
34108
34591
|
return true;
|
|
34109
34592
|
});
|
|
34110
34593
|
}
|
|
34594
|
+
if (language === "csharp") {
|
|
34595
|
+
const sourceLines = ctx.code.split(`
|
|
34596
|
+
`);
|
|
34597
|
+
const constBaseClients = new Set;
|
|
34598
|
+
const declRe = /\b(?:var|HttpClient)\s+([A-Za-z_]\w*)\s*=\s*new\s+HttpClient\s*\{[^}]*\bBaseAddress\s*=\s*new\s+Uri\s*\(\s*(?:@?"[^"]*"|\$?"[^"{}]*")\s*\)/;
|
|
34599
|
+
for (const line of sourceLines) {
|
|
34600
|
+
const m = declRe.exec(line);
|
|
34601
|
+
if (m)
|
|
34602
|
+
constBaseClients.add(m[1]);
|
|
34603
|
+
}
|
|
34604
|
+
if (constBaseClients.size > 0) {
|
|
34605
|
+
const relativeLiteralArgRe = /\.\s*(?:Get|Post|Put|Patch|Delete|Send|GetString|GetByteArray|GetStream)\w*Async\s*\(\s*(?:@?\$?)"([^"]*)"/;
|
|
34606
|
+
filtered = filtered.filter((sink) => {
|
|
34607
|
+
if (sink.type !== "ssrf")
|
|
34608
|
+
return true;
|
|
34609
|
+
const text = sourceLines[sink.line - 1] ?? "";
|
|
34610
|
+
let onConstClient = false;
|
|
34611
|
+
for (const v of constBaseClients) {
|
|
34612
|
+
if (new RegExp(`(?<![\\w])${escapeRegex(v)}\\s*\\.`).test(text)) {
|
|
34613
|
+
onConstClient = true;
|
|
34614
|
+
break;
|
|
34615
|
+
}
|
|
34616
|
+
}
|
|
34617
|
+
if (!onConstClient)
|
|
34618
|
+
return true;
|
|
34619
|
+
const m = relativeLiteralArgRe.exec(text);
|
|
34620
|
+
if (!m)
|
|
34621
|
+
return true;
|
|
34622
|
+
const lit = m[1];
|
|
34623
|
+
if (/^[A-Za-z][A-Za-z0-9+.-]*:/.test(lit))
|
|
34624
|
+
return true;
|
|
34625
|
+
if (lit.startsWith("//"))
|
|
34626
|
+
return true;
|
|
34627
|
+
return false;
|
|
34628
|
+
});
|
|
34629
|
+
}
|
|
34630
|
+
}
|
|
34111
34631
|
if (["javascript", "typescript"].includes(language)) {
|
|
34112
34632
|
const sourceLines = ctx.code.split(`
|
|
34113
34633
|
`);
|
|
@@ -34724,7 +35244,7 @@ function isXPathQuoteEscapedOnLine(lineText, varName) {
|
|
|
34724
35244
|
return seen > 0;
|
|
34725
35245
|
}
|
|
34726
35246
|
|
|
34727
|
-
//
|
|
35247
|
+
// ../circle-ir/dist/analysis/passes/sink-semantics-pass.js
|
|
34728
35248
|
function buildRegistry(entries) {
|
|
34729
35249
|
const registry = new Map;
|
|
34730
35250
|
for (const entry of entries) {
|
|
@@ -34772,7 +35292,7 @@ class SinkSemanticsPass {
|
|
|
34772
35292
|
}
|
|
34773
35293
|
}
|
|
34774
35294
|
|
|
34775
|
-
//
|
|
35295
|
+
// ../circle-ir/dist/analysis/dependency-versions.js
|
|
34776
35296
|
function resolveFastjsonFromPom(pomXml) {
|
|
34777
35297
|
if (!pomXml)
|
|
34778
35298
|
return null;
|
|
@@ -34950,7 +35470,7 @@ function fileConfiguresSnakeYamlSafely(source) {
|
|
|
34950
35470
|
return false;
|
|
34951
35471
|
}
|
|
34952
35472
|
|
|
34953
|
-
//
|
|
35473
|
+
// ../circle-ir/dist/analysis/passes/deserialization-safety-gate-pass.js
|
|
34954
35474
|
var FASTJSON_METHODS = new Set(["parseObject", "parse"]);
|
|
34955
35475
|
var FASTJSON_CLASSES = new Set(["JSON", "JSONObject"]);
|
|
34956
35476
|
var JACKSON_METHODS = new Set(["readValue", "convertValue", "treeToValue"]);
|
|
@@ -35027,7 +35547,7 @@ class DeserializationSafetyGatePass {
|
|
|
35027
35547
|
}
|
|
35028
35548
|
}
|
|
35029
35549
|
|
|
35030
|
-
//
|
|
35550
|
+
// ../circle-ir/dist/analysis/passes/prompt-injection-safety-gate-pass.js
|
|
35031
35551
|
function isDelimiterLiteral(lit) {
|
|
35032
35552
|
const s = lit.trim();
|
|
35033
35553
|
if (s.length === 0)
|
|
@@ -35270,7 +35790,7 @@ class PromptInjectionSafetyGatePass {
|
|
|
35270
35790
|
}
|
|
35271
35791
|
}
|
|
35272
35792
|
|
|
35273
|
-
//
|
|
35793
|
+
// ../circle-ir/dist/analysis/passes/speculative-prompt-param-source-pass.js
|
|
35274
35794
|
function returnOrAssignRhs(text) {
|
|
35275
35795
|
const t = text.trim();
|
|
35276
35796
|
const ret = t.match(/^return\s+(.+?);?$/);
|
|
@@ -35396,7 +35916,7 @@ class SpeculativePromptParamSourcePass {
|
|
|
35396
35916
|
}
|
|
35397
35917
|
}
|
|
35398
35918
|
|
|
35399
|
-
//
|
|
35919
|
+
// ../circle-ir/dist/analysis/passes/cli-main-reflection-suppress-pass.js
|
|
35400
35920
|
var REFLECTION_SINK_METHODS = new Set([
|
|
35401
35921
|
"forName",
|
|
35402
35922
|
"newInstance",
|
|
@@ -35584,7 +36104,7 @@ class CliMainReflectionSuppressPass {
|
|
|
35584
36104
|
}
|
|
35585
36105
|
}
|
|
35586
36106
|
|
|
35587
|
-
//
|
|
36107
|
+
// ../circle-ir/dist/analysis/passes/library-profile-sink-gate-pass.js
|
|
35588
36108
|
var DROPPED_SINK_TYPES = new Set([
|
|
35589
36109
|
"log_injection"
|
|
35590
36110
|
]);
|
|
@@ -35658,7 +36178,7 @@ class LibraryProfileCwe22PathGatePass {
|
|
|
35658
36178
|
droppedBySourceType: {}
|
|
35659
36179
|
};
|
|
35660
36180
|
}
|
|
35661
|
-
const flows = graph.ir.taint.flows;
|
|
36181
|
+
const flows = ctx.hasResult("interprocedural") ? ctx.getResult("interprocedural").additionalFlows : graph.ir.taint.flows;
|
|
35662
36182
|
if (!flows || flows.length === 0) {
|
|
35663
36183
|
return {
|
|
35664
36184
|
profile,
|
|
@@ -35668,19 +36188,18 @@ class LibraryProfileCwe22PathGatePass {
|
|
|
35668
36188
|
};
|
|
35669
36189
|
}
|
|
35670
36190
|
const droppedBySourceType = {};
|
|
35671
|
-
|
|
36191
|
+
let tagged = 0;
|
|
35672
36192
|
for (const flow of flows) {
|
|
35673
36193
|
if (flow.sink_type === "path_traversal" && CWE22_SPECULATIVE_SOURCE_TYPES.has(flow.source_type)) {
|
|
35674
36194
|
droppedBySourceType[flow.source_type] = (droppedBySourceType[flow.source_type] ?? 0) + 1;
|
|
35675
|
-
|
|
36195
|
+
const tags = flow.tags ?? [];
|
|
36196
|
+
if (!tags.includes(LIBRARY_API_SURFACE_TAG)) {
|
|
36197
|
+
flow.tags = [...tags, LIBRARY_API_SURFACE_TAG];
|
|
36198
|
+
}
|
|
36199
|
+
tagged++;
|
|
35676
36200
|
}
|
|
35677
|
-
kept.push(flow);
|
|
35678
|
-
}
|
|
35679
|
-
const dropped = flows.length - kept.length;
|
|
35680
|
-
if (dropped > 0) {
|
|
35681
|
-
flows.length = 0;
|
|
35682
|
-
flows.push(...kept);
|
|
35683
36201
|
}
|
|
36202
|
+
const dropped = tagged;
|
|
35684
36203
|
return {
|
|
35685
36204
|
profile,
|
|
35686
36205
|
applied: true,
|
|
@@ -35690,7 +36209,7 @@ class LibraryProfileCwe22PathGatePass {
|
|
|
35690
36209
|
}
|
|
35691
36210
|
}
|
|
35692
36211
|
|
|
35693
|
-
//
|
|
36212
|
+
// ../circle-ir/dist/analysis/passes/library-profile-xss-gate-pass.js
|
|
35694
36213
|
var XSS_NON_HTML_OUTPUT_CLASSES = new Set([
|
|
35695
36214
|
"StringBuilder",
|
|
35696
36215
|
"StringBuffer",
|
|
@@ -35771,7 +36290,7 @@ class LibraryProfileXssGatePass {
|
|
|
35771
36290
|
}
|
|
35772
36291
|
}
|
|
35773
36292
|
|
|
35774
|
-
//
|
|
36293
|
+
// ../circle-ir/dist/analysis/passes/taint-propagation-pass.js
|
|
35775
36294
|
class TaintPropagationPass {
|
|
35776
36295
|
name = "taint-propagation";
|
|
35777
36296
|
category = "security";
|
|
@@ -35826,6 +36345,63 @@ class TaintPropagationPass {
|
|
|
35826
36345
|
flows.push(f);
|
|
35827
36346
|
return true;
|
|
35828
36347
|
};
|
|
36348
|
+
if (ctx.language === "python" && typeof ctx.code === "string") {
|
|
36349
|
+
const pyTainted = buildPythonTaintedVars(ctx.code);
|
|
36350
|
+
if (pyTainted.size > 0) {
|
|
36351
|
+
for (const v of findPythonTrustBoundaryViolations(ctx.code, pyTainted)) {
|
|
36352
|
+
const sink = sinks.find((sk) => sk.line === v.sinkLine && sk.type === "trust_boundary");
|
|
36353
|
+
if (!sink)
|
|
36354
|
+
continue;
|
|
36355
|
+
const src = sources.find((sc) => sc.line === v.sourceLine) ?? sources.filter((sc) => sc.line <= v.sinkLine).sort((a, b) => b.line - a.line)[0];
|
|
36356
|
+
if (!src)
|
|
36357
|
+
continue;
|
|
36358
|
+
if (constProp.unreachableLines.has(v.sinkLine))
|
|
36359
|
+
continue;
|
|
36360
|
+
pushIfNew({
|
|
36361
|
+
source_line: src.line,
|
|
36362
|
+
sink_line: v.sinkLine,
|
|
36363
|
+
source_type: src.type,
|
|
36364
|
+
sink_type: "trust_boundary",
|
|
36365
|
+
path: [
|
|
36366
|
+
{ variable: src.variable ?? "session_key", line: src.line, type: "source" },
|
|
36367
|
+
{ variable: src.variable ?? "session_key", line: v.sinkLine, type: "sink" }
|
|
36368
|
+
],
|
|
36369
|
+
confidence: (src.confidence ?? 1) * (sink.confidence ?? 1),
|
|
36370
|
+
sanitized: false
|
|
36371
|
+
});
|
|
36372
|
+
}
|
|
36373
|
+
}
|
|
36374
|
+
}
|
|
36375
|
+
if (ctx.language === "python" && typeof ctx.code === "string") {
|
|
36376
|
+
const pyTainted = buildPythonTaintedVars(ctx.code);
|
|
36377
|
+
if (pyTainted.size > 0) {
|
|
36378
|
+
const xssSanitizerLines = sanitizers.filter((sa) => sa.sanitizes.includes("xss")).map((sa) => sa.line);
|
|
36379
|
+
for (const rx of findPythonReturnXSSSinks(ctx.code, pyTainted)) {
|
|
36380
|
+
if (constProp.unreachableLines.has(rx.sinkLine))
|
|
36381
|
+
continue;
|
|
36382
|
+
const sink = sinks.find((sk) => sk.line === rx.sinkLine && sk.type === "xss");
|
|
36383
|
+
if (!sink)
|
|
36384
|
+
continue;
|
|
36385
|
+
const src = sources.filter((sc) => sc.line <= rx.sinkLine).sort((a, b) => b.line - a.line)[0];
|
|
36386
|
+
if (!src)
|
|
36387
|
+
continue;
|
|
36388
|
+
if (xssSanitizerLines.some((l) => l >= src.line && l <= rx.sinkLine))
|
|
36389
|
+
continue;
|
|
36390
|
+
pushIfNew({
|
|
36391
|
+
source_line: src.line,
|
|
36392
|
+
sink_line: rx.sinkLine,
|
|
36393
|
+
source_type: src.type,
|
|
36394
|
+
sink_type: "xss",
|
|
36395
|
+
path: [
|
|
36396
|
+
{ variable: src.variable ?? "response", line: src.line, type: "source" },
|
|
36397
|
+
{ variable: src.variable ?? "response", line: rx.sinkLine, type: "sink" }
|
|
36398
|
+
],
|
|
36399
|
+
confidence: (src.confidence ?? 1) * (sink.confidence ?? 1),
|
|
36400
|
+
sanitized: false
|
|
36401
|
+
});
|
|
36402
|
+
}
|
|
36403
|
+
}
|
|
36404
|
+
}
|
|
35829
36405
|
const arrayFlows = detectArrayElementFlows(calls, sources, sinks, constProp.taintedArrayElements, constProp.unreachableLines, types) ?? [];
|
|
35830
36406
|
for (const f of arrayFlows) {
|
|
35831
36407
|
pushIfNew(f);
|
|
@@ -36515,6 +37091,108 @@ function isReassignedToLiteralBetween(code, variable, srcLine, sinkLine) {
|
|
|
36515
37091
|
}
|
|
36516
37092
|
return false;
|
|
36517
37093
|
}
|
|
37094
|
+
var MASKABLE_STRING_LANGUAGES = new Set(["python", "javascript", "typescript"]);
|
|
37095
|
+
function maskStringLiteralsForTokenScan(expr) {
|
|
37096
|
+
let out2 = "";
|
|
37097
|
+
let i2 = 0;
|
|
37098
|
+
const braceExprs = (body2) => {
|
|
37099
|
+
let acc = "";
|
|
37100
|
+
for (let j = 0;j < body2.length; ) {
|
|
37101
|
+
if (body2[j] === "{" && body2[j + 1] === "{") {
|
|
37102
|
+
j += 2;
|
|
37103
|
+
continue;
|
|
37104
|
+
}
|
|
37105
|
+
if (body2[j] === "}" && body2[j + 1] === "}") {
|
|
37106
|
+
j += 2;
|
|
37107
|
+
continue;
|
|
37108
|
+
}
|
|
37109
|
+
if (body2[j] === "{") {
|
|
37110
|
+
j++;
|
|
37111
|
+
let depth = 1;
|
|
37112
|
+
let inner = "";
|
|
37113
|
+
while (j < body2.length && depth > 0) {
|
|
37114
|
+
if (body2[j] === "{")
|
|
37115
|
+
depth++;
|
|
37116
|
+
else if (body2[j] === "}") {
|
|
37117
|
+
depth--;
|
|
37118
|
+
if (depth === 0)
|
|
37119
|
+
break;
|
|
37120
|
+
}
|
|
37121
|
+
inner += body2[j];
|
|
37122
|
+
j++;
|
|
37123
|
+
}
|
|
37124
|
+
j++;
|
|
37125
|
+
acc += " " + maskStringLiteralsForTokenScan(inner) + " ";
|
|
37126
|
+
continue;
|
|
37127
|
+
}
|
|
37128
|
+
j++;
|
|
37129
|
+
}
|
|
37130
|
+
return acc;
|
|
37131
|
+
};
|
|
37132
|
+
while (i2 < expr.length) {
|
|
37133
|
+
const ch = expr[i2];
|
|
37134
|
+
if (ch === "`") {
|
|
37135
|
+
i2++;
|
|
37136
|
+
let acc = "";
|
|
37137
|
+
while (i2 < expr.length && expr[i2] !== "`") {
|
|
37138
|
+
if (expr[i2] === "\\") {
|
|
37139
|
+
i2 += 2;
|
|
37140
|
+
continue;
|
|
37141
|
+
}
|
|
37142
|
+
if (expr[i2] === "$" && expr[i2 + 1] === "{") {
|
|
37143
|
+
i2 += 2;
|
|
37144
|
+
let depth = 1;
|
|
37145
|
+
let inner = "";
|
|
37146
|
+
while (i2 < expr.length && depth > 0) {
|
|
37147
|
+
if (expr[i2] === "{")
|
|
37148
|
+
depth++;
|
|
37149
|
+
else if (expr[i2] === "}") {
|
|
37150
|
+
depth--;
|
|
37151
|
+
if (depth === 0)
|
|
37152
|
+
break;
|
|
37153
|
+
}
|
|
37154
|
+
inner += expr[i2];
|
|
37155
|
+
i2++;
|
|
37156
|
+
}
|
|
37157
|
+
i2++;
|
|
37158
|
+
acc += " " + maskStringLiteralsForTokenScan(inner) + " ";
|
|
37159
|
+
continue;
|
|
37160
|
+
}
|
|
37161
|
+
i2++;
|
|
37162
|
+
}
|
|
37163
|
+
i2++;
|
|
37164
|
+
out2 += " " + acc + " ";
|
|
37165
|
+
continue;
|
|
37166
|
+
}
|
|
37167
|
+
if (ch === '"' || ch === "'") {
|
|
37168
|
+
const pm = /[A-Za-z_][A-Za-z0-9_]*$/.exec(out2);
|
|
37169
|
+
const prefix = pm ? pm[0] : "";
|
|
37170
|
+
const isPrefix = prefix.length > 0 && /^[rRbBuUfF]+$/.test(prefix);
|
|
37171
|
+
const isF = isPrefix && /[fF]/.test(prefix);
|
|
37172
|
+
if (isPrefix)
|
|
37173
|
+
out2 = out2.slice(0, out2.length - prefix.length) + " ";
|
|
37174
|
+
const triple = expr.startsWith(ch.repeat(3), i2);
|
|
37175
|
+
const delim = triple ? ch.repeat(3) : ch;
|
|
37176
|
+
i2 += delim.length;
|
|
37177
|
+
let body2 = "";
|
|
37178
|
+
while (i2 < expr.length && !expr.startsWith(delim, i2)) {
|
|
37179
|
+
if (expr[i2] === "\\") {
|
|
37180
|
+
body2 += " ";
|
|
37181
|
+
i2 += 2;
|
|
37182
|
+
continue;
|
|
37183
|
+
}
|
|
37184
|
+
body2 += expr[i2];
|
|
37185
|
+
i2++;
|
|
37186
|
+
}
|
|
37187
|
+
i2 += delim.length;
|
|
37188
|
+
out2 += isF ? " " + braceExprs(body2) + " " : " ";
|
|
37189
|
+
continue;
|
|
37190
|
+
}
|
|
37191
|
+
out2 += ch;
|
|
37192
|
+
i2++;
|
|
37193
|
+
}
|
|
37194
|
+
return out2;
|
|
37195
|
+
}
|
|
36518
37196
|
function detectExpressionScanFlows(calls, sources, sinks, sanitizers, unreachableLines, tainted, code, language, types) {
|
|
36519
37197
|
const flows = [];
|
|
36520
37198
|
const sourcesWithVar = sources.filter((s) => typeof s.variable === "string" && s.variable.length > 0);
|
|
@@ -36904,7 +37582,8 @@ function detectExpressionScanFlows(calls, sources, sinks, sanitizers, unreachabl
|
|
|
36904
37582
|
const expr = arg.expression;
|
|
36905
37583
|
if (!expr)
|
|
36906
37584
|
continue;
|
|
36907
|
-
const
|
|
37585
|
+
const scannable = language !== undefined && MASKABLE_STRING_LANGUAGES.has(language) ? maskStringLiteralsForTokenScan(expr) : expr;
|
|
37586
|
+
const exprIdentMatches = scannable.match(/[\p{L}\p{N}_]+/gu);
|
|
36908
37587
|
let candidates = complexSources.length > 0 ? complexSources.slice() : null;
|
|
36909
37588
|
if (exprIdentMatches) {
|
|
36910
37589
|
for (const id of new Set(exprIdentMatches)) {
|
|
@@ -37054,7 +37733,7 @@ function pickScopedSource(sources, sinkLine, methodName, types, taintedVar) {
|
|
|
37054
37733
|
return sources[0];
|
|
37055
37734
|
}
|
|
37056
37735
|
|
|
37057
|
-
//
|
|
37736
|
+
// ../circle-ir/dist/analysis/interprocedural.js
|
|
37058
37737
|
function analyzeInterprocedural2(graphOrTypes, callsOrSources, dfgOrSinks, sourcesOrSanitizers, sinksOrOptions, sanitizersArg, optionsArg = {}) {
|
|
37059
37738
|
let graph;
|
|
37060
37739
|
let sources;
|
|
@@ -37568,7 +38247,7 @@ function findTaintBridges2(result) {
|
|
|
37568
38247
|
return bridges;
|
|
37569
38248
|
}
|
|
37570
38249
|
|
|
37571
|
-
//
|
|
38250
|
+
// ../circle-ir/dist/analysis/passes/interprocedural-pass.js
|
|
37572
38251
|
class InterproceduralPass {
|
|
37573
38252
|
name = "interprocedural";
|
|
37574
38253
|
category = "security";
|
|
@@ -37774,7 +38453,7 @@ class InterproceduralPass {
|
|
|
37774
38453
|
}
|
|
37775
38454
|
}
|
|
37776
38455
|
|
|
37777
|
-
//
|
|
38456
|
+
// ../circle-ir/dist/analysis/passes/dead-code-pass.js
|
|
37778
38457
|
class DeadCodePass {
|
|
37779
38458
|
name = "dead-code";
|
|
37780
38459
|
category = "reliability";
|
|
@@ -37850,7 +38529,7 @@ class DeadCodePass {
|
|
|
37850
38529
|
}
|
|
37851
38530
|
}
|
|
37852
38531
|
|
|
37853
|
-
//
|
|
38532
|
+
// ../circle-ir/dist/analysis/passes/missing-await-pass.js
|
|
37854
38533
|
var ASYNC_METHODS = new Set([
|
|
37855
38534
|
"readFile",
|
|
37856
38535
|
"writeFile",
|
|
@@ -37929,7 +38608,7 @@ class MissingAwaitPass {
|
|
|
37929
38608
|
}
|
|
37930
38609
|
}
|
|
37931
38610
|
|
|
37932
|
-
//
|
|
38611
|
+
// ../circle-ir/dist/analysis/passes/n-plus-one-pass.js
|
|
37933
38612
|
var HIGH_CONFIDENCE_DB_METHODS = new Set([
|
|
37934
38613
|
"executeQuery",
|
|
37935
38614
|
"executeUpdate",
|
|
@@ -38052,7 +38731,7 @@ class NPlusOnePass {
|
|
|
38052
38731
|
}
|
|
38053
38732
|
}
|
|
38054
38733
|
|
|
38055
|
-
//
|
|
38734
|
+
// ../circle-ir/dist/analysis/passes/missing-public-doc-pass.js
|
|
38056
38735
|
var TEST_PATH_RE = /[/._](test|tests|spec|specs|__tests?__|__mocks?__)[/._]/i;
|
|
38057
38736
|
var UTIL_DIR_RE = /[/](utils?|helpers?|internal|private|common|shared)[/]/i;
|
|
38058
38737
|
function hasDocCommentBefore(lines, startLine) {
|
|
@@ -38159,7 +38838,7 @@ class MissingPublicDocPass {
|
|
|
38159
38838
|
}
|
|
38160
38839
|
}
|
|
38161
38840
|
|
|
38162
|
-
//
|
|
38841
|
+
// ../circle-ir/dist/analysis/passes/todo-in-prod-pass.js
|
|
38163
38842
|
var TEST_PATH_RE2 = /[/._](test|tests|spec|specs|__tests?__|__mocks?__)[/._]/i;
|
|
38164
38843
|
var MARKER_RE = /(?:\/\/|#|--|^\s*\*)\s*(TODO|FIXME|HACK|XXX)\b/i;
|
|
38165
38844
|
function markerSeverity(marker) {
|
|
@@ -38205,7 +38884,7 @@ class TodoInProdPass {
|
|
|
38205
38884
|
}
|
|
38206
38885
|
}
|
|
38207
38886
|
|
|
38208
|
-
//
|
|
38887
|
+
// ../circle-ir/dist/analysis/passes/string-concat-loop-pass.js
|
|
38209
38888
|
var CONCAT_RE = /\b([a-zA-Z_$][a-zA-Z0-9_$]*)\s*\+=/;
|
|
38210
38889
|
var NUMERIC_VAR_RE = /^(i|j|k|n|m|x|y|z|count|sum|total|size|index|len|length|num|idx|score|counter|offset|pos|col|row|result|ret|value|acc|bits|byte|bytes|flag|flags|step|delta|diff|dist|min|max|avg|mean|page|line|err|error)$/i;
|
|
38211
38890
|
var NUMERIC_SUFFIX_RE = /(Count|Sum|Total|Size|Index|Length|Offset|Position|Score|Counter|Num|Amount|Val|Idx|Len|Max|Min|Avg|Delta|Diff|Step|Flag|Flags|Bits|Byte|Bytes|Calls|Items|Nodes|Edges|Blocks|Lines|Chars|Entries|Records|Rows)$/;
|
|
@@ -38268,7 +38947,7 @@ class StringConcatLoopPass {
|
|
|
38268
38947
|
}
|
|
38269
38948
|
}
|
|
38270
38949
|
|
|
38271
|
-
//
|
|
38950
|
+
// ../circle-ir/dist/analysis/passes/sync-io-async-pass.js
|
|
38272
38951
|
var BLOCKING_METHODS = new Set([
|
|
38273
38952
|
"sleep"
|
|
38274
38953
|
]);
|
|
@@ -38329,7 +39008,7 @@ class SyncIoAsyncPass {
|
|
|
38329
39008
|
}
|
|
38330
39009
|
}
|
|
38331
39010
|
|
|
38332
|
-
//
|
|
39011
|
+
// ../circle-ir/dist/analysis/passes/unchecked-return-pass.js
|
|
38333
39012
|
var MUST_CHECK_HIGH = new Set([
|
|
38334
39013
|
"createNewFile",
|
|
38335
39014
|
"mkdir",
|
|
@@ -38402,7 +39081,7 @@ class UncheckedReturnPass {
|
|
|
38402
39081
|
}
|
|
38403
39082
|
}
|
|
38404
39083
|
|
|
38405
|
-
//
|
|
39084
|
+
// ../circle-ir/dist/analysis/passes/null-deref-pass.js
|
|
38406
39085
|
var NULL_EXPR_RE = /^\s*(null|None|undefined)\s*$/;
|
|
38407
39086
|
function escRe(s) {
|
|
38408
39087
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -38484,7 +39163,7 @@ class NullDerefPass {
|
|
|
38484
39163
|
}
|
|
38485
39164
|
}
|
|
38486
39165
|
|
|
38487
|
-
//
|
|
39166
|
+
// ../circle-ir/dist/analysis/passes/resource-leak-pass.js
|
|
38488
39167
|
function escapeRegex2(s) {
|
|
38489
39168
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
38490
39169
|
}
|
|
@@ -38761,7 +39440,7 @@ class ResourceLeakPass {
|
|
|
38761
39440
|
}
|
|
38762
39441
|
}
|
|
38763
39442
|
|
|
38764
|
-
//
|
|
39443
|
+
// ../circle-ir/dist/graph/scope-graph.js
|
|
38765
39444
|
function hasDeclKeyword(lineText, language) {
|
|
38766
39445
|
switch (language) {
|
|
38767
39446
|
case "java":
|
|
@@ -38801,7 +39480,7 @@ class ScopeGraph {
|
|
|
38801
39480
|
}
|
|
38802
39481
|
}
|
|
38803
39482
|
|
|
38804
|
-
//
|
|
39483
|
+
// ../circle-ir/dist/analysis/passes/variable-shadowing-pass.js
|
|
38805
39484
|
var SKIP_NAMES = new Set([
|
|
38806
39485
|
"let",
|
|
38807
39486
|
"const",
|
|
@@ -38959,7 +39638,7 @@ class VariableShadowingPass {
|
|
|
38959
39638
|
}
|
|
38960
39639
|
}
|
|
38961
39640
|
|
|
38962
|
-
//
|
|
39641
|
+
// ../circle-ir/dist/analysis/passes/leaked-global-pass.js
|
|
38963
39642
|
var SKIP_NAMES2 = new Set([
|
|
38964
39643
|
"_",
|
|
38965
39644
|
"e",
|
|
@@ -39046,7 +39725,7 @@ class LeakedGlobalPass {
|
|
|
39046
39725
|
}
|
|
39047
39726
|
}
|
|
39048
39727
|
|
|
39049
|
-
//
|
|
39728
|
+
// ../circle-ir/dist/analysis/passes/unused-variable-pass.js
|
|
39050
39729
|
var SKIP_NAMES3 = new Set([
|
|
39051
39730
|
"_",
|
|
39052
39731
|
"unused",
|
|
@@ -39191,7 +39870,7 @@ class UnusedVariablePass {
|
|
|
39191
39870
|
}
|
|
39192
39871
|
}
|
|
39193
39872
|
|
|
39194
|
-
//
|
|
39873
|
+
// ../circle-ir/dist/analysis/passes/dependency-fan-out-pass.js
|
|
39195
39874
|
var DEFAULT_THRESHOLD = 20;
|
|
39196
39875
|
|
|
39197
39876
|
class DependencyFanOutPass {
|
|
@@ -39223,7 +39902,7 @@ class DependencyFanOutPass {
|
|
|
39223
39902
|
}
|
|
39224
39903
|
}
|
|
39225
39904
|
|
|
39226
|
-
//
|
|
39905
|
+
// ../circle-ir/dist/analysis/passes/stale-doc-ref-pass.js
|
|
39227
39906
|
var DOC_BLOCK_RE = /\/\*\*([\s\S]*?)\*\//g;
|
|
39228
39907
|
var LINK_RE = /\{@link\s+([\w.#]+)/g;
|
|
39229
39908
|
var SEE_RE = /@see\s+([\w.#]+)/g;
|
|
@@ -39302,7 +39981,7 @@ class StaleDocRefPass {
|
|
|
39302
39981
|
}
|
|
39303
39982
|
}
|
|
39304
39983
|
|
|
39305
|
-
//
|
|
39984
|
+
// ../circle-ir/dist/analysis/passes/infinite-loop-pass.js
|
|
39306
39985
|
var EXIT_KEYWORDS = /\b(return|throw|raise|break|System\.exit|process\.exit|os\._exit|exit!\()\b/;
|
|
39307
39986
|
var ITERATOR_LOOP_PATTERNS = [
|
|
39308
39987
|
/\bfor\s*\([^)]*\s+of\s+/,
|
|
@@ -39421,7 +40100,7 @@ class InfiniteLoopPass {
|
|
|
39421
40100
|
}
|
|
39422
40101
|
}
|
|
39423
40102
|
|
|
39424
|
-
//
|
|
40103
|
+
// ../circle-ir/dist/analysis/passes/deep-inheritance-pass.js
|
|
39425
40104
|
var DEPTH_THRESHOLD = 5;
|
|
39426
40105
|
var CYCLE_GUARD = 20;
|
|
39427
40106
|
|
|
@@ -39484,7 +40163,7 @@ class DeepInheritancePass {
|
|
|
39484
40163
|
}
|
|
39485
40164
|
}
|
|
39486
40165
|
|
|
39487
|
-
//
|
|
40166
|
+
// ../circle-ir/dist/analysis/passes/redundant-loop-pass.js
|
|
39488
40167
|
var LENGTH_PATTERN = /\b([A-Za-z_$][A-Za-z0-9_$]*)\s*\.\s*(?:length|size\(\)|count\(\))/g;
|
|
39489
40168
|
var LENGTH_PATTERN_METHODS = /\b([A-Za-z_$][A-Za-z0-9_$]*)\s*\.\s*(?:size\(\)|count\(\))/g;
|
|
39490
40169
|
var OBJECT_STATIC_PATTERN = /\bObject\s*\.\s*(?:keys|values|entries)\s*\(\s*([A-Za-z_$][A-Za-z0-9_$]*)\s*\)/g;
|
|
@@ -39607,7 +40286,7 @@ class RedundantLoopPass {
|
|
|
39607
40286
|
}
|
|
39608
40287
|
}
|
|
39609
40288
|
|
|
39610
|
-
//
|
|
40289
|
+
// ../circle-ir/dist/analysis/passes/unbounded-collection-pass.js
|
|
39611
40290
|
var GROW_METHODS = {
|
|
39612
40291
|
java: new Set(["add", "put", "offer", "push", "addAll", "addFirst", "addLast", "enqueue", "insert"]),
|
|
39613
40292
|
javascript: new Set(["push", "set", "add", "unshift", "append", "prepend"]),
|
|
@@ -39731,7 +40410,7 @@ class UnboundedCollectionPass {
|
|
|
39731
40410
|
}
|
|
39732
40411
|
}
|
|
39733
40412
|
|
|
39734
|
-
//
|
|
40413
|
+
// ../circle-ir/dist/analysis/passes/serial-await-pass.js
|
|
39735
40414
|
var AWAIT_ASSIGN_RE = /(?:const|let|var)?\s*(\w+)\s*=\s*await\s/;
|
|
39736
40415
|
var AWAIT_RE = /\bawait\s/;
|
|
39737
40416
|
|
|
@@ -39827,7 +40506,7 @@ class SerialAwaitPass {
|
|
|
39827
40506
|
}
|
|
39828
40507
|
}
|
|
39829
40508
|
|
|
39830
|
-
//
|
|
40509
|
+
// ../circle-ir/dist/analysis/passes/react-inline-jsx-pass.js
|
|
39831
40510
|
var JSX_COMPONENT_RE = /<[A-Z][A-Za-z0-9]*/;
|
|
39832
40511
|
var INLINE_OBJECT_RE = /\s([A-Za-z][A-Za-z0-9_]*)=\{\{/g;
|
|
39833
40512
|
var INLINE_ARROW_RE = /\s([A-Za-z][A-Za-z0-9_]*)=\{(?:\(|[A-Za-z_$]).*?=>/g;
|
|
@@ -39931,7 +40610,7 @@ class ReactInlineJsxPass {
|
|
|
39931
40610
|
}
|
|
39932
40611
|
}
|
|
39933
40612
|
|
|
39934
|
-
//
|
|
40613
|
+
// ../circle-ir/dist/graph/exception-flow-graph.js
|
|
39935
40614
|
class ExceptionFlowGraph2 {
|
|
39936
40615
|
pairs;
|
|
39937
40616
|
catchEntryIds;
|
|
@@ -39982,7 +40661,7 @@ class ExceptionFlowGraph2 {
|
|
|
39982
40661
|
}
|
|
39983
40662
|
}
|
|
39984
40663
|
|
|
39985
|
-
//
|
|
40664
|
+
// ../circle-ir/dist/analysis/passes/swallowed-exception-pass.js
|
|
39986
40665
|
var MEANINGFUL_ACTION_RE = /\b(throw|raise|log|logger|console\.(error|warn|log|debug|info)|System\.(out|err)\.|print(?:ln|f)?|warn|error|debug|info|fatal|LOGGER|LOG|logging\.(warning|error|debug|info|critical))\b|\breturn\s+\S/;
|
|
39987
40666
|
|
|
39988
40667
|
class SwallowedExceptionPass {
|
|
@@ -40080,7 +40759,7 @@ class SwallowedExceptionPass {
|
|
|
40080
40759
|
}
|
|
40081
40760
|
}
|
|
40082
40761
|
|
|
40083
|
-
//
|
|
40762
|
+
// ../circle-ir/dist/analysis/passes/broad-catch-pass.js
|
|
40084
40763
|
var JAVA_BROAD_RE = /catch\s*\(\s*(Exception|Throwable|RuntimeException|Error)\s/;
|
|
40085
40764
|
var PYTHON_BROAD_RE = /^\s*except\s*:|except\s+(Exception|BaseException)\b/;
|
|
40086
40765
|
|
|
@@ -40136,7 +40815,7 @@ class BroadCatchPass {
|
|
|
40136
40815
|
}
|
|
40137
40816
|
}
|
|
40138
40817
|
|
|
40139
|
-
//
|
|
40818
|
+
// ../circle-ir/dist/analysis/passes/unhandled-exception-pass.js
|
|
40140
40819
|
var JS_THROW_RE = /^\s*throw\s+/;
|
|
40141
40820
|
var PYTHON_RAISE_RE = /^\s*raise\b/;
|
|
40142
40821
|
function isValidationThrow(lines, throwLine) {
|
|
@@ -40306,7 +40985,7 @@ class UnhandledExceptionPass {
|
|
|
40306
40985
|
}
|
|
40307
40986
|
}
|
|
40308
40987
|
|
|
40309
|
-
//
|
|
40988
|
+
// ../circle-ir/dist/analysis/passes/double-close-pass.js
|
|
40310
40989
|
var RESOURCE_CTORS2 = new Set([
|
|
40311
40990
|
"FileInputStream",
|
|
40312
40991
|
"FileOutputStream",
|
|
@@ -40421,7 +41100,7 @@ class DoubleClosePass {
|
|
|
40421
41100
|
}
|
|
40422
41101
|
}
|
|
40423
41102
|
|
|
40424
|
-
//
|
|
41103
|
+
// ../circle-ir/dist/analysis/passes/use-after-close-pass.js
|
|
40425
41104
|
var RESOURCE_CTORS3 = new Set([
|
|
40426
41105
|
"FileInputStream",
|
|
40427
41106
|
"FileOutputStream",
|
|
@@ -40529,7 +41208,7 @@ class UseAfterClosePass {
|
|
|
40529
41208
|
}
|
|
40530
41209
|
}
|
|
40531
41210
|
|
|
40532
|
-
//
|
|
41211
|
+
// ../circle-ir/dist/graph/dominator-graph.js
|
|
40533
41212
|
function computeRPO(cfg, entryId) {
|
|
40534
41213
|
const outgoing = new Map;
|
|
40535
41214
|
for (const edge of cfg.edges) {
|
|
@@ -40694,7 +41373,7 @@ class DominatorGraph2 {
|
|
|
40694
41373
|
}
|
|
40695
41374
|
}
|
|
40696
41375
|
|
|
40697
|
-
//
|
|
41376
|
+
// ../circle-ir/dist/analysis/passes/cleanup-verify-pass.js
|
|
40698
41377
|
var RESOURCE_CTORS4 = new Set([
|
|
40699
41378
|
"FileInputStream",
|
|
40700
41379
|
"FileOutputStream",
|
|
@@ -40819,7 +41498,7 @@ class CleanupVerifyPass {
|
|
|
40819
41498
|
}
|
|
40820
41499
|
}
|
|
40821
41500
|
|
|
40822
|
-
//
|
|
41501
|
+
// ../circle-ir/dist/analysis/passes/missing-override-pass.js
|
|
40823
41502
|
class MissingOverridePass {
|
|
40824
41503
|
name = "missing-override";
|
|
40825
41504
|
category = "maintainability";
|
|
@@ -40906,7 +41585,7 @@ class MissingOverridePass {
|
|
|
40906
41585
|
}
|
|
40907
41586
|
}
|
|
40908
41587
|
|
|
40909
|
-
//
|
|
41588
|
+
// ../circle-ir/dist/analysis/passes/unused-interface-method-pass.js
|
|
40910
41589
|
class UnusedInterfaceMethodPass {
|
|
40911
41590
|
name = "unused-interface-method";
|
|
40912
41591
|
category = "maintainability";
|
|
@@ -40949,7 +41628,7 @@ class UnusedInterfaceMethodPass {
|
|
|
40949
41628
|
}
|
|
40950
41629
|
}
|
|
40951
41630
|
|
|
40952
|
-
//
|
|
41631
|
+
// ../circle-ir/dist/analysis/passes/blocking-main-thread-pass.js
|
|
40953
41632
|
var HTTP_DECORATORS = new Set([
|
|
40954
41633
|
"Get",
|
|
40955
41634
|
"Post",
|
|
@@ -40988,6 +41667,18 @@ var CRYPTO_BLOCKING_METHODS = new Set([
|
|
|
40988
41667
|
"deriveKeySync"
|
|
40989
41668
|
]);
|
|
40990
41669
|
var SYNC_SUFFIX_RE2 = /Sync$/;
|
|
41670
|
+
var ROUTER_METHODS = new Set([
|
|
41671
|
+
"get",
|
|
41672
|
+
"post",
|
|
41673
|
+
"put",
|
|
41674
|
+
"patch",
|
|
41675
|
+
"delete",
|
|
41676
|
+
"all",
|
|
41677
|
+
"options",
|
|
41678
|
+
"head",
|
|
41679
|
+
"use"
|
|
41680
|
+
]);
|
|
41681
|
+
var FN_ARG_PARAMS_RE = /^(?:async\s+)?(?:function\s*[\w$]*\s*)?\(([^)]*)\)\s*(?:=>|\{)|^(?:async\s+)?([A-Za-z_$][\w$]*)\s*=>/;
|
|
40991
41682
|
|
|
40992
41683
|
class BlockingMainThreadPass {
|
|
40993
41684
|
name = "blocking-main-thread";
|
|
@@ -41010,8 +41701,10 @@ class BlockingMainThreadPass {
|
|
|
41010
41701
|
}
|
|
41011
41702
|
}
|
|
41012
41703
|
}
|
|
41013
|
-
|
|
41704
|
+
const inlineHandlers = this.collectInlineHandlerNames(graph.ir.calls);
|
|
41705
|
+
if (handlerRanges.length === 0 && inlineHandlers.size === 0) {
|
|
41014
41706
|
return { blockingInHandlers: [] };
|
|
41707
|
+
}
|
|
41015
41708
|
const blockingInHandlers = [];
|
|
41016
41709
|
for (const call of graph.ir.calls) {
|
|
41017
41710
|
const name2 = call.method_name;
|
|
@@ -41020,7 +41713,8 @@ class BlockingMainThreadPass {
|
|
|
41020
41713
|
if (!isCrypto && !isSyncSuffix)
|
|
41021
41714
|
continue;
|
|
41022
41715
|
const line = call.location.line;
|
|
41023
|
-
const
|
|
41716
|
+
const enclosing = call.in_method ?? null;
|
|
41717
|
+
const range = handlerRanges.find((r) => line >= r.start && line <= r.end) ?? (enclosing && inlineHandlers.has(enclosing) ? { start: line, end: line, name: enclosing } : undefined);
|
|
41024
41718
|
if (!range)
|
|
41025
41719
|
continue;
|
|
41026
41720
|
const reason = isCrypto ? "crypto" : "sync-suffix";
|
|
@@ -41042,6 +41736,24 @@ class BlockingMainThreadPass {
|
|
|
41042
41736
|
}
|
|
41043
41737
|
return { blockingInHandlers };
|
|
41044
41738
|
}
|
|
41739
|
+
collectInlineHandlerNames(calls) {
|
|
41740
|
+
const names = new Set;
|
|
41741
|
+
for (const call of calls) {
|
|
41742
|
+
if (!ROUTER_METHODS.has(call.method_name))
|
|
41743
|
+
continue;
|
|
41744
|
+
for (const arg of call.arguments) {
|
|
41745
|
+
const match = FN_ARG_PARAMS_RE.exec((arg.expression ?? "").trim());
|
|
41746
|
+
if (!match)
|
|
41747
|
+
continue;
|
|
41748
|
+
const params = (match[1] ?? match[2] ?? "").split(",").map((p) => p.trim().toLowerCase()).filter((p) => p.length > 0);
|
|
41749
|
+
if (params.some((p) => HANDLER_PARAM_NAMES.has(p))) {
|
|
41750
|
+
names.add(`${call.method_name}_handler`);
|
|
41751
|
+
break;
|
|
41752
|
+
}
|
|
41753
|
+
}
|
|
41754
|
+
}
|
|
41755
|
+
return names;
|
|
41756
|
+
}
|
|
41045
41757
|
isRequestHandler(method) {
|
|
41046
41758
|
if (method.annotations.some((a) => HTTP_DECORATORS.has(a)))
|
|
41047
41759
|
return true;
|
|
@@ -41052,7 +41764,7 @@ class BlockingMainThreadPass {
|
|
|
41052
41764
|
}
|
|
41053
41765
|
}
|
|
41054
41766
|
|
|
41055
|
-
//
|
|
41767
|
+
// ../circle-ir/dist/analysis/passes/excessive-allocation-pass.js
|
|
41056
41768
|
var ALLOC_PATTERNS = {
|
|
41057
41769
|
javascript: /\bnew\s+(Array|Map|Set|Object|WeakMap|WeakSet|Error|RegExp|Date|Buffer|Uint8Array|Int8Array|Float32Array|ArrayBuffer)\s*[(<]|\bArray\.from\s*\(|\bstructuredClone\s*\(|\bObject\.create\s*\(/,
|
|
41058
41770
|
typescript: /\bnew\s+(Array|Map|Set|Object|WeakMap|WeakSet|Error|RegExp|Date|Buffer|Uint8Array|Int8Array|Float32Array|ArrayBuffer)\s*[(<]|\bArray\.from\s*\(|\bstructuredClone\s*\(|\bObject\.create\s*\(/,
|
|
@@ -41119,7 +41831,7 @@ class ExcessiveAllocationPass {
|
|
|
41119
41831
|
}
|
|
41120
41832
|
}
|
|
41121
41833
|
|
|
41122
|
-
//
|
|
41834
|
+
// ../circle-ir/dist/analysis/passes/missing-stream-pass.js
|
|
41123
41835
|
var JS_WHOLE_LOAD_RE = /\b(?:readFileSync|fs\.readFile\b|response\.text\b|response\.json\b|res\.text\b|res\.json\b|body\.text\b|body\.json\b)\s*\(/;
|
|
41124
41836
|
var JS_STREAM_RE = /\.pipe\s*\(|\.on\s*\(\s*['"]data['"]|for\s+await\s*\(|\bcreateReadStream\b|\bstream\b/i;
|
|
41125
41837
|
var JAVA_WHOLE_READ_RE = /\bFiles\.readAllBytes\s*\(|\bFiles\.readAllLines\s*\(|\bFiles\.readString\s*\(|\bnew\s+BufferedReader\s*\(|\bFileInputStream\b/;
|
|
@@ -41266,7 +41978,7 @@ class MissingStreamPass {
|
|
|
41266
41978
|
}
|
|
41267
41979
|
}
|
|
41268
41980
|
|
|
41269
|
-
//
|
|
41981
|
+
// ../circle-ir/dist/analysis/passes/god-class-pass.js
|
|
41270
41982
|
var WMC_THRESHOLD = 47;
|
|
41271
41983
|
var LCOM2_THRESHOLD = 0.8;
|
|
41272
41984
|
var CBO_THRESHOLD = 14;
|
|
@@ -41432,7 +42144,7 @@ class GodClassPass {
|
|
|
41432
42144
|
}
|
|
41433
42145
|
}
|
|
41434
42146
|
|
|
41435
|
-
//
|
|
42147
|
+
// ../circle-ir/dist/analysis/passes/naming-convention-pass.js
|
|
41436
42148
|
var PASCAL_CASE_RE = /^[A-Z][A-Za-z0-9]*$/;
|
|
41437
42149
|
var CAMEL_CASE_RE = /^[a-z][a-zA-Z0-9]*$/;
|
|
41438
42150
|
var SNAKE_CASE_RE = /^[a-z_][a-z0-9_]*$/;
|
|
@@ -41572,7 +42284,7 @@ class NamingConventionPass {
|
|
|
41572
42284
|
}
|
|
41573
42285
|
}
|
|
41574
42286
|
|
|
41575
|
-
//
|
|
42287
|
+
// ../circle-ir/dist/analysis/passes/security-headers-pass.js
|
|
41576
42288
|
var HEADER_WRITE_METHODS = new Set([
|
|
41577
42289
|
"setHeader",
|
|
41578
42290
|
"addHeader",
|
|
@@ -42033,7 +42745,7 @@ function mapReturnValueToCorsRule(returnValue) {
|
|
|
42033
42745
|
};
|
|
42034
42746
|
}
|
|
42035
42747
|
|
|
42036
|
-
//
|
|
42748
|
+
// ../circle-ir/dist/analysis/passes/_fp-allowlists.js
|
|
42037
42749
|
var PEM_BODY_RE = /[A-Za-z0-9+/]{30,}/;
|
|
42038
42750
|
function pemHasInlineBody(lines, hitLineIdx) {
|
|
42039
42751
|
const end = Math.min(hitLineIdx + 5, lines.length);
|
|
@@ -42060,7 +42772,7 @@ function isProtocolMandatedCryptoFile(file, code) {
|
|
|
42060
42772
|
return false;
|
|
42061
42773
|
}
|
|
42062
42774
|
|
|
42063
|
-
//
|
|
42775
|
+
// ../circle-ir/dist/analysis/passes/scan-secrets-pass.js
|
|
42064
42776
|
function applyDemoDowngrade(demoPath, severity, level) {
|
|
42065
42777
|
if (!demoPath)
|
|
42066
42778
|
return { severity, level };
|
|
@@ -42638,7 +43350,7 @@ class ScanSecretsPass {
|
|
|
42638
43350
|
}
|
|
42639
43351
|
}
|
|
42640
43352
|
|
|
42641
|
-
//
|
|
43353
|
+
// ../circle-ir/dist/analysis/passes/python-receiver-taint-format-pass.js
|
|
42642
43354
|
class PythonReceiverTaintFormatPass {
|
|
42643
43355
|
name = "python-receiver-taint-format";
|
|
42644
43356
|
category = "security";
|
|
@@ -42690,7 +43402,7 @@ class PythonReceiverTaintFormatPass {
|
|
|
42690
43402
|
}
|
|
42691
43403
|
}
|
|
42692
43404
|
|
|
42693
|
-
//
|
|
43405
|
+
// ../circle-ir/dist/analysis/passes/spring4shell-pass.js
|
|
42694
43406
|
var CONTROLLER_ANNOTATIONS = new Set([
|
|
42695
43407
|
"Controller",
|
|
42696
43408
|
"RestController",
|
|
@@ -42898,7 +43610,7 @@ function isPotentialPojo(type) {
|
|
|
42898
43610
|
return first >= 65 && first <= 90;
|
|
42899
43611
|
}
|
|
42900
43612
|
|
|
42901
|
-
//
|
|
43613
|
+
// ../circle-ir/dist/analysis/passes/insecure-cookie-pass.js
|
|
42902
43614
|
var COOKIE_RESPONSE_RECEIVERS = new Set([
|
|
42903
43615
|
"res",
|
|
42904
43616
|
"response",
|
|
@@ -43134,7 +43846,7 @@ class InsecureCookiePass {
|
|
|
43134
43846
|
}
|
|
43135
43847
|
}
|
|
43136
43848
|
|
|
43137
|
-
//
|
|
43849
|
+
// ../circle-ir/dist/analysis/passes/weak-hash-pass.js
|
|
43138
43850
|
var WEAK_HASH_NAMES = new Set([
|
|
43139
43851
|
"md2",
|
|
43140
43852
|
"md4",
|
|
@@ -43354,7 +44066,7 @@ class WeakHashPass {
|
|
|
43354
44066
|
}
|
|
43355
44067
|
}
|
|
43356
44068
|
|
|
43357
|
-
//
|
|
44069
|
+
// ../circle-ir/dist/analysis/path-classification.js
|
|
43358
44070
|
var TEST_PATH_PATTERNS = [
|
|
43359
44071
|
/(^|\/)test\//i,
|
|
43360
44072
|
/(^|\/)tests\//i,
|
|
@@ -43391,7 +44103,7 @@ function isTestPath(filepath) {
|
|
|
43391
44103
|
return false;
|
|
43392
44104
|
}
|
|
43393
44105
|
|
|
43394
|
-
//
|
|
44106
|
+
// ../circle-ir/dist/analysis/passes/weak-crypto-pass.js
|
|
43395
44107
|
var WEAK_CIPHER_BASES = new Set([
|
|
43396
44108
|
"des",
|
|
43397
44109
|
"3des",
|
|
@@ -43896,7 +44608,7 @@ class WeakCryptoPass {
|
|
|
43896
44608
|
}
|
|
43897
44609
|
}
|
|
43898
44610
|
|
|
43899
|
-
//
|
|
44611
|
+
// ../circle-ir/dist/analysis/passes/weak-random-pass.js
|
|
43900
44612
|
var JAVA_RANDOM_METHODS = new Set([
|
|
43901
44613
|
"nextInt",
|
|
43902
44614
|
"nextLong",
|
|
@@ -44069,7 +44781,7 @@ class WeakRandomPass {
|
|
|
44069
44781
|
}
|
|
44070
44782
|
}
|
|
44071
44783
|
|
|
44072
|
-
//
|
|
44784
|
+
// ../circle-ir/dist/analysis/passes/_credential-helpers.js
|
|
44073
44785
|
var CRED_KEYWORD_RE2 = /(?:password|passwd|pwd|secret|api[_-]?key|auth[_-]?token|private[_-]?key|access[_-]?key|credential)/i;
|
|
44074
44786
|
function isCredentialIdentifier(name2) {
|
|
44075
44787
|
if (!name2)
|
|
@@ -44162,7 +44874,7 @@ function priorHashOf(varName, priorCalls) {
|
|
|
44162
44874
|
return false;
|
|
44163
44875
|
}
|
|
44164
44876
|
|
|
44165
|
-
//
|
|
44877
|
+
// ../circle-ir/dist/analysis/passes/weak-password-hash-pass.js
|
|
44166
44878
|
var FAST_HASH_NAMES = new Set([
|
|
44167
44879
|
"sha224",
|
|
44168
44880
|
"sha-224",
|
|
@@ -44321,7 +45033,7 @@ class WeakPasswordHashPass {
|
|
|
44321
45033
|
}
|
|
44322
45034
|
}
|
|
44323
45035
|
|
|
44324
|
-
//
|
|
45036
|
+
// ../circle-ir/dist/analysis/passes/weak-password-encoding-pass.js
|
|
44325
45037
|
function isBasicAuthContext(call, code) {
|
|
44326
45038
|
const line = call.location.line;
|
|
44327
45039
|
if (line < 1)
|
|
@@ -44433,7 +45145,7 @@ class WeakPasswordEncodingPass {
|
|
|
44433
45145
|
}
|
|
44434
45146
|
}
|
|
44435
45147
|
|
|
44436
|
-
//
|
|
45148
|
+
// ../circle-ir/dist/analysis/passes/info-disclosure-stacktrace-pass.js
|
|
44437
45149
|
var RESPONSE_RECEIVER_RE = /^(res|response|w|writer|ctx|c)$/i;
|
|
44438
45150
|
var LOGGER_RECEIVER_RE = /^(log|logger|slog|console|pino|winston|sentry)$/i;
|
|
44439
45151
|
var RESPONSE_SEND_METHODS = new Set([
|
|
@@ -44619,7 +45331,7 @@ class InfoDisclosureStacktracePass {
|
|
|
44619
45331
|
}
|
|
44620
45332
|
}
|
|
44621
45333
|
|
|
44622
|
-
//
|
|
45334
|
+
// ../circle-ir/dist/analysis/passes/unrestricted-file-upload-pass.js
|
|
44623
45335
|
var UPLOAD_NAME_RE = /(?:getOriginalFilename|getSubmittedFileName|originalname|originalName|\.filename|\.Filename|FileHeader\.Filename|UploadFile)/;
|
|
44624
45336
|
var FILE_SAFE_CALL_RE = /(?:secure_filename|FilenameUtils\.getExtension|\.lastIndexOf\(['"]\.['"]\)|ALLOWED_EXT|ALLOWED_EXTENSIONS|allowedExtensions|\bfileFilter\b|filepath\.Ext|path\.extname)/;
|
|
44625
45337
|
function lineWindow(lines, startLine, endLine) {
|
|
@@ -44770,7 +45482,7 @@ class UnrestrictedFileUploadPass {
|
|
|
44770
45482
|
}
|
|
44771
45483
|
}
|
|
44772
45484
|
|
|
44773
|
-
//
|
|
45485
|
+
// ../circle-ir/dist/analysis/passes/missing-sanitizer-gate-pass.js
|
|
44774
45486
|
var HTML_OUTPUT_SINKS = new Set([
|
|
44775
45487
|
"addAttribute",
|
|
44776
45488
|
"setAttribute",
|
|
@@ -44918,7 +45630,7 @@ function methodAcceptsHtmlShapedParam(method) {
|
|
|
44918
45630
|
return false;
|
|
44919
45631
|
}
|
|
44920
45632
|
|
|
44921
|
-
//
|
|
45633
|
+
// ../circle-ir/dist/analysis/passes/insecure-deserialization-config-pass.js
|
|
44922
45634
|
var ANY_TYPE_PERMISSION_RE = /\bAnyTypePermission\b/;
|
|
44923
45635
|
|
|
44924
45636
|
class InsecureDeserializationConfigPass {
|
|
@@ -44996,7 +45708,7 @@ class InsecureDeserializationConfigPass {
|
|
|
44996
45708
|
}
|
|
44997
45709
|
var INSECURE_TYPE_NAME_HANDLING_RE = /\bTypeNameHandling\s*=\s*(?:Newtonsoft\.Json\.)?TypeNameHandling\.(All|Auto|Objects|Arrays)\b/;
|
|
44998
45710
|
|
|
44999
|
-
//
|
|
45711
|
+
// ../circle-ir/dist/analysis/passes/plaintext-password-storage-pass.js
|
|
45000
45712
|
function isWriteStorageCall(call, language) {
|
|
45001
45713
|
const method = call.method_name ?? "";
|
|
45002
45714
|
const receiver = call.receiver ?? "";
|
|
@@ -45107,7 +45819,7 @@ class PlaintextPasswordStoragePass {
|
|
|
45107
45819
|
}
|
|
45108
45820
|
}
|
|
45109
45821
|
|
|
45110
|
-
//
|
|
45822
|
+
// ../circle-ir/dist/analysis/passes/cleartext-credential-transport-pass.js
|
|
45111
45823
|
var LOCALHOST_RE = /^(?:localhost|127\.0\.0\.1|0\.0\.0\.0)(?::\d+)?$/i;
|
|
45112
45824
|
function isInsecureHttpUrl(urlLiteral) {
|
|
45113
45825
|
if (!urlLiteral)
|
|
@@ -45235,7 +45947,7 @@ class CleartextCredentialTransportPass {
|
|
|
45235
45947
|
}
|
|
45236
45948
|
}
|
|
45237
45949
|
|
|
45238
|
-
//
|
|
45950
|
+
// ../circle-ir/dist/analysis/passes/tls-verify-disabled-pass.js
|
|
45239
45951
|
var PY_HTTP_METHODS = new Set([
|
|
45240
45952
|
"get",
|
|
45241
45953
|
"post",
|
|
@@ -45448,7 +46160,7 @@ class TlsVerifyDisabledPass {
|
|
|
45448
46160
|
}
|
|
45449
46161
|
}
|
|
45450
46162
|
|
|
45451
|
-
//
|
|
46163
|
+
// ../circle-ir/dist/analysis/passes/module-side-effect-pass.js
|
|
45452
46164
|
var JS_EXEC_METHODS = new Set([
|
|
45453
46165
|
"exec",
|
|
45454
46166
|
"spawn",
|
|
@@ -45679,7 +46391,7 @@ class ModuleSideEffectPass {
|
|
|
45679
46391
|
}
|
|
45680
46392
|
}
|
|
45681
46393
|
|
|
45682
|
-
//
|
|
46394
|
+
// ../circle-ir/dist/analysis/passes/cache-no-vary-pass.js
|
|
45683
46395
|
function isSharedCacheable(value) {
|
|
45684
46396
|
const v = value.toLowerCase();
|
|
45685
46397
|
if (/\b(private|no-store|no-cache)\b/.test(v))
|
|
@@ -45966,7 +46678,7 @@ class CacheNoVaryPass {
|
|
|
45966
46678
|
}
|
|
45967
46679
|
}
|
|
45968
46680
|
|
|
45969
|
-
//
|
|
46681
|
+
// ../circle-ir/dist/analysis/passes/jwt-verify-disabled-pass.js
|
|
45970
46682
|
var PY_VERIFY_SIGNATURE_FALSE_RE = /["']verify_signature["']\s*:\s*False\b/;
|
|
45971
46683
|
var PY_VERIFY_KW_FALSE_RE = /\bverify\s*=\s*False\b/;
|
|
45972
46684
|
var PY_ALG_NONE_RE = /\balgorithms\s*=\s*[\[\(]\s*["']none["']/i;
|
|
@@ -46091,7 +46803,7 @@ class JwtVerifyDisabledPass {
|
|
|
46091
46803
|
}
|
|
46092
46804
|
}
|
|
46093
46805
|
|
|
46094
|
-
//
|
|
46806
|
+
// ../circle-ir/dist/analysis/passes/csrf-protection-disabled-pass.js
|
|
46095
46807
|
var JAVA_CSRF_DISABLE_RE = /\.csrf\s*\([^)]*\)\s*\.\s*disable\b/;
|
|
46096
46808
|
var JAVA_CSRF_LAMBDA_DISABLE_RE = /\bcsrf\s*\(\s*\w+\s*->\s*\w+\s*\.\s*disable\s*\(/;
|
|
46097
46809
|
var JAVA_CSRF_METHODREF_RE = /\bcsrf\s*\(\s*[\w.]+::disable\s*\)/;
|
|
@@ -46227,7 +46939,7 @@ class CsrfProtectionDisabledPass {
|
|
|
46227
46939
|
}
|
|
46228
46940
|
}
|
|
46229
46941
|
|
|
46230
|
-
//
|
|
46942
|
+
// ../circle-ir/dist/analysis/passes/xml-entity-expansion-pass.js
|
|
46231
46943
|
var JAVA_FACTORIES = new Set([
|
|
46232
46944
|
"SAXParserFactory",
|
|
46233
46945
|
"DocumentBuilderFactory",
|
|
@@ -46367,7 +47079,7 @@ class XmlEntityExpansionPass {
|
|
|
46367
47079
|
}
|
|
46368
47080
|
}
|
|
46369
47081
|
|
|
46370
|
-
//
|
|
47082
|
+
// ../circle-ir/dist/analysis/passes/mass-assignment-pass.js
|
|
46371
47083
|
var PY_KWARGS_SPLAT_RE = /\*\*\s*(?:request|self\.request|flask\.request|ctx|self)\s*\.\s*(?:form|args|values|json|get_json\s*\(\s*\)|files|data)/;
|
|
46372
47084
|
var JS_OBJECT_SPREAD_RE = /\{\s*\.\.\.\s*(?:req|request|ctx|context)(?:\.request)?\s*\.\s*(?:body|query|params|form)\b/;
|
|
46373
47085
|
|
|
@@ -46451,7 +47163,7 @@ class MassAssignmentPass {
|
|
|
46451
47163
|
}
|
|
46452
47164
|
}
|
|
46453
47165
|
|
|
46454
|
-
//
|
|
47166
|
+
// ../circle-ir/dist/graph/import-graph.js
|
|
46455
47167
|
function dirname(filePath) {
|
|
46456
47168
|
const idx = filePath.lastIndexOf("/");
|
|
46457
47169
|
return idx >= 0 ? filePath.slice(0, idx) : "";
|
|
@@ -46584,7 +47296,7 @@ class ImportGraph2 {
|
|
|
46584
47296
|
}
|
|
46585
47297
|
}
|
|
46586
47298
|
|
|
46587
|
-
//
|
|
47299
|
+
// ../circle-ir/dist/analysis/passes/circular-dependency-pass.js
|
|
46588
47300
|
class CircularDependencyPass {
|
|
46589
47301
|
run(_projectGraph, importGraph) {
|
|
46590
47302
|
const findings = [];
|
|
@@ -46611,7 +47323,7 @@ class CircularDependencyPass {
|
|
|
46611
47323
|
}
|
|
46612
47324
|
}
|
|
46613
47325
|
|
|
46614
|
-
//
|
|
47326
|
+
// ../circle-ir/dist/analysis/passes/orphan-module-pass.js
|
|
46615
47327
|
class OrphanModulePass {
|
|
46616
47328
|
run(_projectGraph, importGraph) {
|
|
46617
47329
|
const findings = [];
|
|
@@ -46635,7 +47347,7 @@ class OrphanModulePass {
|
|
|
46635
47347
|
}
|
|
46636
47348
|
}
|
|
46637
47349
|
|
|
46638
|
-
//
|
|
47350
|
+
// ../circle-ir/dist/analysis/metrics/passes/size-metrics-pass.js
|
|
46639
47351
|
class SizeMetricsPass {
|
|
46640
47352
|
name = "size-metrics";
|
|
46641
47353
|
run(ctx) {
|
|
@@ -46691,7 +47403,7 @@ class SizeMetricsPass {
|
|
|
46691
47403
|
}
|
|
46692
47404
|
}
|
|
46693
47405
|
|
|
46694
|
-
//
|
|
47406
|
+
// ../circle-ir/dist/analysis/metrics/passes/complexity-metrics-pass.js
|
|
46695
47407
|
class ComplexityMetricsPass {
|
|
46696
47408
|
name = "complexity-metrics";
|
|
46697
47409
|
run(ctx) {
|
|
@@ -46755,7 +47467,7 @@ class ComplexityMetricsPass {
|
|
|
46755
47467
|
}
|
|
46756
47468
|
}
|
|
46757
47469
|
|
|
46758
|
-
//
|
|
47470
|
+
// ../circle-ir/dist/analysis/metrics/passes/halstead-metrics-pass.js
|
|
46759
47471
|
var KEYWORDS = new Set([
|
|
46760
47472
|
"if",
|
|
46761
47473
|
"else",
|
|
@@ -46910,7 +47622,7 @@ class HalsteadMetricsPass {
|
|
|
46910
47622
|
}
|
|
46911
47623
|
}
|
|
46912
47624
|
|
|
46913
|
-
//
|
|
47625
|
+
// ../circle-ir/dist/analysis/metrics/passes/data-flow-metrics-pass.js
|
|
46914
47626
|
class DataFlowMetricsPass {
|
|
46915
47627
|
name = "data-flow-metrics";
|
|
46916
47628
|
run(ctx) {
|
|
@@ -46928,7 +47640,7 @@ class DataFlowMetricsPass {
|
|
|
46928
47640
|
}
|
|
46929
47641
|
}
|
|
46930
47642
|
|
|
46931
|
-
//
|
|
47643
|
+
// ../circle-ir/dist/analysis/metrics/passes/coupling-metrics-pass.js
|
|
46932
47644
|
class CouplingMetricsPass {
|
|
46933
47645
|
name = "coupling-metrics";
|
|
46934
47646
|
run(ctx) {
|
|
@@ -47006,7 +47718,7 @@ class CouplingMetricsPass {
|
|
|
47006
47718
|
}
|
|
47007
47719
|
}
|
|
47008
47720
|
|
|
47009
|
-
//
|
|
47721
|
+
// ../circle-ir/dist/analysis/metrics/passes/inheritance-metrics-pass.js
|
|
47010
47722
|
class InheritanceMetricsPass {
|
|
47011
47723
|
name = "inheritance-metrics";
|
|
47012
47724
|
run(ctx) {
|
|
@@ -47066,7 +47778,7 @@ class InheritanceMetricsPass {
|
|
|
47066
47778
|
}
|
|
47067
47779
|
}
|
|
47068
47780
|
|
|
47069
|
-
//
|
|
47781
|
+
// ../circle-ir/dist/analysis/metrics/passes/cohesion-metrics-pass.js
|
|
47070
47782
|
class CohesionMetricsPass {
|
|
47071
47783
|
name = "cohesion-metrics";
|
|
47072
47784
|
run(ctx) {
|
|
@@ -47149,7 +47861,7 @@ class CohesionMetricsPass {
|
|
|
47149
47861
|
}
|
|
47150
47862
|
}
|
|
47151
47863
|
|
|
47152
|
-
//
|
|
47864
|
+
// ../circle-ir/dist/analysis/metrics/passes/documentation-metrics-pass.js
|
|
47153
47865
|
class DocumentationMetricsPass {
|
|
47154
47866
|
name = "documentation-metrics";
|
|
47155
47867
|
run(ctx) {
|
|
@@ -47202,7 +47914,7 @@ class DocumentationMetricsPass {
|
|
|
47202
47914
|
}
|
|
47203
47915
|
}
|
|
47204
47916
|
|
|
47205
|
-
//
|
|
47917
|
+
// ../circle-ir/dist/analysis/metrics/passes/composite-metrics-pass.js
|
|
47206
47918
|
class CompositeMetricsPass {
|
|
47207
47919
|
name = "composite-metrics";
|
|
47208
47920
|
run(ctx) {
|
|
@@ -47261,7 +47973,7 @@ class CompositeMetricsPass {
|
|
|
47261
47973
|
}
|
|
47262
47974
|
}
|
|
47263
47975
|
|
|
47264
|
-
//
|
|
47976
|
+
// ../circle-ir/dist/analysis/metrics/metric-runner.js
|
|
47265
47977
|
class MetricRunner {
|
|
47266
47978
|
passes = [
|
|
47267
47979
|
new SizeMetricsPass,
|
|
@@ -47283,7 +47995,7 @@ class MetricRunner {
|
|
|
47283
47995
|
return accumulated;
|
|
47284
47996
|
}
|
|
47285
47997
|
}
|
|
47286
|
-
//
|
|
47998
|
+
// ../circle-ir/dist/analyzer.js
|
|
47287
47999
|
var initialized = false;
|
|
47288
48000
|
async function initAnalyzer(options = {}) {
|
|
47289
48001
|
if (initialized)
|
|
@@ -47599,8 +48311,6 @@ async function analyze(code, filePath, language, options = {}) {
|
|
|
47599
48311
|
pipeline.add(new LanguageSourcesPass);
|
|
47600
48312
|
if (!disabledPasses.has("source-semantics"))
|
|
47601
48313
|
pipeline.add(new SourceSemanticsPass);
|
|
47602
|
-
if (!disabledPasses.has("library-profile-source-gate"))
|
|
47603
|
-
pipeline.add(new LibraryProfileSourceGatePass);
|
|
47604
48314
|
if (!disabledPasses.has("mybatis-annotation-sql-sink"))
|
|
47605
48315
|
pipeline.add(new MyBatisAnnotationSqlSinkPass);
|
|
47606
48316
|
pipeline.add(new SinkFilterPass);
|
|
@@ -47617,6 +48327,8 @@ async function analyze(code, filePath, language, options = {}) {
|
|
|
47617
48327
|
pipeline.add(new LibraryProfileSinkGatePass);
|
|
47618
48328
|
if (!disabledPasses.has("library-profile-xss-gate"))
|
|
47619
48329
|
pipeline.add(new LibraryProfileXssGatePass);
|
|
48330
|
+
if (!disabledPasses.has("library-profile-source-gate"))
|
|
48331
|
+
pipeline.add(new LibraryProfileSourceGatePass);
|
|
47620
48332
|
pipeline.add(new TaintPropagationPass);
|
|
47621
48333
|
pipeline.add(new InterproceduralPass({
|
|
47622
48334
|
enableEntryPointGate: options.enableEntryPointGate ?? true
|
|
@@ -47880,7 +48592,19 @@ async function analyzeProject(files, options = {}) {
|
|
|
47880
48592
|
const fileAnalyses = [];
|
|
47881
48593
|
const projectGraph = new ProjectGraph;
|
|
47882
48594
|
const sourceLinesByFile = new Map;
|
|
48595
|
+
const perFileBudgetMs = options.perFileBudgetMs ?? 0;
|
|
48596
|
+
const perFileStart = Date.now();
|
|
48597
|
+
let perFileBudgetExceeded = false;
|
|
47883
48598
|
for (const { code, filePath, language } of files) {
|
|
48599
|
+
if (perFileBudgetMs > 0 && Date.now() - perFileStart > perFileBudgetMs) {
|
|
48600
|
+
perFileBudgetExceeded = true;
|
|
48601
|
+
logger.warn("analyzeProject: per-file budget exceeded, skipping remaining files", {
|
|
48602
|
+
analysed: fileAnalyses.length,
|
|
48603
|
+
total: files.length,
|
|
48604
|
+
budgetMs: perFileBudgetMs
|
|
48605
|
+
});
|
|
48606
|
+
break;
|
|
48607
|
+
}
|
|
47884
48608
|
const ir = await analyze(code, filePath, language, options);
|
|
47885
48609
|
fileAnalyses.push({ file: filePath, analysis: ir });
|
|
47886
48610
|
projectGraph.addFile(filePath, new CodeGraph(ir));
|
|
@@ -47936,6 +48660,9 @@ async function analyzeProject(files, options = {}) {
|
|
|
47936
48660
|
if (crossFileResult.budgetExceeded) {
|
|
47937
48661
|
projectAnalysis.cross_file_budget_exceeded = true;
|
|
47938
48662
|
}
|
|
48663
|
+
if (perFileBudgetExceeded) {
|
|
48664
|
+
projectAnalysis.per_file_budget_exceeded = true;
|
|
48665
|
+
}
|
|
47939
48666
|
return projectAnalysis;
|
|
47940
48667
|
}
|
|
47941
48668
|
function deriveProjectName(paths) {
|
|
@@ -47955,7 +48682,7 @@ function deriveProjectRoot(paths) {
|
|
|
47955
48682
|
}
|
|
47956
48683
|
return common.join("/") || "/";
|
|
47957
48684
|
}
|
|
47958
|
-
//
|
|
48685
|
+
// ../circle-ir/dist/analysis/sbom.js
|
|
47959
48686
|
function purlVersion(spec) {
|
|
47960
48687
|
const stripped = spec.trim().replace(/^[\s^~=<>]+/, "");
|
|
47961
48688
|
if (/^v?[0-9][\w.\-+]*$/.test(stripped))
|
|
@@ -49011,7 +49738,7 @@ var colors = {
|
|
|
49011
49738
|
};
|
|
49012
49739
|
|
|
49013
49740
|
// src/version.ts
|
|
49014
|
-
var version = "4.9.
|
|
49741
|
+
var version = "4.9.20";
|
|
49015
49742
|
|
|
49016
49743
|
// src/formatters.ts
|
|
49017
49744
|
var LIBRARY_API_SURFACE_TAG2 = "library-api-surface:caller-responsibility";
|
|
@@ -49564,8 +50291,8 @@ function generateSarifResults(results, crossFileData) {
|
|
|
49564
50291
|
|
|
49565
50292
|
// src/build-info.ts
|
|
49566
50293
|
var buildInfo = {
|
|
49567
|
-
gitSha: "
|
|
49568
|
-
builtAt: "2026-09-
|
|
50294
|
+
gitSha: "eb03cc5",
|
|
50295
|
+
builtAt: "2026-09-19T19:54:44.551Z"
|
|
49569
50296
|
};
|
|
49570
50297
|
|
|
49571
50298
|
// src/utils/args.ts
|