cognium-dev 4.9.17 → 4.9.19
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 -209
- 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 },
|
|
@@ -11533,8 +11575,8 @@ var DEFAULT_SINKS = [
|
|
|
11533
11575
|
{ method: "selectByExample", class: "*Mapper", type: "mybatis_mapper_call", cwe: "CWE-89", severity: "medium", arg_positions: [0], languages: ["java"] },
|
|
11534
11576
|
{ method: "exec", class: "Runtime", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1] },
|
|
11535
11577
|
{ 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] },
|
|
11578
|
+
{ method: "ProcessBuilder", class: "constructor", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1, 2, 3, 4, 5, 6, 7] },
|
|
11579
|
+
{ method: "command", class: "ProcessBuilder", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1, 2, 3, 4, 5, 6, 7] },
|
|
11538
11580
|
{ method: "execute", class: "DefaultExecutor", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
11539
11581
|
{ method: "CommandLine", class: "constructor", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
11540
11582
|
{ method: "parse", class: "CommandLine", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
@@ -12335,7 +12377,6 @@ var DEFAULT_SINKS = [
|
|
|
12335
12377
|
{ method: "fatal", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [0, 1, 2, 3, 4] },
|
|
12336
12378
|
{ method: "log", class: "logging", type: "log_injection", cwe: "CWE-117", severity: "low", arg_positions: [1, 2, 3, 4] },
|
|
12337
12379
|
{ 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
12380
|
{ method: "step", class: "StepExecution", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
|
|
12340
12381
|
{ method: "invokeMethod", class: "Script", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1] },
|
|
12341
12382
|
{ method: "evaluate", class: "Script", type: "code_injection", cwe: "CWE-94", severity: "critical", arg_positions: [0] },
|
|
@@ -13097,7 +13138,33 @@ var DEFAULT_HEADER_RULES = [
|
|
|
13097
13138
|
note: "Fires when the value is not a string literal (likely reflected from request)"
|
|
13098
13139
|
}
|
|
13099
13140
|
];
|
|
13100
|
-
//
|
|
13141
|
+
// ../circle-ir/dist/analysis/literal-expression.js
|
|
13142
|
+
function isProvablyLiteralExpression(expr) {
|
|
13143
|
+
let e = (expr ?? "").trim();
|
|
13144
|
+
if (e.length === 0)
|
|
13145
|
+
return false;
|
|
13146
|
+
e = e.replace(/\/\/.*$/, "").replace(/;\s*$/, "").trim();
|
|
13147
|
+
if (e.length === 0)
|
|
13148
|
+
return false;
|
|
13149
|
+
if (e.includes("${"))
|
|
13150
|
+
return false;
|
|
13151
|
+
if (/[+]\s*$/.test(e))
|
|
13152
|
+
return false;
|
|
13153
|
+
const stripped = e.replace(/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|`(?:[^`\\$]|\\.)*`/g, "");
|
|
13154
|
+
if (/["'`]/.test(stripped))
|
|
13155
|
+
return false;
|
|
13156
|
+
return /^[\s+()]*$/.test(stripped);
|
|
13157
|
+
}
|
|
13158
|
+
var DOM_ASSIGNMENT_SINK_METHODS = new Set([
|
|
13159
|
+
"innerHTML",
|
|
13160
|
+
"outerHTML",
|
|
13161
|
+
"cssText",
|
|
13162
|
+
"src",
|
|
13163
|
+
"href",
|
|
13164
|
+
"textContent"
|
|
13165
|
+
]);
|
|
13166
|
+
|
|
13167
|
+
// ../circle-ir/dist/analysis/arg-type-resolver.js
|
|
13101
13168
|
function findEnclosingType(callInMethod, types) {
|
|
13102
13169
|
if (!callInMethod)
|
|
13103
13170
|
return null;
|
|
@@ -13175,7 +13242,7 @@ function isArgvContainerType(rawType) {
|
|
|
13175
13242
|
return /^(?:List|ArrayList|LinkedList|Collection|Iterable|Deque|Queue)\s*<\s*(?:String|CharSequence|java\.lang\.String)\b/.test(s);
|
|
13176
13243
|
}
|
|
13177
13244
|
|
|
13178
|
-
//
|
|
13245
|
+
// ../circle-ir/dist/analysis/taint-matcher.js
|
|
13179
13246
|
var PYTHON_TAINTED_PATTERNS = [
|
|
13180
13247
|
{ pattern: /\brequest\.args\b/, sourceType: "http_param" },
|
|
13181
13248
|
{ pattern: /\brequest\.form\b/, sourceType: "http_body" },
|
|
@@ -14050,7 +14117,7 @@ function isCSharpSsrfHostAllowlistGuarded(call, pattern, language, sourceLines)
|
|
|
14050
14117
|
if (!guards)
|
|
14051
14118
|
continue;
|
|
14052
14119
|
for (const g of guards) {
|
|
14053
|
-
if (g.i
|
|
14120
|
+
if (g.i > sinkIdx || checked.has(g))
|
|
14054
14121
|
continue;
|
|
14055
14122
|
checked.add(g);
|
|
14056
14123
|
const block = csThenBlock(sourceLines, g.i, g.rest);
|
|
@@ -14193,6 +14260,21 @@ function isRegexReceiver(receiver, sourceLines) {
|
|
|
14193
14260
|
const decl = new RegExp(`(?:const|let|var)\\s+${escapeRe(r)}\\s*=\\s*(?:/|(?:new\\s+)?RegExp\\s*\\()`);
|
|
14194
14261
|
return sourceLines.some((l) => decl.test(l));
|
|
14195
14262
|
}
|
|
14263
|
+
function isDeclaredFunctionReference(arg, sourceLines) {
|
|
14264
|
+
if (arg.literal !== null && arg.literal !== undefined)
|
|
14265
|
+
return false;
|
|
14266
|
+
if (!sourceLines)
|
|
14267
|
+
return false;
|
|
14268
|
+
const name2 = (arg.expression ?? "").trim();
|
|
14269
|
+
if (!/^[A-Za-z_$][\w$]*$/.test(name2))
|
|
14270
|
+
return false;
|
|
14271
|
+
const n = escapeRe(name2);
|
|
14272
|
+
const decls = [
|
|
14273
|
+
new RegExp(`\\bfunction\\s+${n}\\s*\\(`),
|
|
14274
|
+
new RegExp(`\\b(?:const|let|var)\\s+${n}\\s*=\\s*(?:async\\s+)?(?:function\\b|\\(|[A-Za-z_$][\\w$]*\\s*=>)`)
|
|
14275
|
+
];
|
|
14276
|
+
return sourceLines.some((l) => decls.some((re) => re.test(l)));
|
|
14277
|
+
}
|
|
14196
14278
|
function isFunctionCallbackArgument(arg) {
|
|
14197
14279
|
if (arg.literal !== null && arg.literal !== undefined)
|
|
14198
14280
|
return false;
|
|
@@ -14396,11 +14478,17 @@ function findSinks(calls, patterns, typeHierarchy, language, sourceLines, types)
|
|
|
14396
14478
|
}
|
|
14397
14479
|
if (pattern.type === "code_injection" && (call.method_name === "setInterval" || call.method_name === "setTimeout" || call.method_name === "setImmediate")) {
|
|
14398
14480
|
const firstArg = call.arguments.find((a) => a.position === 0);
|
|
14399
|
-
if (firstArg && isFunctionCallbackArgument(firstArg)) {
|
|
14481
|
+
if (firstArg && (isFunctionCallbackArgument(firstArg) || isDeclaredFunctionReference(firstArg, sourceLines))) {
|
|
14400
14482
|
continue;
|
|
14401
14483
|
}
|
|
14402
14484
|
}
|
|
14403
|
-
if (pattern.type === "
|
|
14485
|
+
if (pattern.type === "xss" && (language === "javascript" || language === "typescript") && DOM_ASSIGNMENT_SINK_METHODS.has(call.method_name) && call.arguments.length > 0) {
|
|
14486
|
+
const rhs = call.arguments.find((a) => a.position === 0);
|
|
14487
|
+
if (rhs && isProvablyLiteralExpression(rhs.expression ?? "")) {
|
|
14488
|
+
continue;
|
|
14489
|
+
}
|
|
14490
|
+
}
|
|
14491
|
+
if ((pattern.type === "command_injection" || pattern.type === "sql_injection") && call.method_name === "exec" && (language === "javascript" || language === "typescript") && isRegexReceiver(call.receiver, sourceLines)) {
|
|
14404
14492
|
continue;
|
|
14405
14493
|
}
|
|
14406
14494
|
if (pattern.type === "code_injection" && language === "python" && call.method_name === "compile" && call.receiver && call.receiver !== "builtins") {
|
|
@@ -15216,7 +15304,7 @@ function formatSanitizerMethod(call) {
|
|
|
15216
15304
|
return `${call.method_name}()`;
|
|
15217
15305
|
}
|
|
15218
15306
|
|
|
15219
|
-
//
|
|
15307
|
+
// ../circle-ir/dist/analysis/unresolved.js
|
|
15220
15308
|
function detectUnresolved(calls, types, dfg) {
|
|
15221
15309
|
const unresolved = [];
|
|
15222
15310
|
unresolved.push(...detectVirtualDispatch(calls));
|
|
@@ -15380,7 +15468,7 @@ function formatCallCode(call) {
|
|
|
15380
15468
|
}
|
|
15381
15469
|
return `${call.method_name}(${args2})`;
|
|
15382
15470
|
}
|
|
15383
|
-
//
|
|
15471
|
+
// ../circle-ir/dist/analysis/non-executable-lines.js
|
|
15384
15472
|
function isNonExecutableSourceLine(sourceCode, line, language) {
|
|
15385
15473
|
if (!sourceCode || line < 1)
|
|
15386
15474
|
return false;
|
|
@@ -15440,7 +15528,7 @@ function isNonExecutablePython(trimmed) {
|
|
|
15440
15528
|
return false;
|
|
15441
15529
|
}
|
|
15442
15530
|
|
|
15443
|
-
//
|
|
15531
|
+
// ../circle-ir/dist/analysis/sanitizer-index.js
|
|
15444
15532
|
var SANITIZER_SET_CACHE = new WeakMap;
|
|
15445
15533
|
function getSanitizesSet(san) {
|
|
15446
15534
|
let s = SANITIZER_SET_CACHE.get(san);
|
|
@@ -15454,7 +15542,7 @@ function sanitizerCoversSink(san, sinkType) {
|
|
|
15454
15542
|
return getSanitizesSet(san).has(sinkType);
|
|
15455
15543
|
}
|
|
15456
15544
|
|
|
15457
|
-
//
|
|
15545
|
+
// ../circle-ir/dist/analysis/dfg-walk.js
|
|
15458
15546
|
var walkBackwardDefsMemo = new WeakMap;
|
|
15459
15547
|
function walkBackwardDefs(startDefId, chainsByToDef, defById, options = {}) {
|
|
15460
15548
|
const maxHops = options.maxHops ?? 32;
|
|
@@ -15507,7 +15595,7 @@ function walkBackwardDefs(startDefId, chainsByToDef, defById, options = {}) {
|
|
|
15507
15595
|
return result;
|
|
15508
15596
|
}
|
|
15509
15597
|
|
|
15510
|
-
//
|
|
15598
|
+
// ../circle-ir/dist/analysis/findings.js
|
|
15511
15599
|
function canSourceReachSink(sourceType, sinkType) {
|
|
15512
15600
|
const sourceToSinkMapping = {
|
|
15513
15601
|
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 +15626,7 @@ function sourceSemanticsAllowed(source, sinkType) {
|
|
|
15538
15626
|
return true;
|
|
15539
15627
|
}
|
|
15540
15628
|
|
|
15541
|
-
//
|
|
15629
|
+
// ../circle-ir/dist/analysis/findings-instrumentation.js
|
|
15542
15630
|
var instrumentEnabled = false;
|
|
15543
15631
|
function setFindingsInstrumentation(enabled) {
|
|
15544
15632
|
instrumentEnabled = enabled;
|
|
@@ -15601,7 +15689,7 @@ function emitFindingsInstrumentation(filePath, findings, taint) {
|
|
|
15601
15689
|
};
|
|
15602
15690
|
console.error(`[findings-summary] ${JSON.stringify(summary)}`);
|
|
15603
15691
|
}
|
|
15604
|
-
//
|
|
15692
|
+
// ../circle-ir/dist/graph/code-graph.js
|
|
15605
15693
|
class CodeGraph {
|
|
15606
15694
|
ir;
|
|
15607
15695
|
constructor(ir) {
|
|
@@ -15811,7 +15899,7 @@ class CodeGraph {
|
|
|
15811
15899
|
return result;
|
|
15812
15900
|
}
|
|
15813
15901
|
}
|
|
15814
|
-
//
|
|
15902
|
+
// ../circle-ir/dist/resolution/type-hierarchy.js
|
|
15815
15903
|
class TypeHierarchyResolver {
|
|
15816
15904
|
types = new Map;
|
|
15817
15905
|
nameToFqn = new Map;
|
|
@@ -16383,7 +16471,7 @@ function registerCommonLibraries(resolver) {
|
|
|
16383
16471
|
resolver.registerFactoryReturnType("HttpClients", "createSystem", "org.apache.http.impl.client.CloseableHttpClient");
|
|
16384
16472
|
resolver.registerFactoryReturnType("HttpClients", "createMinimal", "org.apache.http.impl.client.MinimalHttpClient");
|
|
16385
16473
|
}
|
|
16386
|
-
//
|
|
16474
|
+
// ../circle-ir/dist/resolution/symbol-table.js
|
|
16387
16475
|
class SymbolTable {
|
|
16388
16476
|
exports = new Map;
|
|
16389
16477
|
nameToFqns = new Map;
|
|
@@ -16606,7 +16694,7 @@ class SymbolTable {
|
|
|
16606
16694
|
return "package";
|
|
16607
16695
|
}
|
|
16608
16696
|
}
|
|
16609
|
-
//
|
|
16697
|
+
// ../circle-ir/dist/resolution/cross-file.js
|
|
16610
16698
|
function buildFileIndex(ir) {
|
|
16611
16699
|
const callsByLine = new Map;
|
|
16612
16700
|
for (const c of ir.calls) {
|
|
@@ -17104,10 +17192,12 @@ class CrossFileResolver {
|
|
|
17104
17192
|
}
|
|
17105
17193
|
return callers;
|
|
17106
17194
|
}
|
|
17107
|
-
findCrossFileTaintFlows() {
|
|
17195
|
+
findCrossFileTaintFlows(deadline) {
|
|
17108
17196
|
const flows = [];
|
|
17109
17197
|
const seen = new Set;
|
|
17110
17198
|
for (const [filePath, ir] of this.fileIRs) {
|
|
17199
|
+
if (deadline?.())
|
|
17200
|
+
break;
|
|
17111
17201
|
for (const source of ir.taint.sources) {
|
|
17112
17202
|
if (source.type === "interprocedural_param")
|
|
17113
17203
|
continue;
|
|
@@ -17182,11 +17272,13 @@ class CrossFileResolver {
|
|
|
17182
17272
|
}
|
|
17183
17273
|
return flows;
|
|
17184
17274
|
}
|
|
17185
|
-
findInterproceduralTaintPaths() {
|
|
17275
|
+
findInterproceduralTaintPaths(deadline) {
|
|
17186
17276
|
const paths = [];
|
|
17187
17277
|
const seen = new Set;
|
|
17188
17278
|
const methodIndex = this.buildMethodIndex();
|
|
17189
17279
|
for (const [callerFile, callerIR] of this.fileIRs) {
|
|
17280
|
+
if (deadline?.())
|
|
17281
|
+
break;
|
|
17190
17282
|
const callerIdx = this.getFileIndex(callerIR);
|
|
17191
17283
|
for (const type of callerIR.types) {
|
|
17192
17284
|
for (const method of type.methods) {
|
|
@@ -17325,7 +17417,7 @@ class CrossFileResolver {
|
|
|
17325
17417
|
}
|
|
17326
17418
|
return paths;
|
|
17327
17419
|
}
|
|
17328
|
-
findFieldBindingTaintPaths() {
|
|
17420
|
+
findFieldBindingTaintPaths(deadline) {
|
|
17329
17421
|
const paths = [];
|
|
17330
17422
|
const seen = new Set;
|
|
17331
17423
|
if (this.fieldTaintInfo.size === 0)
|
|
@@ -17333,6 +17425,8 @@ class CrossFileResolver {
|
|
|
17333
17425
|
const fieldExprRe = /^(\w+)\.(\w+)$/;
|
|
17334
17426
|
const methodIndex = this.buildMethodIndex();
|
|
17335
17427
|
for (const [callerFile, callerIR] of this.fileIRs) {
|
|
17428
|
+
if (deadline?.())
|
|
17429
|
+
break;
|
|
17336
17430
|
const callerIdx = this.getFileIndex(callerIR);
|
|
17337
17431
|
for (const type of callerIR.types) {
|
|
17338
17432
|
const callerTypeFqn = callerIR.meta.package ? `${callerIR.meta.package}.${type.name}` : type.name;
|
|
@@ -17694,7 +17788,7 @@ class CrossFileResolver {
|
|
|
17694
17788
|
return this.fieldTaintInfo.get(`${typeFqn}.${fieldName}`);
|
|
17695
17789
|
}
|
|
17696
17790
|
}
|
|
17697
|
-
//
|
|
17791
|
+
// ../circle-ir/dist/graph/project-graph.js
|
|
17698
17792
|
class ProjectGraph {
|
|
17699
17793
|
files = new Map;
|
|
17700
17794
|
_symbolTable = null;
|
|
@@ -17746,7 +17840,7 @@ class ProjectGraph {
|
|
|
17746
17840
|
return this._resolver;
|
|
17747
17841
|
}
|
|
17748
17842
|
}
|
|
17749
|
-
//
|
|
17843
|
+
// ../circle-ir/dist/graph/analysis-pass.js
|
|
17750
17844
|
class AnalysisPipeline {
|
|
17751
17845
|
passes = [];
|
|
17752
17846
|
add(pass) {
|
|
@@ -17793,7 +17887,7 @@ class AnalysisPipeline {
|
|
|
17793
17887
|
return { results, findings };
|
|
17794
17888
|
}
|
|
17795
17889
|
}
|
|
17796
|
-
//
|
|
17890
|
+
// ../circle-ir/dist/analysis/taint-propagation.js
|
|
17797
17891
|
function buildSanitizersByLine(sanitizers) {
|
|
17798
17892
|
const out2 = new Map;
|
|
17799
17893
|
for (const san of sanitizers) {
|
|
@@ -18068,7 +18162,7 @@ function checkSanitized(fromLine, toLine, sinkType, sanitizersByLine, ctx) {
|
|
|
18068
18162
|
function buildTaintFlow(source, sink, taintInfo) {
|
|
18069
18163
|
const path = [];
|
|
18070
18164
|
path.push({
|
|
18071
|
-
variable: taintInfo.variable,
|
|
18165
|
+
variable: source.variable ?? taintInfo.variable,
|
|
18072
18166
|
line: source.line,
|
|
18073
18167
|
type: "source",
|
|
18074
18168
|
description: `Tainted data enters via ${source.type}`
|
|
@@ -18095,7 +18189,7 @@ function buildTaintFlow(source, sink, taintInfo) {
|
|
|
18095
18189
|
confidence: taintInfo.confidence * 0.9
|
|
18096
18190
|
};
|
|
18097
18191
|
}
|
|
18098
|
-
//
|
|
18192
|
+
// ../circle-ir/dist/analysis/constant-propagation/ast-utils.js
|
|
18099
18193
|
function isKnown(cv) {
|
|
18100
18194
|
return cv.type !== "unknown";
|
|
18101
18195
|
}
|
|
@@ -18112,7 +18206,7 @@ function getNodeLine(node) {
|
|
|
18112
18206
|
return node.startPosition.row + 1;
|
|
18113
18207
|
}
|
|
18114
18208
|
|
|
18115
|
-
//
|
|
18209
|
+
// ../circle-ir/dist/analysis/constant-propagation/evaluator.js
|
|
18116
18210
|
class ExpressionEvaluator {
|
|
18117
18211
|
source;
|
|
18118
18212
|
getSymbol;
|
|
@@ -18382,7 +18476,7 @@ class ExpressionEvaluator {
|
|
|
18382
18476
|
}
|
|
18383
18477
|
}
|
|
18384
18478
|
|
|
18385
|
-
//
|
|
18479
|
+
// ../circle-ir/dist/analysis/constant-propagation/patterns.js
|
|
18386
18480
|
var TAINT_PATTERNS = [
|
|
18387
18481
|
"request.getParameter",
|
|
18388
18482
|
"request.getHeader",
|
|
@@ -18577,7 +18671,7 @@ var PROPAGATOR_METHODS = new Set([
|
|
|
18577
18671
|
"decodeRequestString"
|
|
18578
18672
|
]);
|
|
18579
18673
|
|
|
18580
|
-
//
|
|
18674
|
+
// ../circle-ir/dist/analysis/constant-propagation/propagator.js
|
|
18581
18675
|
class ConstantPropagator {
|
|
18582
18676
|
symbols = new Map;
|
|
18583
18677
|
tainted = new Set;
|
|
@@ -20434,7 +20528,7 @@ class ConstantPropagator {
|
|
|
20434
20528
|
}
|
|
20435
20529
|
}
|
|
20436
20530
|
|
|
20437
|
-
//
|
|
20531
|
+
// ../circle-ir/dist/analysis/constant-propagation/index.js
|
|
20438
20532
|
function analyzeConstantPropagation(tree, sourceCode, options = {}) {
|
|
20439
20533
|
const propagator = new ConstantPropagator;
|
|
20440
20534
|
return propagator.analyze(tree, sourceCode, options.additionalTaintPatterns ?? [], options.sanitizerMethods ?? [], options.taintedParameters ?? []);
|
|
@@ -20522,7 +20616,7 @@ function normalizeCondition(cond) {
|
|
|
20522
20616
|
}
|
|
20523
20617
|
return normalized;
|
|
20524
20618
|
}
|
|
20525
|
-
//
|
|
20619
|
+
// ../circle-ir/dist/utils/logger.js
|
|
20526
20620
|
var LOG_LEVELS = {
|
|
20527
20621
|
trace: 0,
|
|
20528
20622
|
debug: 1,
|
|
@@ -20594,7 +20688,7 @@ var logger = {
|
|
|
20594
20688
|
}
|
|
20595
20689
|
};
|
|
20596
20690
|
|
|
20597
|
-
//
|
|
20691
|
+
// ../circle-ir/dist/analysis/per-file-finding-cap.js
|
|
20598
20692
|
var DEFAULT_PER_FILE_FINDING_CAP = 1000;
|
|
20599
20693
|
var SATURATED_FILE_RULE_ID = "saturated-file";
|
|
20600
20694
|
function applyPerFileFindingCap(filePath, findings, cap) {
|
|
@@ -20630,7 +20724,7 @@ function applyPerFileFindingCap(filePath, findings, cap) {
|
|
|
20630
20724
|
return [advisory];
|
|
20631
20725
|
}
|
|
20632
20726
|
|
|
20633
|
-
//
|
|
20727
|
+
// ../circle-ir/dist/analysis/confidence-filter.js
|
|
20634
20728
|
function applyConfidenceFilter(findings, includeSpeculative) {
|
|
20635
20729
|
if (includeSpeculative)
|
|
20636
20730
|
return findings;
|
|
@@ -20640,7 +20734,7 @@ function isHighConfidence(finding) {
|
|
|
20640
20734
|
return finding.confidence === undefined || finding.confidence === "high";
|
|
20641
20735
|
}
|
|
20642
20736
|
|
|
20643
|
-
//
|
|
20737
|
+
// ../circle-ir/dist/analysis/library-api-surface-downgrade.js
|
|
20644
20738
|
var LIBRARY_API_SURFACE_TAG = "library-api-surface:caller-responsibility";
|
|
20645
20739
|
function applyLibraryApiSurfaceDowngrade(findings) {
|
|
20646
20740
|
return findings.map((f) => {
|
|
@@ -20657,7 +20751,7 @@ function applyLibraryApiSurfaceDowngrade(findings) {
|
|
|
20657
20751
|
});
|
|
20658
20752
|
}
|
|
20659
20753
|
|
|
20660
|
-
//
|
|
20754
|
+
// ../circle-ir/dist/analysis/note-coalescer.js
|
|
20661
20755
|
var CLICKJACKING_PAIR = new Set(["missing-x-frame-options", "missing-csp-frame-ancestors"]);
|
|
20662
20756
|
function levelRank(level) {
|
|
20663
20757
|
return level === "error" ? 0 : level === "warning" ? 1 : 2;
|
|
@@ -20721,7 +20815,7 @@ function coalesceNoteLevelFindings(findings) {
|
|
|
20721
20815
|
return out2;
|
|
20722
20816
|
}
|
|
20723
20817
|
|
|
20724
|
-
//
|
|
20818
|
+
// ../circle-ir/dist/analysis/entry-point-detection.js
|
|
20725
20819
|
var TIER_1_METHOD_ANNOTATIONS = new Set([
|
|
20726
20820
|
"RequestMapping",
|
|
20727
20821
|
"GetMapping",
|
|
@@ -21378,7 +21472,7 @@ function methodIsRuntimeRegistrationHandler(method, regs) {
|
|
|
21378
21472
|
return false;
|
|
21379
21473
|
}
|
|
21380
21474
|
|
|
21381
|
-
//
|
|
21475
|
+
// ../circle-ir/dist/analysis/require-entry-path.js
|
|
21382
21476
|
var RULE_ID_REQUIRE_ENTRY_PATH = "require-entry-path";
|
|
21383
21477
|
var MAX_VISITED_METHODS = 2000;
|
|
21384
21478
|
var TAINT_FLOW_RULE_IDS = new Set([
|
|
@@ -21767,7 +21861,7 @@ function normalizeDisabled(input) {
|
|
|
21767
21861
|
return new Set(input);
|
|
21768
21862
|
}
|
|
21769
21863
|
|
|
21770
|
-
//
|
|
21864
|
+
// ../circle-ir/dist/analysis/project-profile-transform.js
|
|
21771
21865
|
var DOWNGRADE_ELIGIBLE_RULE_IDS = new Set([
|
|
21772
21866
|
"code_injection",
|
|
21773
21867
|
"template_injection",
|
|
@@ -21829,7 +21923,7 @@ function applyProjectProfileTransform(findings, resolveProfile) {
|
|
|
21829
21923
|
});
|
|
21830
21924
|
}
|
|
21831
21925
|
|
|
21832
|
-
//
|
|
21926
|
+
// ../circle-ir/dist/languages/registry.js
|
|
21833
21927
|
class DefaultLanguageRegistry {
|
|
21834
21928
|
plugins = new Map;
|
|
21835
21929
|
extensionMap = new Map;
|
|
@@ -21876,7 +21970,7 @@ function registerLanguage(plugin) {
|
|
|
21876
21970
|
function getLanguagePlugin(language) {
|
|
21877
21971
|
return getLanguageRegistry().get(language);
|
|
21878
21972
|
}
|
|
21879
|
-
//
|
|
21973
|
+
// ../circle-ir/dist/languages/plugins/base.js
|
|
21880
21974
|
class BaseLanguagePlugin {
|
|
21881
21975
|
parser = null;
|
|
21882
21976
|
async initialize(parser) {
|
|
@@ -21937,7 +22031,7 @@ class BaseLanguagePlugin {
|
|
|
21937
22031
|
}
|
|
21938
22032
|
}
|
|
21939
22033
|
|
|
21940
|
-
//
|
|
22034
|
+
// ../circle-ir/dist/languages/plugins/java.js
|
|
21941
22035
|
class JavaPlugin extends BaseLanguagePlugin {
|
|
21942
22036
|
id = "java";
|
|
21943
22037
|
name = "Java";
|
|
@@ -22194,7 +22288,7 @@ class JavaPlugin extends BaseLanguagePlugin {
|
|
|
22194
22288
|
}
|
|
22195
22289
|
}
|
|
22196
22290
|
|
|
22197
|
-
//
|
|
22291
|
+
// ../circle-ir/dist/languages/plugins/javascript.js
|
|
22198
22292
|
class JavaScriptPlugin extends BaseLanguagePlugin {
|
|
22199
22293
|
id = "javascript";
|
|
22200
22294
|
name = "JavaScript/TypeScript";
|
|
@@ -22860,7 +22954,7 @@ class JavaScriptPlugin extends BaseLanguagePlugin {
|
|
|
22860
22954
|
}
|
|
22861
22955
|
}
|
|
22862
22956
|
|
|
22863
|
-
//
|
|
22957
|
+
// ../circle-ir/dist/languages/plugins/python.js
|
|
22864
22958
|
class PythonPlugin extends BaseLanguagePlugin {
|
|
22865
22959
|
id = "python";
|
|
22866
22960
|
name = "Python";
|
|
@@ -23136,7 +23230,7 @@ class PythonPlugin extends BaseLanguagePlugin {
|
|
|
23136
23230
|
}
|
|
23137
23231
|
}
|
|
23138
23232
|
|
|
23139
|
-
//
|
|
23233
|
+
// ../circle-ir/dist/languages/plugins/rust.js
|
|
23140
23234
|
class RustPlugin extends BaseLanguagePlugin {
|
|
23141
23235
|
id = "rust";
|
|
23142
23236
|
name = "Rust";
|
|
@@ -23369,7 +23463,7 @@ class RustPlugin extends BaseLanguagePlugin {
|
|
|
23369
23463
|
}
|
|
23370
23464
|
}
|
|
23371
23465
|
|
|
23372
|
-
//
|
|
23466
|
+
// ../circle-ir/dist/languages/plugins/bash.js
|
|
23373
23467
|
class BashPlugin extends BaseLanguagePlugin {
|
|
23374
23468
|
id = "bash";
|
|
23375
23469
|
name = "Bash/Shell";
|
|
@@ -23575,7 +23669,7 @@ class BashPlugin extends BaseLanguagePlugin {
|
|
|
23575
23669
|
}
|
|
23576
23670
|
}
|
|
23577
23671
|
|
|
23578
|
-
//
|
|
23672
|
+
// ../circle-ir/dist/languages/plugins/html.js
|
|
23579
23673
|
class HtmlPlugin extends BaseLanguagePlugin {
|
|
23580
23674
|
id = "html";
|
|
23581
23675
|
name = "HTML";
|
|
@@ -23640,7 +23734,7 @@ class HtmlPlugin extends BaseLanguagePlugin {
|
|
|
23640
23734
|
}
|
|
23641
23735
|
}
|
|
23642
23736
|
|
|
23643
|
-
//
|
|
23737
|
+
// ../circle-ir/dist/languages/plugins/vue.js
|
|
23644
23738
|
class VuePlugin extends BaseLanguagePlugin {
|
|
23645
23739
|
id = "vue";
|
|
23646
23740
|
name = "Vue";
|
|
@@ -23705,7 +23799,7 @@ class VuePlugin extends BaseLanguagePlugin {
|
|
|
23705
23799
|
}
|
|
23706
23800
|
}
|
|
23707
23801
|
|
|
23708
|
-
//
|
|
23802
|
+
// ../circle-ir/dist/languages/plugins/go.js
|
|
23709
23803
|
class GoPlugin extends BaseLanguagePlugin {
|
|
23710
23804
|
id = "go";
|
|
23711
23805
|
name = "Go";
|
|
@@ -23930,6 +24024,54 @@ class GoPlugin extends BaseLanguagePlugin {
|
|
|
23930
24024
|
severity: "high",
|
|
23931
24025
|
argPositions: [0]
|
|
23932
24026
|
},
|
|
24027
|
+
{
|
|
24028
|
+
method: "Create",
|
|
24029
|
+
class: "os",
|
|
24030
|
+
type: "path_traversal",
|
|
24031
|
+
cwe: "CWE-22",
|
|
24032
|
+
severity: "high",
|
|
24033
|
+
argPositions: [0]
|
|
24034
|
+
},
|
|
24035
|
+
{
|
|
24036
|
+
method: "OpenFile",
|
|
24037
|
+
class: "os",
|
|
24038
|
+
type: "path_traversal",
|
|
24039
|
+
cwe: "CWE-22",
|
|
24040
|
+
severity: "high",
|
|
24041
|
+
argPositions: [0]
|
|
24042
|
+
},
|
|
24043
|
+
{
|
|
24044
|
+
method: "Remove",
|
|
24045
|
+
class: "os",
|
|
24046
|
+
type: "path_traversal",
|
|
24047
|
+
cwe: "CWE-22",
|
|
24048
|
+
severity: "high",
|
|
24049
|
+
argPositions: [0]
|
|
24050
|
+
},
|
|
24051
|
+
{
|
|
24052
|
+
method: "RemoveAll",
|
|
24053
|
+
class: "os",
|
|
24054
|
+
type: "path_traversal",
|
|
24055
|
+
cwe: "CWE-22",
|
|
24056
|
+
severity: "high",
|
|
24057
|
+
argPositions: [0]
|
|
24058
|
+
},
|
|
24059
|
+
{
|
|
24060
|
+
method: "ReadFile",
|
|
24061
|
+
class: "ioutil",
|
|
24062
|
+
type: "path_traversal",
|
|
24063
|
+
cwe: "CWE-22",
|
|
24064
|
+
severity: "high",
|
|
24065
|
+
argPositions: [0]
|
|
24066
|
+
},
|
|
24067
|
+
{
|
|
24068
|
+
method: "WriteFile",
|
|
24069
|
+
class: "ioutil",
|
|
24070
|
+
type: "path_traversal",
|
|
24071
|
+
cwe: "CWE-22",
|
|
24072
|
+
severity: "high",
|
|
24073
|
+
argPositions: [0]
|
|
24074
|
+
},
|
|
23933
24075
|
{
|
|
23934
24076
|
method: "Fprintf",
|
|
23935
24077
|
class: "fmt",
|
|
@@ -24354,7 +24496,7 @@ class GoPlugin extends BaseLanguagePlugin {
|
|
|
24354
24496
|
}
|
|
24355
24497
|
}
|
|
24356
24498
|
|
|
24357
|
-
//
|
|
24499
|
+
// ../circle-ir/dist/languages/plugins/csharp.js
|
|
24358
24500
|
class CSharpPlugin extends BaseLanguagePlugin {
|
|
24359
24501
|
id = "csharp";
|
|
24360
24502
|
name = "C#";
|
|
@@ -24413,7 +24555,7 @@ class CSharpPlugin extends BaseLanguagePlugin {
|
|
|
24413
24555
|
}
|
|
24414
24556
|
}
|
|
24415
24557
|
|
|
24416
|
-
//
|
|
24558
|
+
// ../circle-ir/dist/languages/plugins/index.js
|
|
24417
24559
|
function registerBuiltinPlugins() {
|
|
24418
24560
|
registerLanguage(new JavaPlugin);
|
|
24419
24561
|
registerLanguage(new JavaScriptPlugin);
|
|
@@ -24425,7 +24567,7 @@ function registerBuiltinPlugins() {
|
|
|
24425
24567
|
registerLanguage(new GoPlugin);
|
|
24426
24568
|
registerLanguage(new CSharpPlugin);
|
|
24427
24569
|
}
|
|
24428
|
-
//
|
|
24570
|
+
// ../circle-ir/dist/analysis/passes/cross-file-pass.js
|
|
24429
24571
|
class CrossFilePass {
|
|
24430
24572
|
run(projectGraph, sourceLines, options = {}) {
|
|
24431
24573
|
const resolver = projectGraph.resolver;
|
|
@@ -24436,7 +24578,8 @@ class CrossFilePass {
|
|
|
24436
24578
|
logger.info("cross-file: starting", { files: fileCount, budgetMs });
|
|
24437
24579
|
const phase1Start = Date.now();
|
|
24438
24580
|
logger.debug("cross-file: phase 1/4 starting (findCrossFileTaintFlows)");
|
|
24439
|
-
const flows = resolver.findCrossFileTaintFlows();
|
|
24581
|
+
const flows = resolver.findCrossFileTaintFlows(budgetExceeded);
|
|
24582
|
+
let phase1Truncated = budgetExceeded();
|
|
24440
24583
|
logger.info("cross-file: phase 1/4 done", {
|
|
24441
24584
|
flows: flows.length,
|
|
24442
24585
|
elapsedMs: Date.now() - phase1Start
|
|
@@ -24486,7 +24629,7 @@ class CrossFilePass {
|
|
|
24486
24629
|
confidence: 0.7
|
|
24487
24630
|
}];
|
|
24488
24631
|
});
|
|
24489
|
-
let exceeded =
|
|
24632
|
+
let exceeded = phase1Truncated;
|
|
24490
24633
|
const ipPaths = [];
|
|
24491
24634
|
if (budgetExceeded()) {
|
|
24492
24635
|
exceeded = true;
|
|
@@ -24498,7 +24641,7 @@ class CrossFilePass {
|
|
|
24498
24641
|
} else {
|
|
24499
24642
|
const phase2Start = Date.now();
|
|
24500
24643
|
logger.debug("cross-file: phase 2/4 starting (findInterproceduralTaintPaths)");
|
|
24501
|
-
const phase2 = resolver.findInterproceduralTaintPaths();
|
|
24644
|
+
const phase2 = resolver.findInterproceduralTaintPaths(budgetExceeded);
|
|
24502
24645
|
ipPaths.push(...phase2);
|
|
24503
24646
|
logger.info("cross-file: phase 2/4 done", {
|
|
24504
24647
|
paths: phase2.length,
|
|
@@ -24515,7 +24658,7 @@ class CrossFilePass {
|
|
|
24515
24658
|
} else if (!exceeded) {
|
|
24516
24659
|
const phase3Start = Date.now();
|
|
24517
24660
|
logger.debug("cross-file: phase 3/4 starting (findFieldBindingTaintPaths)");
|
|
24518
|
-
const phase3 = resolver.findFieldBindingTaintPaths();
|
|
24661
|
+
const phase3 = resolver.findFieldBindingTaintPaths(budgetExceeded);
|
|
24519
24662
|
ipPaths.push(...phase3);
|
|
24520
24663
|
logger.info("cross-file: phase 3/4 done", {
|
|
24521
24664
|
paths: phase3.length,
|
|
@@ -24751,7 +24894,7 @@ function findCrossInstanceAliasingPaths(projectGraph, _sourceLines) {
|
|
|
24751
24894
|
return paths;
|
|
24752
24895
|
}
|
|
24753
24896
|
|
|
24754
|
-
//
|
|
24897
|
+
// ../circle-ir/dist/analysis/html/html-extractor.js
|
|
24755
24898
|
var EVENT_HANDLER_ATTRS = new Set([
|
|
24756
24899
|
"onclick",
|
|
24757
24900
|
"ondblclick",
|
|
@@ -24906,7 +25049,7 @@ function stripQuotes2(text) {
|
|
|
24906
25049
|
return text;
|
|
24907
25050
|
}
|
|
24908
25051
|
|
|
24909
|
-
//
|
|
25052
|
+
// ../circle-ir/dist/analysis/html/html-attribute-security-pass.js
|
|
24910
25053
|
function runHtmlAttributeSecurityChecks(rootNode, filePath) {
|
|
24911
25054
|
const findings = [];
|
|
24912
25055
|
walkForSecurityChecks(rootNode, filePath, findings);
|
|
@@ -25132,7 +25275,7 @@ function truncate(s, maxLen) {
|
|
|
25132
25275
|
return s.length > maxLen ? s.slice(0, maxLen) + "..." : s;
|
|
25133
25276
|
}
|
|
25134
25277
|
|
|
25135
|
-
//
|
|
25278
|
+
// ../circle-ir/dist/analysis/html/vue-template-xss-pass.js
|
|
25136
25279
|
var DANGEROUS_BINDINGS = new Set([
|
|
25137
25280
|
"v-html",
|
|
25138
25281
|
"v-bind:innerhtml",
|
|
@@ -25252,7 +25395,7 @@ function collectTaintedNames(blocks) {
|
|
|
25252
25395
|
return names;
|
|
25253
25396
|
}
|
|
25254
25397
|
|
|
25255
|
-
//
|
|
25398
|
+
// ../circle-ir/dist/analysis/html/html-merge.js
|
|
25256
25399
|
function mergeHtmlResults(htmlMeta, scriptResults, attributeFindings) {
|
|
25257
25400
|
const allTypes = [];
|
|
25258
25401
|
const allCalls = [];
|
|
@@ -25402,7 +25545,7 @@ function mergeHtmlResults(htmlMeta, scriptResults, attributeFindings) {
|
|
|
25402
25545
|
};
|
|
25403
25546
|
}
|
|
25404
25547
|
|
|
25405
|
-
//
|
|
25548
|
+
// ../circle-ir/dist/analysis/passes/taint-matcher-pass.js
|
|
25406
25549
|
class TaintMatcherPass {
|
|
25407
25550
|
name = "taint-matcher";
|
|
25408
25551
|
category = "security";
|
|
@@ -25463,7 +25606,7 @@ class TaintMatcherPass {
|
|
|
25463
25606
|
}
|
|
25464
25607
|
}
|
|
25465
25608
|
|
|
25466
|
-
//
|
|
25609
|
+
// ../circle-ir/dist/analysis/passes/constant-propagation-pass.js
|
|
25467
25610
|
class ConstantPropagationPass {
|
|
25468
25611
|
tree;
|
|
25469
25612
|
name = "constant-propagation";
|
|
@@ -25493,7 +25636,7 @@ class ConstantPropagationPass {
|
|
|
25493
25636
|
}
|
|
25494
25637
|
}
|
|
25495
25638
|
|
|
25496
|
-
//
|
|
25639
|
+
// ../circle-ir/dist/analysis/passes/language-sources-pass.js
|
|
25497
25640
|
var JS_DOM_XSS_SINKS = [
|
|
25498
25641
|
{ pattern: /\.innerHTML\s*=/, type: "xss", cwe: "CWE-79", severity: "critical" },
|
|
25499
25642
|
{ pattern: /\.outerHTML\s*=/, type: "xss", cwe: "CWE-79", severity: "critical" },
|
|
@@ -25611,6 +25754,8 @@ class LanguageSourcesPass {
|
|
|
25611
25754
|
additionalSources.push(...findCSharpBindingAttributeSources(code, language));
|
|
25612
25755
|
additionalSources.push(...findCSharpMinimalApiSources(code, language));
|
|
25613
25756
|
additionalSources.push(...findGoArgvSources(code, language));
|
|
25757
|
+
additionalSources.push(...findGoArchiveEntrySources(code, language));
|
|
25758
|
+
additionalSources.push(...findGoMultipartUploadSources(code, language));
|
|
25614
25759
|
const jsDOMSinks = findJavaScriptDOMSinks(code, language);
|
|
25615
25760
|
for (const s of jsDOMSinks) {
|
|
25616
25761
|
const alreadyExists = additionalSinks.some((x) => x.line === s.line && x.cwe === s.cwe);
|
|
@@ -25681,6 +25826,7 @@ class LanguageSourcesPass {
|
|
|
25681
25826
|
if (language === "go") {
|
|
25682
25827
|
additionalSanitizers.push(...findGoMapAllowlistGuardSanitizers(code));
|
|
25683
25828
|
additionalSanitizers.push(...findGoHtmlTemplateImportSanitizers(code));
|
|
25829
|
+
additionalSanitizers.push(...findGoPathContainmentGuardSanitizers(code));
|
|
25684
25830
|
const goMisconfigFindings = findGoPatternFindings(code, graph.ir.meta.file);
|
|
25685
25831
|
for (const finding of goMisconfigFindings) {
|
|
25686
25832
|
ctx.addFinding(finding);
|
|
@@ -25718,6 +25864,7 @@ class LanguageSourcesPass {
|
|
|
25718
25864
|
additionalSanitizers.push(...findPythonUrlAllowlistRedirectSanitizers(code));
|
|
25719
25865
|
additionalSanitizers.push(...findPythonDefusedXmlSanitizers(code));
|
|
25720
25866
|
additionalSanitizers.push(...findPythonJinjaAutoescapeSanitizers(code));
|
|
25867
|
+
additionalSanitizers.push(...findCrlfWrapperFunctionSanitizers(code, "python"));
|
|
25721
25868
|
const pyMisconfigFindings = findPythonPatternFindings(code, graph.ir.meta.file);
|
|
25722
25869
|
for (const finding of pyMisconfigFindings) {
|
|
25723
25870
|
ctx.addFinding(finding);
|
|
@@ -25821,12 +25968,16 @@ class LanguageSourcesPass {
|
|
|
25821
25968
|
ctx.addFinding(finding);
|
|
25822
25969
|
}
|
|
25823
25970
|
}
|
|
25971
|
+
if (language === "csharp") {
|
|
25972
|
+
additionalSanitizers.push(...findCSharpFullPathStartsWithGuardSanitizers(code));
|
|
25973
|
+
}
|
|
25824
25974
|
if (language === "java") {
|
|
25825
25975
|
additionalSanitizers.push(...findJavaSafeJsonParseSanitizers(code));
|
|
25826
25976
|
additionalSanitizers.push(...findJavaPathNormalizeStartsWithGuardSanitizers(code));
|
|
25827
25977
|
additionalSanitizers.push(...findJavaPathGetFileNameSanitizers(code));
|
|
25828
25978
|
additionalSanitizers.push(...findJavaCanonicalPathStartsWithGuardSanitizers(code));
|
|
25829
25979
|
additionalSanitizers.push(...findJavaInlineCrlfStripLogSanitizers(code));
|
|
25980
|
+
additionalSanitizers.push(...findCrlfWrapperFunctionSanitizers(code, "java"));
|
|
25830
25981
|
additionalSanitizers.push(...findJavaArgvFormExecSanitizers(code));
|
|
25831
25982
|
for (const finding of findJavaPatternFindings(code, graph.ir.meta.file)) {
|
|
25832
25983
|
ctx.addFinding(finding);
|
|
@@ -26242,13 +26393,121 @@ function findGoArgvSources(sourceCode, language) {
|
|
|
26242
26393
|
}
|
|
26243
26394
|
return sources;
|
|
26244
26395
|
}
|
|
26396
|
+
function findGoArchiveEntrySources(sourceCode, language) {
|
|
26397
|
+
if (language !== "go")
|
|
26398
|
+
return [];
|
|
26399
|
+
if (!/\bimport\b[\s\S]{0,400}?archive\/(?:zip|tar)|"archive\/(?:zip|tar)"/.test(sourceCode))
|
|
26400
|
+
return [];
|
|
26401
|
+
const sources = [];
|
|
26402
|
+
const lines = sourceCode.split(`
|
|
26403
|
+
`);
|
|
26404
|
+
const entryVars = new Set;
|
|
26405
|
+
const zipRange = /\bfor\b[^;{]*?,\s*([A-Za-z_]\w*)\s*:?=\s*range\s+[A-Za-z_][\w.]*\.File\b/;
|
|
26406
|
+
const tarNext = /\b([A-Za-z_]\w*)\s*,\s*[A-Za-z_]\w*\s*:?=\s*[A-Za-z_][\w.]*\.Next\s*\(\s*\)/;
|
|
26407
|
+
for (const line of lines) {
|
|
26408
|
+
const z = zipRange.exec(line);
|
|
26409
|
+
if (z)
|
|
26410
|
+
entryVars.add(z[1]);
|
|
26411
|
+
const t = tarNext.exec(line);
|
|
26412
|
+
if (t)
|
|
26413
|
+
entryVars.add(t[1]);
|
|
26414
|
+
}
|
|
26415
|
+
if (entryVars.size === 0)
|
|
26416
|
+
return sources;
|
|
26417
|
+
const assignRe = /^\s*(?:var\s+)?([A-Za-z_]\w*)\s*(?::?=|=)\s*(.+?)\s*$/;
|
|
26418
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
26419
|
+
const m = assignRe.exec(lines[i2]);
|
|
26420
|
+
if (!m)
|
|
26421
|
+
continue;
|
|
26422
|
+
const [, lhs, rhs] = m;
|
|
26423
|
+
let matched = null;
|
|
26424
|
+
for (const v of entryVars) {
|
|
26425
|
+
if (new RegExp(`(?<![\\w.])${v}\\s*\\.\\s*Name\\b`).test(rhs)) {
|
|
26426
|
+
matched = v;
|
|
26427
|
+
break;
|
|
26428
|
+
}
|
|
26429
|
+
}
|
|
26430
|
+
if (!matched)
|
|
26431
|
+
continue;
|
|
26432
|
+
const lineNumber = i2 + 1;
|
|
26433
|
+
if (sources.some((sc) => sc.line === lineNumber && sc.variable === lhs))
|
|
26434
|
+
continue;
|
|
26435
|
+
sources.push({
|
|
26436
|
+
type: "file_input",
|
|
26437
|
+
location: `${lhs} derived from archive entry name ${matched}.Name (Zip/Tar Slip)`,
|
|
26438
|
+
severity: "high",
|
|
26439
|
+
line: lineNumber,
|
|
26440
|
+
confidence: 0.9,
|
|
26441
|
+
variable: lhs
|
|
26442
|
+
});
|
|
26443
|
+
}
|
|
26444
|
+
return sources;
|
|
26445
|
+
}
|
|
26446
|
+
function findGoMultipartUploadSources(sourceCode, language) {
|
|
26447
|
+
if (language !== "go")
|
|
26448
|
+
return [];
|
|
26449
|
+
if (!/\.\s*(?:FormFile|MultipartForm|MultipartReader)\b/.test(sourceCode))
|
|
26450
|
+
return [];
|
|
26451
|
+
const sources = [];
|
|
26452
|
+
const lines = sourceCode.split(`
|
|
26453
|
+
`);
|
|
26454
|
+
const headerVars = new Set;
|
|
26455
|
+
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*\(/;
|
|
26456
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
26457
|
+
const m = formFileRe.exec(lines[i2]);
|
|
26458
|
+
if (!m)
|
|
26459
|
+
continue;
|
|
26460
|
+
const v = m[1];
|
|
26461
|
+
if (v === "_")
|
|
26462
|
+
continue;
|
|
26463
|
+
headerVars.add(v);
|
|
26464
|
+
sources.push({
|
|
26465
|
+
type: "http_param",
|
|
26466
|
+
location: `${v}.Filename from r.FormFile (client-supplied upload filename)`,
|
|
26467
|
+
severity: "high",
|
|
26468
|
+
line: i2 + 1,
|
|
26469
|
+
confidence: 0.9,
|
|
26470
|
+
variable: v
|
|
26471
|
+
});
|
|
26472
|
+
}
|
|
26473
|
+
const assignRe = /^\s*(?:var\s+)?([A-Za-z_]\w*)\s*(?::?=|=)\s*(.+?)\s*$/;
|
|
26474
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
26475
|
+
const m = assignRe.exec(lines[i2]);
|
|
26476
|
+
if (!m)
|
|
26477
|
+
continue;
|
|
26478
|
+
const [, lhs, rhs] = m;
|
|
26479
|
+
if (lhs === "_")
|
|
26480
|
+
continue;
|
|
26481
|
+
let matched = null;
|
|
26482
|
+
for (const v of headerVars) {
|
|
26483
|
+
if (new RegExp(`(?<![\\w.])${v}\\s*\\.\\s*Filename\\b`).test(rhs)) {
|
|
26484
|
+
matched = v;
|
|
26485
|
+
break;
|
|
26486
|
+
}
|
|
26487
|
+
}
|
|
26488
|
+
if (!matched)
|
|
26489
|
+
continue;
|
|
26490
|
+
const lineNumber = i2 + 1;
|
|
26491
|
+
if (sources.some((sc) => sc.line === lineNumber && sc.variable === lhs))
|
|
26492
|
+
continue;
|
|
26493
|
+
sources.push({
|
|
26494
|
+
type: "http_param",
|
|
26495
|
+
location: `${lhs} derived from upload filename ${matched}.Filename`,
|
|
26496
|
+
severity: "high",
|
|
26497
|
+
line: lineNumber,
|
|
26498
|
+
confidence: 0.9,
|
|
26499
|
+
variable: lhs
|
|
26500
|
+
});
|
|
26501
|
+
}
|
|
26502
|
+
return sources;
|
|
26503
|
+
}
|
|
26245
26504
|
function findCSharpRequestSources(sourceCode, language) {
|
|
26246
26505
|
if (language !== "csharp")
|
|
26247
26506
|
return [];
|
|
26248
26507
|
const sources = [];
|
|
26249
26508
|
const lines = sourceCode.split(`
|
|
26250
26509
|
`);
|
|
26251
|
-
const assignRe = /^\s*(?:var\s+|[A-Za-z_][\w.<>\[\]]*\s+)?([A-Za-z_]\w*)\s*=\s*(.+?);?\s*$/;
|
|
26510
|
+
const assignRe = /^\s*(?:await\s+)?(?:using\s*\(?\s*)?(?:var\s+|[A-Za-z_][\w.<>\[\]]*\s+)?([A-Za-z_]\w*)\s*=\s*(.+?);?\s*$/;
|
|
26252
26511
|
const requestReadRe = /\bRequest\s*\.\s*(?:Query|Form|Headers|Cookies|QueryString|RouteValues|Body|Files|Params)\b/;
|
|
26253
26512
|
const consoleReadRe = /\bConsole\s*\.\s*ReadLine\s*\(/;
|
|
26254
26513
|
const envReadRe = /\bEnvironment\s*\.\s*GetEnvironmentVariables?\s*(?:\(|\[)/;
|
|
@@ -26954,6 +27213,12 @@ function findPythonReflectionInvocationSinks(sourceCode, taintedVars) {
|
|
|
26954
27213
|
}
|
|
26955
27214
|
return sinks;
|
|
26956
27215
|
}
|
|
27216
|
+
function isProvablyLiteralDomAssignment(line) {
|
|
27217
|
+
const eq = line.indexOf("=");
|
|
27218
|
+
if (eq < 0)
|
|
27219
|
+
return false;
|
|
27220
|
+
return isProvablyLiteralExpression(line.slice(eq + 1));
|
|
27221
|
+
}
|
|
26957
27222
|
function findJavaScriptDOMSinks(sourceCode, language) {
|
|
26958
27223
|
if (!["javascript", "typescript"].includes(language))
|
|
26959
27224
|
return [];
|
|
@@ -26982,6 +27247,9 @@ function findJavaScriptDOMSinks(sourceCode, language) {
|
|
|
26982
27247
|
method = "cssText";
|
|
26983
27248
|
else if (line.includes("style.textContent"))
|
|
26984
27249
|
method = "textContent";
|
|
27250
|
+
if (DOM_ASSIGNMENT_SINK_METHODS.has(method) && isProvablyLiteralDomAssignment(line)) {
|
|
27251
|
+
continue;
|
|
27252
|
+
}
|
|
26985
27253
|
if (method === "document.write" || method === "document.writeln") {
|
|
26986
27254
|
const argMatch = line.match(/document\.write(?:ln)?\s*\(\s*([^)]*)\)/);
|
|
26987
27255
|
if (argMatch) {
|
|
@@ -27747,6 +28015,47 @@ function findGoMapAllowlistGuardSanitizers(code) {
|
|
|
27747
28015
|
}
|
|
27748
28016
|
return sanitizers;
|
|
27749
28017
|
}
|
|
28018
|
+
function findGoPathContainmentGuardSanitizers(code) {
|
|
28019
|
+
const sanitizers = [];
|
|
28020
|
+
const lines = code.split(`
|
|
28021
|
+
`);
|
|
28022
|
+
const REJECT = /\b(?:continue|break|return|panic|fmt\.Errorf|errors\.New)\b/;
|
|
28023
|
+
const guarded = new Map;
|
|
28024
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
28025
|
+
const line = lines[i2];
|
|
28026
|
+
const hp = /if\s*!\s*strings\s*\.\s*HasPrefix\s*\(\s*([A-Za-z_]\w*)\s*,/.exec(line);
|
|
28027
|
+
if (hp && guardRejects(lines, i2, REJECT, 4)) {
|
|
28028
|
+
if (!guarded.has(hp[1]))
|
|
28029
|
+
guarded.set(hp[1], i2 + 1);
|
|
28030
|
+
continue;
|
|
28031
|
+
}
|
|
28032
|
+
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);
|
|
28033
|
+
if (rel) {
|
|
28034
|
+
const window2 = lines.slice(i2, i2 + 5).join(`
|
|
28035
|
+
`);
|
|
28036
|
+
if (/\.\./.test(window2) && REJECT.test(window2)) {
|
|
28037
|
+
if (!guarded.has(rel[2]))
|
|
28038
|
+
guarded.set(rel[2], i2 + 1);
|
|
28039
|
+
}
|
|
28040
|
+
}
|
|
28041
|
+
}
|
|
28042
|
+
if (guarded.size === 0)
|
|
28043
|
+
return sanitizers;
|
|
28044
|
+
for (const [name2, guardLine] of guarded) {
|
|
28045
|
+
const useRe = new RegExp(`(?<![\\w.])${name2}(?![\\w])`);
|
|
28046
|
+
for (let l = guardLine;l < lines.length; l++) {
|
|
28047
|
+
if (!useRe.test(lines[l]))
|
|
28048
|
+
continue;
|
|
28049
|
+
sanitizers.push({
|
|
28050
|
+
type: "go_path_containment_guard",
|
|
28051
|
+
method: "strings.HasPrefix",
|
|
28052
|
+
line: l + 1,
|
|
28053
|
+
sanitizes: ["path_traversal"]
|
|
28054
|
+
});
|
|
28055
|
+
}
|
|
28056
|
+
}
|
|
28057
|
+
return sanitizers;
|
|
28058
|
+
}
|
|
27750
28059
|
function findGoHtmlTemplateImportSanitizers(code) {
|
|
27751
28060
|
const sanitizers = [];
|
|
27752
28061
|
const hasHtmlTemplate = /["\s]html\/template["\s]/.test(code);
|
|
@@ -28713,7 +29022,7 @@ function findJsPathResolveStartsWithGuardSanitizers(code) {
|
|
|
28713
29022
|
for (let l = c.line;l < Math.min(lines.length, c.line + 6); l++) {
|
|
28714
29023
|
if (!guardRe.test(lines[l]))
|
|
28715
29024
|
continue;
|
|
28716
|
-
if (
|
|
29025
|
+
if (guardRejects(lines, l, terminatorRe, 2)) {
|
|
28717
29026
|
guardLine = l + 1;
|
|
28718
29027
|
break;
|
|
28719
29028
|
}
|
|
@@ -28833,7 +29142,7 @@ function findJavaPathNormalizeStartsWithGuardSanitizers(code) {
|
|
|
28833
29142
|
for (let l = c.line;l < Math.min(lines.length, c.line + 6); l++) {
|
|
28834
29143
|
if (!guardRe.test(lines[l]))
|
|
28835
29144
|
continue;
|
|
28836
|
-
if (
|
|
29145
|
+
if (guardRejects(lines, l, terminatorRe, 2)) {
|
|
28837
29146
|
guardLine = l + 1;
|
|
28838
29147
|
break;
|
|
28839
29148
|
}
|
|
@@ -28871,18 +29180,7 @@ function findJavaCanonicalPathStartsWithGuardSanitizers(code) {
|
|
|
28871
29180
|
const m = guardRe.exec(lines[i2]);
|
|
28872
29181
|
if (!m)
|
|
28873
29182
|
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)
|
|
29183
|
+
if (!guardRejects(lines, i2, terminatorRe, 6))
|
|
28886
29184
|
continue;
|
|
28887
29185
|
const guarded = new Set([m[1]]);
|
|
28888
29186
|
const mentions = (t) => {
|
|
@@ -28912,6 +29210,71 @@ function findJavaCanonicalPathStartsWithGuardSanitizers(code) {
|
|
|
28912
29210
|
}
|
|
28913
29211
|
return sanitizers;
|
|
28914
29212
|
}
|
|
29213
|
+
function guardRejects(lines, i2, terminatorRe, window2) {
|
|
29214
|
+
if (terminatorRe.test(lines[i2]))
|
|
29215
|
+
return true;
|
|
29216
|
+
const opens = (lines[i2].match(/\{/g) ?? []).length;
|
|
29217
|
+
const closes = (lines[i2].match(/\}/g) ?? []).length;
|
|
29218
|
+
if (opens > 0 && closes >= opens)
|
|
29219
|
+
return false;
|
|
29220
|
+
for (let j = i2 + 1;j < Math.min(lines.length, i2 + window2); j++) {
|
|
29221
|
+
if (terminatorRe.test(lines[j]))
|
|
29222
|
+
return true;
|
|
29223
|
+
if (lines[j].includes("}"))
|
|
29224
|
+
return false;
|
|
29225
|
+
}
|
|
29226
|
+
return false;
|
|
29227
|
+
}
|
|
29228
|
+
function findCSharpFullPathStartsWithGuardSanitizers(code) {
|
|
29229
|
+
const sanitizers = [];
|
|
29230
|
+
const lines = code.split(`
|
|
29231
|
+
`);
|
|
29232
|
+
const assignRe = /^\s*(?:(?:var|string)\s+)?([A-Za-z_]\w*)\s*=(?!=)\s*(.*)$/;
|
|
29233
|
+
const fullPathRe = /\bPath\s*\.\s*GetFullPath\s*\(/;
|
|
29234
|
+
const canonicalVars = new Set;
|
|
29235
|
+
for (const line of lines) {
|
|
29236
|
+
const a = assignRe.exec(line);
|
|
29237
|
+
if (a && fullPathRe.test(a[2]))
|
|
29238
|
+
canonicalVars.add(a[1]);
|
|
29239
|
+
}
|
|
29240
|
+
if (canonicalVars.size === 0)
|
|
29241
|
+
return sanitizers;
|
|
29242
|
+
const guardRe = /\bif\s*\(\s*!\s*([A-Za-z_]\w*)\s*\.\s*StartsWith\s*\(/;
|
|
29243
|
+
const terminatorRe = /\b(throw|return)\b/;
|
|
29244
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
29245
|
+
const m = guardRe.exec(lines[i2]);
|
|
29246
|
+
if (!m || !canonicalVars.has(m[1]))
|
|
29247
|
+
continue;
|
|
29248
|
+
if (!guardRejects(lines, i2, terminatorRe, 6))
|
|
29249
|
+
continue;
|
|
29250
|
+
const guarded = new Set([m[1]]);
|
|
29251
|
+
const mentions = (t) => {
|
|
29252
|
+
for (const n of guarded)
|
|
29253
|
+
if (new RegExp(`\\b${n}\\b`).test(t))
|
|
29254
|
+
return true;
|
|
29255
|
+
return false;
|
|
29256
|
+
};
|
|
29257
|
+
for (let l = 0;l < lines.length; l++) {
|
|
29258
|
+
const lt = lines[l];
|
|
29259
|
+
const a = assignRe.exec(lt);
|
|
29260
|
+
if (a) {
|
|
29261
|
+
if (mentions(a[2]))
|
|
29262
|
+
guarded.add(a[1]);
|
|
29263
|
+
else if (a[1] !== m[1])
|
|
29264
|
+
guarded.delete(a[1]);
|
|
29265
|
+
}
|
|
29266
|
+
if (mentions(lt)) {
|
|
29267
|
+
sanitizers.push({
|
|
29268
|
+
type: "csharp_fullpath_startswith_guard",
|
|
29269
|
+
method: "GetFullPath",
|
|
29270
|
+
line: l + 1,
|
|
29271
|
+
sanitizes: ["path_traversal", "external_taint_escape"]
|
|
29272
|
+
});
|
|
29273
|
+
}
|
|
29274
|
+
}
|
|
29275
|
+
}
|
|
29276
|
+
return sanitizers;
|
|
29277
|
+
}
|
|
28915
29278
|
function findJavaPathGetFileNameSanitizers(code) {
|
|
28916
29279
|
const sanitizers = [];
|
|
28917
29280
|
const lines = code.split(`
|
|
@@ -28955,6 +29318,41 @@ function findJavaPathGetFileNameSanitizers(code) {
|
|
|
28955
29318
|
}
|
|
28956
29319
|
return sanitizers;
|
|
28957
29320
|
}
|
|
29321
|
+
function findCrlfWrapperFunctionSanitizers(code, language) {
|
|
29322
|
+
const sanitizers = [];
|
|
29323
|
+
const lines = code.split(`
|
|
29324
|
+
`);
|
|
29325
|
+
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*\(/;
|
|
29326
|
+
const stripRe = language === "java" ? /\.\s*replace(?:All)?\s*\(\s*(?:"[^"]*\\[rnt]|'\\[rnt]')/ : /(?:re\s*\.\s*sub\s*\(\s*r?["'][^"']*\\[rnt]|\.\s*replace\s*\(\s*["']\\[rnt])/;
|
|
29327
|
+
const bodyWindow = 10;
|
|
29328
|
+
const wrappers = new Set;
|
|
29329
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
29330
|
+
const m = declRe.exec(lines[i2]);
|
|
29331
|
+
if (!m)
|
|
29332
|
+
continue;
|
|
29333
|
+
const body2 = lines.slice(i2, Math.min(lines.length, i2 + bodyWindow)).join(`
|
|
29334
|
+
`);
|
|
29335
|
+
if (stripRe.test(body2))
|
|
29336
|
+
wrappers.add(m[1]);
|
|
29337
|
+
}
|
|
29338
|
+
if (wrappers.size === 0)
|
|
29339
|
+
return sanitizers;
|
|
29340
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
29341
|
+
for (const name2 of wrappers) {
|
|
29342
|
+
if (declRe.test(lines[i2]) && new RegExp(`\\b${name2}\\s*\\(`).test(lines[i2]))
|
|
29343
|
+
continue;
|
|
29344
|
+
if (!new RegExp(`\\b${name2}\\s*\\(`).test(lines[i2]))
|
|
29345
|
+
continue;
|
|
29346
|
+
sanitizers.push({
|
|
29347
|
+
type: language === "java" ? "java_wrapper_crlf_strip" : "python_wrapper_crlf_strip",
|
|
29348
|
+
method: name2,
|
|
29349
|
+
line: i2 + 1,
|
|
29350
|
+
sanitizes: ["log_injection", "external_taint_escape"]
|
|
29351
|
+
});
|
|
29352
|
+
}
|
|
29353
|
+
}
|
|
29354
|
+
return sanitizers;
|
|
29355
|
+
}
|
|
28958
29356
|
function findJavaInlineCrlfStripLogSanitizers(code) {
|
|
28959
29357
|
const sanitizers = [];
|
|
28960
29358
|
const lines = code.split(`
|
|
@@ -32550,7 +32948,7 @@ function findJsTemplateInjectionSstiFindings(code, file) {
|
|
|
32550
32948
|
return findings;
|
|
32551
32949
|
}
|
|
32552
32950
|
|
|
32553
|
-
//
|
|
32951
|
+
// ../circle-ir/dist/analysis/passes/source-semantics-pass.js
|
|
32554
32952
|
var DEMO_PATH_RE = /(?:^|\/)(?:demo|example|examples|samples|integration-tests|integration_tests)(?:\/|$)/i;
|
|
32555
32953
|
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
32954
|
var STATIC_FINAL_RE = /^\s*(?:public\s+|private\s+|protected\s+)?static\s+final\s+/;
|
|
@@ -32638,7 +33036,7 @@ class SourceSemanticsPass {
|
|
|
32638
33036
|
}
|
|
32639
33037
|
}
|
|
32640
33038
|
|
|
32641
|
-
//
|
|
33039
|
+
// ../circle-ir/dist/analysis/passes/library-profile-source-gate-pass.js
|
|
32642
33040
|
var SPECULATIVE_SOURCE_TYPES = new Set([
|
|
32643
33041
|
"interprocedural_param",
|
|
32644
33042
|
"constructor_field"
|
|
@@ -32663,7 +33061,7 @@ class LibraryProfileSourceGatePass {
|
|
|
32663
33061
|
droppedByType: {}
|
|
32664
33062
|
};
|
|
32665
33063
|
}
|
|
32666
|
-
const sources = graph.ir.taint.sources;
|
|
33064
|
+
const sources = ctx.hasResult("sink-filter") ? ctx.getResult("sink-filter").sources : graph.ir.taint.sources;
|
|
32667
33065
|
if (sources.length === 0) {
|
|
32668
33066
|
return {
|
|
32669
33067
|
profile,
|
|
@@ -32673,17 +33071,12 @@ class LibraryProfileSourceGatePass {
|
|
|
32673
33071
|
};
|
|
32674
33072
|
}
|
|
32675
33073
|
const droppedByType = {};
|
|
32676
|
-
const kept = [];
|
|
32677
33074
|
for (const src of sources) {
|
|
32678
33075
|
if (SPECULATIVE_SOURCE_TYPES.has(src.type)) {
|
|
32679
33076
|
droppedByType[src.type] = (droppedByType[src.type] ?? 0) + 1;
|
|
32680
|
-
continue;
|
|
32681
33077
|
}
|
|
32682
|
-
kept.push(src);
|
|
32683
33078
|
}
|
|
32684
|
-
const dropped =
|
|
32685
|
-
sources.length = 0;
|
|
32686
|
-
sources.push(...kept);
|
|
33079
|
+
const dropped = 0;
|
|
32687
33080
|
return {
|
|
32688
33081
|
profile,
|
|
32689
33082
|
applied: true,
|
|
@@ -32693,7 +33086,7 @@ class LibraryProfileSourceGatePass {
|
|
|
32693
33086
|
}
|
|
32694
33087
|
}
|
|
32695
33088
|
|
|
32696
|
-
//
|
|
33089
|
+
// ../circle-ir/dist/analysis/passes/mybatis-annotation-sql-sink-pass.js
|
|
32697
33090
|
var MYBATIS_SQL_ANNOTATIONS = new Set([
|
|
32698
33091
|
"Select",
|
|
32699
33092
|
"Update",
|
|
@@ -32920,7 +33313,7 @@ class MyBatisAnnotationSqlSinkPass {
|
|
|
32920
33313
|
}
|
|
32921
33314
|
}
|
|
32922
33315
|
|
|
32923
|
-
//
|
|
33316
|
+
// ../circle-ir/dist/analysis/passes/sink-filter-pass.js
|
|
32924
33317
|
function escapeReSf(s) {
|
|
32925
33318
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
32926
33319
|
}
|
|
@@ -33027,7 +33420,32 @@ var PROTOCOL_CLIENT_PACKAGES = [
|
|
|
33027
33420
|
"org.eclipse.paho"
|
|
33028
33421
|
];
|
|
33029
33422
|
var OS_EXEC_RECEIVER_RE = /\b(?:Runtime|ProcessBuilder|DefaultExecutor|Executor|Exec|Launcher|ProcStarter|ProcessExecutor|RuntimeUtil)\s*[.(]/;
|
|
33423
|
+
var JAVA_STDOUT_PRINT_RE = /\bSystem\s*\.\s*(?:out|err)\s*\.\s*(?:println|print|printf|write|append)\s*\(/;
|
|
33030
33424
|
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*,)/;
|
|
33425
|
+
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*,)/;
|
|
33426
|
+
var SHELL_PROGRAMS = new Set([
|
|
33427
|
+
"sh",
|
|
33428
|
+
"bash",
|
|
33429
|
+
"zsh",
|
|
33430
|
+
"ksh",
|
|
33431
|
+
"dash",
|
|
33432
|
+
"ash",
|
|
33433
|
+
"csh",
|
|
33434
|
+
"tcsh",
|
|
33435
|
+
"fish",
|
|
33436
|
+
"cmd",
|
|
33437
|
+
"command",
|
|
33438
|
+
"powershell",
|
|
33439
|
+
"pwsh"
|
|
33440
|
+
]);
|
|
33441
|
+
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*"([^"]*)"/;
|
|
33442
|
+
function argvFirstLiteralIsShell(lineText) {
|
|
33443
|
+
const m = ARGV_FIRST_LITERAL_RE.exec(lineText);
|
|
33444
|
+
if (!m)
|
|
33445
|
+
return false;
|
|
33446
|
+
const base = m[1].split(/[\\/]/).pop().replace(/\.exe$/i, "").toLowerCase();
|
|
33447
|
+
return SHELL_PROGRAMS.has(base);
|
|
33448
|
+
}
|
|
33031
33449
|
var JAVA_THROW_STATEMENT_RE = /^\s*throw\s+new\s+\w+(?:Exception|Error)\b[^;]*;\s*(?:\/\/.*|\/\*.*)?$/;
|
|
33032
33450
|
var JEXL_ENGINE_TYPES = new Set(["JexlEngine", "Jexl", "JxltEngine"]);
|
|
33033
33451
|
var JEXL_EXPRESSION_TYPE_RE = /(?:Jexl)?(?:Expression|Script|Template)(?:Script)?$/;
|
|
@@ -33197,10 +33615,41 @@ function jsSsrfHostGuardedLines(code) {
|
|
|
33197
33615
|
}
|
|
33198
33616
|
return covered;
|
|
33199
33617
|
}
|
|
33618
|
+
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*\)/;
|
|
33619
|
+
function isUnwrittenLocalMapKeyRead(code, source) {
|
|
33620
|
+
if (source.type !== "plugin_param")
|
|
33621
|
+
return false;
|
|
33622
|
+
const lines = code.split(`
|
|
33623
|
+
`);
|
|
33624
|
+
const lineText = lines[source.line - 1] ?? "";
|
|
33625
|
+
const read = /\b([A-Za-z_]\w*)\s*\.\s*get\s*\(\s*"([^"]*)"\s*\)/.exec(lineText);
|
|
33626
|
+
if (!read)
|
|
33627
|
+
return false;
|
|
33628
|
+
const [, recv, key] = read;
|
|
33629
|
+
const ctorRe = new RegExp(`\\b${recv}\\s*=\\s*new\\s+(?:Hash|Tree|LinkedHash|ConcurrentHash|Concurrent|Identity|Weak)?Map\\s*(?:<[^>]*>)?\\s*\\(`);
|
|
33630
|
+
if (!lines.some((l) => ctorRe.test(l)))
|
|
33631
|
+
return false;
|
|
33632
|
+
const escapeRe2 = new RegExp(`\\w\\s*\\([^)]*(?<![\\w.])${recv}(?![\\w.])[^)]*\\)`);
|
|
33633
|
+
for (const l of lines) {
|
|
33634
|
+
if (!escapeRe2.test(l))
|
|
33635
|
+
continue;
|
|
33636
|
+
const stripped = l.replace(new RegExp(`\\b${recv}\\s*\\.\\s*\\w+\\s*\\(`, "g"), "X(");
|
|
33637
|
+
if (escapeRe2.test(stripped))
|
|
33638
|
+
return false;
|
|
33639
|
+
}
|
|
33640
|
+
const putRe = new RegExp(`\\b${recv}\\s*\\.\\s*put\\s*\\(\\s*"${key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}"`);
|
|
33641
|
+
if (lines.some((l) => putRe.test(l)))
|
|
33642
|
+
return false;
|
|
33643
|
+
return true;
|
|
33644
|
+
}
|
|
33200
33645
|
var CSHARP_SANITIZER_RES = [
|
|
33201
33646
|
{ re: /\b(?:HtmlEncode|JavaScriptStringEncode)\s*\(/, type: "xss" },
|
|
33202
33647
|
{ re: /\bHtmlEncoder\s*\.\s*Encode\s*\(/, type: "xss" },
|
|
33203
|
-
{ re: /\bPath\s*\.\s*GetFileName\s*\(/, type: "path_traversal" }
|
|
33648
|
+
{ re: /\bPath\s*\.\s*GetFileName\s*\(/, type: "path_traversal" },
|
|
33649
|
+
{ re: CSHARP_ALLOWLIST_STRIP_RE, type: "ldap_injection" },
|
|
33650
|
+
{ re: CSHARP_ALLOWLIST_STRIP_RE, type: "xpath_injection" },
|
|
33651
|
+
{ re: CSHARP_ALLOWLIST_STRIP_RE, type: "command_injection" },
|
|
33652
|
+
{ re: CSHARP_ALLOWLIST_STRIP_RE, type: "sql_injection" }
|
|
33204
33653
|
];
|
|
33205
33654
|
function csharpSanitizedVarsByType(code) {
|
|
33206
33655
|
const lines = code.split(`
|
|
@@ -33444,6 +33893,24 @@ function hasJavaImportFromPackage(packagePrefix, sourceLines) {
|
|
|
33444
33893
|
}
|
|
33445
33894
|
return false;
|
|
33446
33895
|
}
|
|
33896
|
+
function hasSameOriginLiteralPrefix(lineText) {
|
|
33897
|
+
const m = lineText.match(/\(\s*(['"`])([^'"`]*)\1\s*(?:\+|,|\))/);
|
|
33898
|
+
const prefix = m?.[2];
|
|
33899
|
+
if (prefix === undefined) {
|
|
33900
|
+
const t = lineText.match(/\(\s*`([^`$]*)\$\{/);
|
|
33901
|
+
if (!t)
|
|
33902
|
+
return false;
|
|
33903
|
+
return isSameOriginQueryPrefix(t[1]);
|
|
33904
|
+
}
|
|
33905
|
+
return isSameOriginQueryPrefix(prefix);
|
|
33906
|
+
}
|
|
33907
|
+
function isSameOriginQueryPrefix(prefix) {
|
|
33908
|
+
if (!prefix.startsWith("/"))
|
|
33909
|
+
return false;
|
|
33910
|
+
if (prefix.startsWith("//"))
|
|
33911
|
+
return false;
|
|
33912
|
+
return prefix.includes("?");
|
|
33913
|
+
}
|
|
33447
33914
|
|
|
33448
33915
|
class SinkFilterPass {
|
|
33449
33916
|
name = "sink-filter";
|
|
@@ -33455,7 +33922,8 @@ class SinkFilterPass {
|
|
|
33455
33922
|
const constProp = ctx.getResult("constant-propagation");
|
|
33456
33923
|
const langSources = ctx.getResult("language-sources");
|
|
33457
33924
|
const mergedSources = [...taintMatcher.sources, ...langSources.additionalSources];
|
|
33458
|
-
const
|
|
33925
|
+
const executableSources = ctx.code && ctx.language ? mergedSources.filter((s) => !isNonExecutableSourceLine(ctx.code, s.line, ctx.language)) : mergedSources;
|
|
33926
|
+
const sources = ctx.code ? executableSources.filter((s) => !isUnwrittenLocalMapKeyRead(ctx.code, s)) : executableSources;
|
|
33459
33927
|
const sinks = [...taintMatcher.sinks];
|
|
33460
33928
|
for (const s of langSources.additionalSinks) {
|
|
33461
33929
|
if (!sinks.some((x) => x.line === s.line && x.cwe === s.cwe && x.type === s.type)) {
|
|
@@ -33608,6 +34076,9 @@ class SinkFilterPass {
|
|
|
33608
34076
|
if (setHeaderMatch) {
|
|
33609
34077
|
return false;
|
|
33610
34078
|
}
|
|
34079
|
+
if (sink.type === "open_redirect" && hasSameOriginLiteralPrefix(sinkLineText)) {
|
|
34080
|
+
return false;
|
|
34081
|
+
}
|
|
33611
34082
|
if (sink.method === "cookie" && sink.type === "crlf") {
|
|
33612
34083
|
return false;
|
|
33613
34084
|
}
|
|
@@ -33747,13 +34218,23 @@ class SinkFilterPass {
|
|
|
33747
34218
|
filtered = filtered.filter((sink) => {
|
|
33748
34219
|
if (sink.type !== "command_injection")
|
|
33749
34220
|
return true;
|
|
33750
|
-
if (sink.method !== "ProcessBuilder" && sink.method !== "start")
|
|
34221
|
+
if (sink.method !== "ProcessBuilder" && sink.method !== "start" && sink.method !== "command") {
|
|
33751
34222
|
return true;
|
|
34223
|
+
}
|
|
33752
34224
|
const sinkLineText = sourceLines[sink.line - 1] ?? "";
|
|
33753
|
-
|
|
34225
|
+
const isCtorLine = /\bnew\s+ProcessBuilder\s*\(/.test(sinkLineText);
|
|
34226
|
+
const isCommandLine = /\.\s*command\s*\(/.test(sinkLineText);
|
|
34227
|
+
if (!isCtorLine && !isCommandLine)
|
|
33754
34228
|
return true;
|
|
33755
|
-
if (
|
|
34229
|
+
if (argvFirstLiteralIsShell(sinkLineText))
|
|
34230
|
+
return true;
|
|
34231
|
+
if (isCtorLine && PROCESS_BUILDER_ARGV_FORM_RE.test(sinkLineText))
|
|
34232
|
+
return false;
|
|
34233
|
+
if (isCommandLine && PROCESS_BUILDER_COMMAND_ARGV_FORM_RE.test(sinkLineText)) {
|
|
33756
34234
|
return false;
|
|
34235
|
+
}
|
|
34236
|
+
if (!isCtorLine)
|
|
34237
|
+
return true;
|
|
33757
34238
|
const ctorCall = irCalls.find((c) => c.method_name === "ProcessBuilder" && c.location.line === sink.line && (c.receiver === null || c.receiver === undefined));
|
|
33758
34239
|
if (!ctorCall || ctorCall.arguments.length === 0)
|
|
33759
34240
|
return true;
|
|
@@ -34023,6 +34504,15 @@ class SinkFilterPass {
|
|
|
34023
34504
|
if (language === "java" && !HTML_CONTENT_TYPE_RE.test(ctx.code)) {
|
|
34024
34505
|
filtered = filtered.filter((sink) => !(sink.type === "xss" && sink.method === "body"));
|
|
34025
34506
|
}
|
|
34507
|
+
if (language === "java") {
|
|
34508
|
+
const sourceLines = ctx.code.split(`
|
|
34509
|
+
`);
|
|
34510
|
+
filtered = filtered.filter((sink) => {
|
|
34511
|
+
if (sink.type !== "xss" || sink.class !== undefined)
|
|
34512
|
+
return true;
|
|
34513
|
+
return !JAVA_STDOUT_PRINT_RE.test(sourceLines[sink.line - 1] ?? "");
|
|
34514
|
+
});
|
|
34515
|
+
}
|
|
34026
34516
|
if (language === "java") {
|
|
34027
34517
|
const guardedLines = javaTraversalRejectGuardedLines(ctx.code);
|
|
34028
34518
|
if (guardedLines.size > 0) {
|
|
@@ -34108,6 +34598,43 @@ class SinkFilterPass {
|
|
|
34108
34598
|
return true;
|
|
34109
34599
|
});
|
|
34110
34600
|
}
|
|
34601
|
+
if (language === "csharp") {
|
|
34602
|
+
const sourceLines = ctx.code.split(`
|
|
34603
|
+
`);
|
|
34604
|
+
const constBaseClients = new Set;
|
|
34605
|
+
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*\)/;
|
|
34606
|
+
for (const line of sourceLines) {
|
|
34607
|
+
const m = declRe.exec(line);
|
|
34608
|
+
if (m)
|
|
34609
|
+
constBaseClients.add(m[1]);
|
|
34610
|
+
}
|
|
34611
|
+
if (constBaseClients.size > 0) {
|
|
34612
|
+
const relativeLiteralArgRe = /\.\s*(?:Get|Post|Put|Patch|Delete|Send|GetString|GetByteArray|GetStream)\w*Async\s*\(\s*(?:@?\$?)"([^"]*)"/;
|
|
34613
|
+
filtered = filtered.filter((sink) => {
|
|
34614
|
+
if (sink.type !== "ssrf")
|
|
34615
|
+
return true;
|
|
34616
|
+
const text = sourceLines[sink.line - 1] ?? "";
|
|
34617
|
+
let onConstClient = false;
|
|
34618
|
+
for (const v of constBaseClients) {
|
|
34619
|
+
if (new RegExp(`(?<![\\w])${escapeRegex(v)}\\s*\\.`).test(text)) {
|
|
34620
|
+
onConstClient = true;
|
|
34621
|
+
break;
|
|
34622
|
+
}
|
|
34623
|
+
}
|
|
34624
|
+
if (!onConstClient)
|
|
34625
|
+
return true;
|
|
34626
|
+
const m = relativeLiteralArgRe.exec(text);
|
|
34627
|
+
if (!m)
|
|
34628
|
+
return true;
|
|
34629
|
+
const lit = m[1];
|
|
34630
|
+
if (/^[A-Za-z][A-Za-z0-9+.-]*:/.test(lit))
|
|
34631
|
+
return true;
|
|
34632
|
+
if (lit.startsWith("//"))
|
|
34633
|
+
return true;
|
|
34634
|
+
return false;
|
|
34635
|
+
});
|
|
34636
|
+
}
|
|
34637
|
+
}
|
|
34111
34638
|
if (["javascript", "typescript"].includes(language)) {
|
|
34112
34639
|
const sourceLines = ctx.code.split(`
|
|
34113
34640
|
`);
|
|
@@ -34724,7 +35251,7 @@ function isXPathQuoteEscapedOnLine(lineText, varName) {
|
|
|
34724
35251
|
return seen > 0;
|
|
34725
35252
|
}
|
|
34726
35253
|
|
|
34727
|
-
//
|
|
35254
|
+
// ../circle-ir/dist/analysis/passes/sink-semantics-pass.js
|
|
34728
35255
|
function buildRegistry(entries) {
|
|
34729
35256
|
const registry = new Map;
|
|
34730
35257
|
for (const entry of entries) {
|
|
@@ -34772,7 +35299,7 @@ class SinkSemanticsPass {
|
|
|
34772
35299
|
}
|
|
34773
35300
|
}
|
|
34774
35301
|
|
|
34775
|
-
//
|
|
35302
|
+
// ../circle-ir/dist/analysis/dependency-versions.js
|
|
34776
35303
|
function resolveFastjsonFromPom(pomXml) {
|
|
34777
35304
|
if (!pomXml)
|
|
34778
35305
|
return null;
|
|
@@ -34950,7 +35477,7 @@ function fileConfiguresSnakeYamlSafely(source) {
|
|
|
34950
35477
|
return false;
|
|
34951
35478
|
}
|
|
34952
35479
|
|
|
34953
|
-
//
|
|
35480
|
+
// ../circle-ir/dist/analysis/passes/deserialization-safety-gate-pass.js
|
|
34954
35481
|
var FASTJSON_METHODS = new Set(["parseObject", "parse"]);
|
|
34955
35482
|
var FASTJSON_CLASSES = new Set(["JSON", "JSONObject"]);
|
|
34956
35483
|
var JACKSON_METHODS = new Set(["readValue", "convertValue", "treeToValue"]);
|
|
@@ -35027,7 +35554,7 @@ class DeserializationSafetyGatePass {
|
|
|
35027
35554
|
}
|
|
35028
35555
|
}
|
|
35029
35556
|
|
|
35030
|
-
//
|
|
35557
|
+
// ../circle-ir/dist/analysis/passes/prompt-injection-safety-gate-pass.js
|
|
35031
35558
|
function isDelimiterLiteral(lit) {
|
|
35032
35559
|
const s = lit.trim();
|
|
35033
35560
|
if (s.length === 0)
|
|
@@ -35270,7 +35797,7 @@ class PromptInjectionSafetyGatePass {
|
|
|
35270
35797
|
}
|
|
35271
35798
|
}
|
|
35272
35799
|
|
|
35273
|
-
//
|
|
35800
|
+
// ../circle-ir/dist/analysis/passes/speculative-prompt-param-source-pass.js
|
|
35274
35801
|
function returnOrAssignRhs(text) {
|
|
35275
35802
|
const t = text.trim();
|
|
35276
35803
|
const ret = t.match(/^return\s+(.+?);?$/);
|
|
@@ -35396,7 +35923,7 @@ class SpeculativePromptParamSourcePass {
|
|
|
35396
35923
|
}
|
|
35397
35924
|
}
|
|
35398
35925
|
|
|
35399
|
-
//
|
|
35926
|
+
// ../circle-ir/dist/analysis/passes/cli-main-reflection-suppress-pass.js
|
|
35400
35927
|
var REFLECTION_SINK_METHODS = new Set([
|
|
35401
35928
|
"forName",
|
|
35402
35929
|
"newInstance",
|
|
@@ -35584,7 +36111,7 @@ class CliMainReflectionSuppressPass {
|
|
|
35584
36111
|
}
|
|
35585
36112
|
}
|
|
35586
36113
|
|
|
35587
|
-
//
|
|
36114
|
+
// ../circle-ir/dist/analysis/passes/library-profile-sink-gate-pass.js
|
|
35588
36115
|
var DROPPED_SINK_TYPES = new Set([
|
|
35589
36116
|
"log_injection"
|
|
35590
36117
|
]);
|
|
@@ -35658,7 +36185,7 @@ class LibraryProfileCwe22PathGatePass {
|
|
|
35658
36185
|
droppedBySourceType: {}
|
|
35659
36186
|
};
|
|
35660
36187
|
}
|
|
35661
|
-
const flows = graph.ir.taint.flows;
|
|
36188
|
+
const flows = ctx.hasResult("interprocedural") ? ctx.getResult("interprocedural").additionalFlows : graph.ir.taint.flows;
|
|
35662
36189
|
if (!flows || flows.length === 0) {
|
|
35663
36190
|
return {
|
|
35664
36191
|
profile,
|
|
@@ -35668,19 +36195,18 @@ class LibraryProfileCwe22PathGatePass {
|
|
|
35668
36195
|
};
|
|
35669
36196
|
}
|
|
35670
36197
|
const droppedBySourceType = {};
|
|
35671
|
-
|
|
36198
|
+
let tagged = 0;
|
|
35672
36199
|
for (const flow of flows) {
|
|
35673
36200
|
if (flow.sink_type === "path_traversal" && CWE22_SPECULATIVE_SOURCE_TYPES.has(flow.source_type)) {
|
|
35674
36201
|
droppedBySourceType[flow.source_type] = (droppedBySourceType[flow.source_type] ?? 0) + 1;
|
|
35675
|
-
|
|
36202
|
+
const tags = flow.tags ?? [];
|
|
36203
|
+
if (!tags.includes(LIBRARY_API_SURFACE_TAG)) {
|
|
36204
|
+
flow.tags = [...tags, LIBRARY_API_SURFACE_TAG];
|
|
36205
|
+
}
|
|
36206
|
+
tagged++;
|
|
35676
36207
|
}
|
|
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
36208
|
}
|
|
36209
|
+
const dropped = tagged;
|
|
35684
36210
|
return {
|
|
35685
36211
|
profile,
|
|
35686
36212
|
applied: true,
|
|
@@ -35690,7 +36216,7 @@ class LibraryProfileCwe22PathGatePass {
|
|
|
35690
36216
|
}
|
|
35691
36217
|
}
|
|
35692
36218
|
|
|
35693
|
-
//
|
|
36219
|
+
// ../circle-ir/dist/analysis/passes/library-profile-xss-gate-pass.js
|
|
35694
36220
|
var XSS_NON_HTML_OUTPUT_CLASSES = new Set([
|
|
35695
36221
|
"StringBuilder",
|
|
35696
36222
|
"StringBuffer",
|
|
@@ -35771,7 +36297,7 @@ class LibraryProfileXssGatePass {
|
|
|
35771
36297
|
}
|
|
35772
36298
|
}
|
|
35773
36299
|
|
|
35774
|
-
//
|
|
36300
|
+
// ../circle-ir/dist/analysis/passes/taint-propagation-pass.js
|
|
35775
36301
|
class TaintPropagationPass {
|
|
35776
36302
|
name = "taint-propagation";
|
|
35777
36303
|
category = "security";
|
|
@@ -35826,6 +36352,63 @@ class TaintPropagationPass {
|
|
|
35826
36352
|
flows.push(f);
|
|
35827
36353
|
return true;
|
|
35828
36354
|
};
|
|
36355
|
+
if (ctx.language === "python" && typeof ctx.code === "string") {
|
|
36356
|
+
const pyTainted = buildPythonTaintedVars(ctx.code);
|
|
36357
|
+
if (pyTainted.size > 0) {
|
|
36358
|
+
for (const v of findPythonTrustBoundaryViolations(ctx.code, pyTainted)) {
|
|
36359
|
+
const sink = sinks.find((sk) => sk.line === v.sinkLine && sk.type === "trust_boundary");
|
|
36360
|
+
if (!sink)
|
|
36361
|
+
continue;
|
|
36362
|
+
const src = sources.find((sc) => sc.line === v.sourceLine) ?? sources.filter((sc) => sc.line <= v.sinkLine).sort((a, b) => b.line - a.line)[0];
|
|
36363
|
+
if (!src)
|
|
36364
|
+
continue;
|
|
36365
|
+
if (constProp.unreachableLines.has(v.sinkLine))
|
|
36366
|
+
continue;
|
|
36367
|
+
pushIfNew({
|
|
36368
|
+
source_line: src.line,
|
|
36369
|
+
sink_line: v.sinkLine,
|
|
36370
|
+
source_type: src.type,
|
|
36371
|
+
sink_type: "trust_boundary",
|
|
36372
|
+
path: [
|
|
36373
|
+
{ variable: src.variable ?? "session_key", line: src.line, type: "source" },
|
|
36374
|
+
{ variable: src.variable ?? "session_key", line: v.sinkLine, type: "sink" }
|
|
36375
|
+
],
|
|
36376
|
+
confidence: (src.confidence ?? 1) * (sink.confidence ?? 1),
|
|
36377
|
+
sanitized: false
|
|
36378
|
+
});
|
|
36379
|
+
}
|
|
36380
|
+
}
|
|
36381
|
+
}
|
|
36382
|
+
if (ctx.language === "python" && typeof ctx.code === "string") {
|
|
36383
|
+
const pyTainted = buildPythonTaintedVars(ctx.code);
|
|
36384
|
+
if (pyTainted.size > 0) {
|
|
36385
|
+
const xssSanitizerLines = sanitizers.filter((sa) => sa.sanitizes.includes("xss")).map((sa) => sa.line);
|
|
36386
|
+
for (const rx of findPythonReturnXSSSinks(ctx.code, pyTainted)) {
|
|
36387
|
+
if (constProp.unreachableLines.has(rx.sinkLine))
|
|
36388
|
+
continue;
|
|
36389
|
+
const sink = sinks.find((sk) => sk.line === rx.sinkLine && sk.type === "xss");
|
|
36390
|
+
if (!sink)
|
|
36391
|
+
continue;
|
|
36392
|
+
const src = sources.filter((sc) => sc.line <= rx.sinkLine).sort((a, b) => b.line - a.line)[0];
|
|
36393
|
+
if (!src)
|
|
36394
|
+
continue;
|
|
36395
|
+
if (xssSanitizerLines.some((l) => l >= src.line && l <= rx.sinkLine))
|
|
36396
|
+
continue;
|
|
36397
|
+
pushIfNew({
|
|
36398
|
+
source_line: src.line,
|
|
36399
|
+
sink_line: rx.sinkLine,
|
|
36400
|
+
source_type: src.type,
|
|
36401
|
+
sink_type: "xss",
|
|
36402
|
+
path: [
|
|
36403
|
+
{ variable: src.variable ?? "response", line: src.line, type: "source" },
|
|
36404
|
+
{ variable: src.variable ?? "response", line: rx.sinkLine, type: "sink" }
|
|
36405
|
+
],
|
|
36406
|
+
confidence: (src.confidence ?? 1) * (sink.confidence ?? 1),
|
|
36407
|
+
sanitized: false
|
|
36408
|
+
});
|
|
36409
|
+
}
|
|
36410
|
+
}
|
|
36411
|
+
}
|
|
35829
36412
|
const arrayFlows = detectArrayElementFlows(calls, sources, sinks, constProp.taintedArrayElements, constProp.unreachableLines, types) ?? [];
|
|
35830
36413
|
for (const f of arrayFlows) {
|
|
35831
36414
|
pushIfNew(f);
|
|
@@ -36515,6 +37098,108 @@ function isReassignedToLiteralBetween(code, variable, srcLine, sinkLine) {
|
|
|
36515
37098
|
}
|
|
36516
37099
|
return false;
|
|
36517
37100
|
}
|
|
37101
|
+
var MASKABLE_STRING_LANGUAGES = new Set(["python", "javascript", "typescript"]);
|
|
37102
|
+
function maskStringLiteralsForTokenScan(expr) {
|
|
37103
|
+
let out2 = "";
|
|
37104
|
+
let i2 = 0;
|
|
37105
|
+
const braceExprs = (body2) => {
|
|
37106
|
+
let acc = "";
|
|
37107
|
+
for (let j = 0;j < body2.length; ) {
|
|
37108
|
+
if (body2[j] === "{" && body2[j + 1] === "{") {
|
|
37109
|
+
j += 2;
|
|
37110
|
+
continue;
|
|
37111
|
+
}
|
|
37112
|
+
if (body2[j] === "}" && body2[j + 1] === "}") {
|
|
37113
|
+
j += 2;
|
|
37114
|
+
continue;
|
|
37115
|
+
}
|
|
37116
|
+
if (body2[j] === "{") {
|
|
37117
|
+
j++;
|
|
37118
|
+
let depth = 1;
|
|
37119
|
+
let inner = "";
|
|
37120
|
+
while (j < body2.length && depth > 0) {
|
|
37121
|
+
if (body2[j] === "{")
|
|
37122
|
+
depth++;
|
|
37123
|
+
else if (body2[j] === "}") {
|
|
37124
|
+
depth--;
|
|
37125
|
+
if (depth === 0)
|
|
37126
|
+
break;
|
|
37127
|
+
}
|
|
37128
|
+
inner += body2[j];
|
|
37129
|
+
j++;
|
|
37130
|
+
}
|
|
37131
|
+
j++;
|
|
37132
|
+
acc += " " + maskStringLiteralsForTokenScan(inner) + " ";
|
|
37133
|
+
continue;
|
|
37134
|
+
}
|
|
37135
|
+
j++;
|
|
37136
|
+
}
|
|
37137
|
+
return acc;
|
|
37138
|
+
};
|
|
37139
|
+
while (i2 < expr.length) {
|
|
37140
|
+
const ch = expr[i2];
|
|
37141
|
+
if (ch === "`") {
|
|
37142
|
+
i2++;
|
|
37143
|
+
let acc = "";
|
|
37144
|
+
while (i2 < expr.length && expr[i2] !== "`") {
|
|
37145
|
+
if (expr[i2] === "\\") {
|
|
37146
|
+
i2 += 2;
|
|
37147
|
+
continue;
|
|
37148
|
+
}
|
|
37149
|
+
if (expr[i2] === "$" && expr[i2 + 1] === "{") {
|
|
37150
|
+
i2 += 2;
|
|
37151
|
+
let depth = 1;
|
|
37152
|
+
let inner = "";
|
|
37153
|
+
while (i2 < expr.length && depth > 0) {
|
|
37154
|
+
if (expr[i2] === "{")
|
|
37155
|
+
depth++;
|
|
37156
|
+
else if (expr[i2] === "}") {
|
|
37157
|
+
depth--;
|
|
37158
|
+
if (depth === 0)
|
|
37159
|
+
break;
|
|
37160
|
+
}
|
|
37161
|
+
inner += expr[i2];
|
|
37162
|
+
i2++;
|
|
37163
|
+
}
|
|
37164
|
+
i2++;
|
|
37165
|
+
acc += " " + maskStringLiteralsForTokenScan(inner) + " ";
|
|
37166
|
+
continue;
|
|
37167
|
+
}
|
|
37168
|
+
i2++;
|
|
37169
|
+
}
|
|
37170
|
+
i2++;
|
|
37171
|
+
out2 += " " + acc + " ";
|
|
37172
|
+
continue;
|
|
37173
|
+
}
|
|
37174
|
+
if (ch === '"' || ch === "'") {
|
|
37175
|
+
const pm = /[A-Za-z_][A-Za-z0-9_]*$/.exec(out2);
|
|
37176
|
+
const prefix = pm ? pm[0] : "";
|
|
37177
|
+
const isPrefix = prefix.length > 0 && /^[rRbBuUfF]+$/.test(prefix);
|
|
37178
|
+
const isF = isPrefix && /[fF]/.test(prefix);
|
|
37179
|
+
if (isPrefix)
|
|
37180
|
+
out2 = out2.slice(0, out2.length - prefix.length) + " ";
|
|
37181
|
+
const triple = expr.startsWith(ch.repeat(3), i2);
|
|
37182
|
+
const delim = triple ? ch.repeat(3) : ch;
|
|
37183
|
+
i2 += delim.length;
|
|
37184
|
+
let body2 = "";
|
|
37185
|
+
while (i2 < expr.length && !expr.startsWith(delim, i2)) {
|
|
37186
|
+
if (expr[i2] === "\\") {
|
|
37187
|
+
body2 += " ";
|
|
37188
|
+
i2 += 2;
|
|
37189
|
+
continue;
|
|
37190
|
+
}
|
|
37191
|
+
body2 += expr[i2];
|
|
37192
|
+
i2++;
|
|
37193
|
+
}
|
|
37194
|
+
i2 += delim.length;
|
|
37195
|
+
out2 += isF ? " " + braceExprs(body2) + " " : " ";
|
|
37196
|
+
continue;
|
|
37197
|
+
}
|
|
37198
|
+
out2 += ch;
|
|
37199
|
+
i2++;
|
|
37200
|
+
}
|
|
37201
|
+
return out2;
|
|
37202
|
+
}
|
|
36518
37203
|
function detectExpressionScanFlows(calls, sources, sinks, sanitizers, unreachableLines, tainted, code, language, types) {
|
|
36519
37204
|
const flows = [];
|
|
36520
37205
|
const sourcesWithVar = sources.filter((s) => typeof s.variable === "string" && s.variable.length > 0);
|
|
@@ -36904,7 +37589,8 @@ function detectExpressionScanFlows(calls, sources, sinks, sanitizers, unreachabl
|
|
|
36904
37589
|
const expr = arg.expression;
|
|
36905
37590
|
if (!expr)
|
|
36906
37591
|
continue;
|
|
36907
|
-
const
|
|
37592
|
+
const scannable = language !== undefined && MASKABLE_STRING_LANGUAGES.has(language) ? maskStringLiteralsForTokenScan(expr) : expr;
|
|
37593
|
+
const exprIdentMatches = scannable.match(/[\p{L}\p{N}_]+/gu);
|
|
36908
37594
|
let candidates = complexSources.length > 0 ? complexSources.slice() : null;
|
|
36909
37595
|
if (exprIdentMatches) {
|
|
36910
37596
|
for (const id of new Set(exprIdentMatches)) {
|
|
@@ -37054,7 +37740,7 @@ function pickScopedSource(sources, sinkLine, methodName, types, taintedVar) {
|
|
|
37054
37740
|
return sources[0];
|
|
37055
37741
|
}
|
|
37056
37742
|
|
|
37057
|
-
//
|
|
37743
|
+
// ../circle-ir/dist/analysis/interprocedural.js
|
|
37058
37744
|
function analyzeInterprocedural2(graphOrTypes, callsOrSources, dfgOrSinks, sourcesOrSanitizers, sinksOrOptions, sanitizersArg, optionsArg = {}) {
|
|
37059
37745
|
let graph;
|
|
37060
37746
|
let sources;
|
|
@@ -37568,7 +38254,7 @@ function findTaintBridges2(result) {
|
|
|
37568
38254
|
return bridges;
|
|
37569
38255
|
}
|
|
37570
38256
|
|
|
37571
|
-
//
|
|
38257
|
+
// ../circle-ir/dist/analysis/passes/interprocedural-pass.js
|
|
37572
38258
|
class InterproceduralPass {
|
|
37573
38259
|
name = "interprocedural";
|
|
37574
38260
|
category = "security";
|
|
@@ -37774,7 +38460,7 @@ class InterproceduralPass {
|
|
|
37774
38460
|
}
|
|
37775
38461
|
}
|
|
37776
38462
|
|
|
37777
|
-
//
|
|
38463
|
+
// ../circle-ir/dist/analysis/passes/dead-code-pass.js
|
|
37778
38464
|
class DeadCodePass {
|
|
37779
38465
|
name = "dead-code";
|
|
37780
38466
|
category = "reliability";
|
|
@@ -37850,7 +38536,7 @@ class DeadCodePass {
|
|
|
37850
38536
|
}
|
|
37851
38537
|
}
|
|
37852
38538
|
|
|
37853
|
-
//
|
|
38539
|
+
// ../circle-ir/dist/analysis/passes/missing-await-pass.js
|
|
37854
38540
|
var ASYNC_METHODS = new Set([
|
|
37855
38541
|
"readFile",
|
|
37856
38542
|
"writeFile",
|
|
@@ -37929,7 +38615,7 @@ class MissingAwaitPass {
|
|
|
37929
38615
|
}
|
|
37930
38616
|
}
|
|
37931
38617
|
|
|
37932
|
-
//
|
|
38618
|
+
// ../circle-ir/dist/analysis/passes/n-plus-one-pass.js
|
|
37933
38619
|
var HIGH_CONFIDENCE_DB_METHODS = new Set([
|
|
37934
38620
|
"executeQuery",
|
|
37935
38621
|
"executeUpdate",
|
|
@@ -38052,7 +38738,7 @@ class NPlusOnePass {
|
|
|
38052
38738
|
}
|
|
38053
38739
|
}
|
|
38054
38740
|
|
|
38055
|
-
//
|
|
38741
|
+
// ../circle-ir/dist/analysis/passes/missing-public-doc-pass.js
|
|
38056
38742
|
var TEST_PATH_RE = /[/._](test|tests|spec|specs|__tests?__|__mocks?__)[/._]/i;
|
|
38057
38743
|
var UTIL_DIR_RE = /[/](utils?|helpers?|internal|private|common|shared)[/]/i;
|
|
38058
38744
|
function hasDocCommentBefore(lines, startLine) {
|
|
@@ -38159,7 +38845,7 @@ class MissingPublicDocPass {
|
|
|
38159
38845
|
}
|
|
38160
38846
|
}
|
|
38161
38847
|
|
|
38162
|
-
//
|
|
38848
|
+
// ../circle-ir/dist/analysis/passes/todo-in-prod-pass.js
|
|
38163
38849
|
var TEST_PATH_RE2 = /[/._](test|tests|spec|specs|__tests?__|__mocks?__)[/._]/i;
|
|
38164
38850
|
var MARKER_RE = /(?:\/\/|#|--|^\s*\*)\s*(TODO|FIXME|HACK|XXX)\b/i;
|
|
38165
38851
|
function markerSeverity(marker) {
|
|
@@ -38205,7 +38891,7 @@ class TodoInProdPass {
|
|
|
38205
38891
|
}
|
|
38206
38892
|
}
|
|
38207
38893
|
|
|
38208
|
-
//
|
|
38894
|
+
// ../circle-ir/dist/analysis/passes/string-concat-loop-pass.js
|
|
38209
38895
|
var CONCAT_RE = /\b([a-zA-Z_$][a-zA-Z0-9_$]*)\s*\+=/;
|
|
38210
38896
|
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
38897
|
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 +38954,7 @@ class StringConcatLoopPass {
|
|
|
38268
38954
|
}
|
|
38269
38955
|
}
|
|
38270
38956
|
|
|
38271
|
-
//
|
|
38957
|
+
// ../circle-ir/dist/analysis/passes/sync-io-async-pass.js
|
|
38272
38958
|
var BLOCKING_METHODS = new Set([
|
|
38273
38959
|
"sleep"
|
|
38274
38960
|
]);
|
|
@@ -38329,7 +39015,7 @@ class SyncIoAsyncPass {
|
|
|
38329
39015
|
}
|
|
38330
39016
|
}
|
|
38331
39017
|
|
|
38332
|
-
//
|
|
39018
|
+
// ../circle-ir/dist/analysis/passes/unchecked-return-pass.js
|
|
38333
39019
|
var MUST_CHECK_HIGH = new Set([
|
|
38334
39020
|
"createNewFile",
|
|
38335
39021
|
"mkdir",
|
|
@@ -38402,7 +39088,7 @@ class UncheckedReturnPass {
|
|
|
38402
39088
|
}
|
|
38403
39089
|
}
|
|
38404
39090
|
|
|
38405
|
-
//
|
|
39091
|
+
// ../circle-ir/dist/analysis/passes/null-deref-pass.js
|
|
38406
39092
|
var NULL_EXPR_RE = /^\s*(null|None|undefined)\s*$/;
|
|
38407
39093
|
function escRe(s) {
|
|
38408
39094
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -38484,7 +39170,7 @@ class NullDerefPass {
|
|
|
38484
39170
|
}
|
|
38485
39171
|
}
|
|
38486
39172
|
|
|
38487
|
-
//
|
|
39173
|
+
// ../circle-ir/dist/analysis/passes/resource-leak-pass.js
|
|
38488
39174
|
function escapeRegex2(s) {
|
|
38489
39175
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
38490
39176
|
}
|
|
@@ -38761,7 +39447,7 @@ class ResourceLeakPass {
|
|
|
38761
39447
|
}
|
|
38762
39448
|
}
|
|
38763
39449
|
|
|
38764
|
-
//
|
|
39450
|
+
// ../circle-ir/dist/graph/scope-graph.js
|
|
38765
39451
|
function hasDeclKeyword(lineText, language) {
|
|
38766
39452
|
switch (language) {
|
|
38767
39453
|
case "java":
|
|
@@ -38801,7 +39487,7 @@ class ScopeGraph {
|
|
|
38801
39487
|
}
|
|
38802
39488
|
}
|
|
38803
39489
|
|
|
38804
|
-
//
|
|
39490
|
+
// ../circle-ir/dist/analysis/passes/variable-shadowing-pass.js
|
|
38805
39491
|
var SKIP_NAMES = new Set([
|
|
38806
39492
|
"let",
|
|
38807
39493
|
"const",
|
|
@@ -38959,7 +39645,7 @@ class VariableShadowingPass {
|
|
|
38959
39645
|
}
|
|
38960
39646
|
}
|
|
38961
39647
|
|
|
38962
|
-
//
|
|
39648
|
+
// ../circle-ir/dist/analysis/passes/leaked-global-pass.js
|
|
38963
39649
|
var SKIP_NAMES2 = new Set([
|
|
38964
39650
|
"_",
|
|
38965
39651
|
"e",
|
|
@@ -39046,7 +39732,7 @@ class LeakedGlobalPass {
|
|
|
39046
39732
|
}
|
|
39047
39733
|
}
|
|
39048
39734
|
|
|
39049
|
-
//
|
|
39735
|
+
// ../circle-ir/dist/analysis/passes/unused-variable-pass.js
|
|
39050
39736
|
var SKIP_NAMES3 = new Set([
|
|
39051
39737
|
"_",
|
|
39052
39738
|
"unused",
|
|
@@ -39191,7 +39877,7 @@ class UnusedVariablePass {
|
|
|
39191
39877
|
}
|
|
39192
39878
|
}
|
|
39193
39879
|
|
|
39194
|
-
//
|
|
39880
|
+
// ../circle-ir/dist/analysis/passes/dependency-fan-out-pass.js
|
|
39195
39881
|
var DEFAULT_THRESHOLD = 20;
|
|
39196
39882
|
|
|
39197
39883
|
class DependencyFanOutPass {
|
|
@@ -39223,7 +39909,7 @@ class DependencyFanOutPass {
|
|
|
39223
39909
|
}
|
|
39224
39910
|
}
|
|
39225
39911
|
|
|
39226
|
-
//
|
|
39912
|
+
// ../circle-ir/dist/analysis/passes/stale-doc-ref-pass.js
|
|
39227
39913
|
var DOC_BLOCK_RE = /\/\*\*([\s\S]*?)\*\//g;
|
|
39228
39914
|
var LINK_RE = /\{@link\s+([\w.#]+)/g;
|
|
39229
39915
|
var SEE_RE = /@see\s+([\w.#]+)/g;
|
|
@@ -39302,7 +39988,7 @@ class StaleDocRefPass {
|
|
|
39302
39988
|
}
|
|
39303
39989
|
}
|
|
39304
39990
|
|
|
39305
|
-
//
|
|
39991
|
+
// ../circle-ir/dist/analysis/passes/infinite-loop-pass.js
|
|
39306
39992
|
var EXIT_KEYWORDS = /\b(return|throw|raise|break|System\.exit|process\.exit|os\._exit|exit!\()\b/;
|
|
39307
39993
|
var ITERATOR_LOOP_PATTERNS = [
|
|
39308
39994
|
/\bfor\s*\([^)]*\s+of\s+/,
|
|
@@ -39421,7 +40107,7 @@ class InfiniteLoopPass {
|
|
|
39421
40107
|
}
|
|
39422
40108
|
}
|
|
39423
40109
|
|
|
39424
|
-
//
|
|
40110
|
+
// ../circle-ir/dist/analysis/passes/deep-inheritance-pass.js
|
|
39425
40111
|
var DEPTH_THRESHOLD = 5;
|
|
39426
40112
|
var CYCLE_GUARD = 20;
|
|
39427
40113
|
|
|
@@ -39484,7 +40170,7 @@ class DeepInheritancePass {
|
|
|
39484
40170
|
}
|
|
39485
40171
|
}
|
|
39486
40172
|
|
|
39487
|
-
//
|
|
40173
|
+
// ../circle-ir/dist/analysis/passes/redundant-loop-pass.js
|
|
39488
40174
|
var LENGTH_PATTERN = /\b([A-Za-z_$][A-Za-z0-9_$]*)\s*\.\s*(?:length|size\(\)|count\(\))/g;
|
|
39489
40175
|
var LENGTH_PATTERN_METHODS = /\b([A-Za-z_$][A-Za-z0-9_$]*)\s*\.\s*(?:size\(\)|count\(\))/g;
|
|
39490
40176
|
var OBJECT_STATIC_PATTERN = /\bObject\s*\.\s*(?:keys|values|entries)\s*\(\s*([A-Za-z_$][A-Za-z0-9_$]*)\s*\)/g;
|
|
@@ -39607,7 +40293,7 @@ class RedundantLoopPass {
|
|
|
39607
40293
|
}
|
|
39608
40294
|
}
|
|
39609
40295
|
|
|
39610
|
-
//
|
|
40296
|
+
// ../circle-ir/dist/analysis/passes/unbounded-collection-pass.js
|
|
39611
40297
|
var GROW_METHODS = {
|
|
39612
40298
|
java: new Set(["add", "put", "offer", "push", "addAll", "addFirst", "addLast", "enqueue", "insert"]),
|
|
39613
40299
|
javascript: new Set(["push", "set", "add", "unshift", "append", "prepend"]),
|
|
@@ -39731,7 +40417,7 @@ class UnboundedCollectionPass {
|
|
|
39731
40417
|
}
|
|
39732
40418
|
}
|
|
39733
40419
|
|
|
39734
|
-
//
|
|
40420
|
+
// ../circle-ir/dist/analysis/passes/serial-await-pass.js
|
|
39735
40421
|
var AWAIT_ASSIGN_RE = /(?:const|let|var)?\s*(\w+)\s*=\s*await\s/;
|
|
39736
40422
|
var AWAIT_RE = /\bawait\s/;
|
|
39737
40423
|
|
|
@@ -39827,7 +40513,7 @@ class SerialAwaitPass {
|
|
|
39827
40513
|
}
|
|
39828
40514
|
}
|
|
39829
40515
|
|
|
39830
|
-
//
|
|
40516
|
+
// ../circle-ir/dist/analysis/passes/react-inline-jsx-pass.js
|
|
39831
40517
|
var JSX_COMPONENT_RE = /<[A-Z][A-Za-z0-9]*/;
|
|
39832
40518
|
var INLINE_OBJECT_RE = /\s([A-Za-z][A-Za-z0-9_]*)=\{\{/g;
|
|
39833
40519
|
var INLINE_ARROW_RE = /\s([A-Za-z][A-Za-z0-9_]*)=\{(?:\(|[A-Za-z_$]).*?=>/g;
|
|
@@ -39931,7 +40617,7 @@ class ReactInlineJsxPass {
|
|
|
39931
40617
|
}
|
|
39932
40618
|
}
|
|
39933
40619
|
|
|
39934
|
-
//
|
|
40620
|
+
// ../circle-ir/dist/graph/exception-flow-graph.js
|
|
39935
40621
|
class ExceptionFlowGraph2 {
|
|
39936
40622
|
pairs;
|
|
39937
40623
|
catchEntryIds;
|
|
@@ -39982,7 +40668,7 @@ class ExceptionFlowGraph2 {
|
|
|
39982
40668
|
}
|
|
39983
40669
|
}
|
|
39984
40670
|
|
|
39985
|
-
//
|
|
40671
|
+
// ../circle-ir/dist/analysis/passes/swallowed-exception-pass.js
|
|
39986
40672
|
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
40673
|
|
|
39988
40674
|
class SwallowedExceptionPass {
|
|
@@ -40080,7 +40766,7 @@ class SwallowedExceptionPass {
|
|
|
40080
40766
|
}
|
|
40081
40767
|
}
|
|
40082
40768
|
|
|
40083
|
-
//
|
|
40769
|
+
// ../circle-ir/dist/analysis/passes/broad-catch-pass.js
|
|
40084
40770
|
var JAVA_BROAD_RE = /catch\s*\(\s*(Exception|Throwable|RuntimeException|Error)\s/;
|
|
40085
40771
|
var PYTHON_BROAD_RE = /^\s*except\s*:|except\s+(Exception|BaseException)\b/;
|
|
40086
40772
|
|
|
@@ -40136,7 +40822,7 @@ class BroadCatchPass {
|
|
|
40136
40822
|
}
|
|
40137
40823
|
}
|
|
40138
40824
|
|
|
40139
|
-
//
|
|
40825
|
+
// ../circle-ir/dist/analysis/passes/unhandled-exception-pass.js
|
|
40140
40826
|
var JS_THROW_RE = /^\s*throw\s+/;
|
|
40141
40827
|
var PYTHON_RAISE_RE = /^\s*raise\b/;
|
|
40142
40828
|
function isValidationThrow(lines, throwLine) {
|
|
@@ -40306,7 +40992,7 @@ class UnhandledExceptionPass {
|
|
|
40306
40992
|
}
|
|
40307
40993
|
}
|
|
40308
40994
|
|
|
40309
|
-
//
|
|
40995
|
+
// ../circle-ir/dist/analysis/passes/double-close-pass.js
|
|
40310
40996
|
var RESOURCE_CTORS2 = new Set([
|
|
40311
40997
|
"FileInputStream",
|
|
40312
40998
|
"FileOutputStream",
|
|
@@ -40421,7 +41107,7 @@ class DoubleClosePass {
|
|
|
40421
41107
|
}
|
|
40422
41108
|
}
|
|
40423
41109
|
|
|
40424
|
-
//
|
|
41110
|
+
// ../circle-ir/dist/analysis/passes/use-after-close-pass.js
|
|
40425
41111
|
var RESOURCE_CTORS3 = new Set([
|
|
40426
41112
|
"FileInputStream",
|
|
40427
41113
|
"FileOutputStream",
|
|
@@ -40529,7 +41215,7 @@ class UseAfterClosePass {
|
|
|
40529
41215
|
}
|
|
40530
41216
|
}
|
|
40531
41217
|
|
|
40532
|
-
//
|
|
41218
|
+
// ../circle-ir/dist/graph/dominator-graph.js
|
|
40533
41219
|
function computeRPO(cfg, entryId) {
|
|
40534
41220
|
const outgoing = new Map;
|
|
40535
41221
|
for (const edge of cfg.edges) {
|
|
@@ -40694,7 +41380,7 @@ class DominatorGraph2 {
|
|
|
40694
41380
|
}
|
|
40695
41381
|
}
|
|
40696
41382
|
|
|
40697
|
-
//
|
|
41383
|
+
// ../circle-ir/dist/analysis/passes/cleanup-verify-pass.js
|
|
40698
41384
|
var RESOURCE_CTORS4 = new Set([
|
|
40699
41385
|
"FileInputStream",
|
|
40700
41386
|
"FileOutputStream",
|
|
@@ -40819,7 +41505,7 @@ class CleanupVerifyPass {
|
|
|
40819
41505
|
}
|
|
40820
41506
|
}
|
|
40821
41507
|
|
|
40822
|
-
//
|
|
41508
|
+
// ../circle-ir/dist/analysis/passes/missing-override-pass.js
|
|
40823
41509
|
class MissingOverridePass {
|
|
40824
41510
|
name = "missing-override";
|
|
40825
41511
|
category = "maintainability";
|
|
@@ -40906,7 +41592,7 @@ class MissingOverridePass {
|
|
|
40906
41592
|
}
|
|
40907
41593
|
}
|
|
40908
41594
|
|
|
40909
|
-
//
|
|
41595
|
+
// ../circle-ir/dist/analysis/passes/unused-interface-method-pass.js
|
|
40910
41596
|
class UnusedInterfaceMethodPass {
|
|
40911
41597
|
name = "unused-interface-method";
|
|
40912
41598
|
category = "maintainability";
|
|
@@ -40949,7 +41635,7 @@ class UnusedInterfaceMethodPass {
|
|
|
40949
41635
|
}
|
|
40950
41636
|
}
|
|
40951
41637
|
|
|
40952
|
-
//
|
|
41638
|
+
// ../circle-ir/dist/analysis/passes/blocking-main-thread-pass.js
|
|
40953
41639
|
var HTTP_DECORATORS = new Set([
|
|
40954
41640
|
"Get",
|
|
40955
41641
|
"Post",
|
|
@@ -40988,6 +41674,18 @@ var CRYPTO_BLOCKING_METHODS = new Set([
|
|
|
40988
41674
|
"deriveKeySync"
|
|
40989
41675
|
]);
|
|
40990
41676
|
var SYNC_SUFFIX_RE2 = /Sync$/;
|
|
41677
|
+
var ROUTER_METHODS = new Set([
|
|
41678
|
+
"get",
|
|
41679
|
+
"post",
|
|
41680
|
+
"put",
|
|
41681
|
+
"patch",
|
|
41682
|
+
"delete",
|
|
41683
|
+
"all",
|
|
41684
|
+
"options",
|
|
41685
|
+
"head",
|
|
41686
|
+
"use"
|
|
41687
|
+
]);
|
|
41688
|
+
var FN_ARG_PARAMS_RE = /^(?:async\s+)?(?:function\s*[\w$]*\s*)?\(([^)]*)\)\s*(?:=>|\{)|^(?:async\s+)?([A-Za-z_$][\w$]*)\s*=>/;
|
|
40991
41689
|
|
|
40992
41690
|
class BlockingMainThreadPass {
|
|
40993
41691
|
name = "blocking-main-thread";
|
|
@@ -41010,8 +41708,10 @@ class BlockingMainThreadPass {
|
|
|
41010
41708
|
}
|
|
41011
41709
|
}
|
|
41012
41710
|
}
|
|
41013
|
-
|
|
41711
|
+
const inlineHandlers = this.collectInlineHandlerNames(graph.ir.calls);
|
|
41712
|
+
if (handlerRanges.length === 0 && inlineHandlers.size === 0) {
|
|
41014
41713
|
return { blockingInHandlers: [] };
|
|
41714
|
+
}
|
|
41015
41715
|
const blockingInHandlers = [];
|
|
41016
41716
|
for (const call of graph.ir.calls) {
|
|
41017
41717
|
const name2 = call.method_name;
|
|
@@ -41020,7 +41720,8 @@ class BlockingMainThreadPass {
|
|
|
41020
41720
|
if (!isCrypto && !isSyncSuffix)
|
|
41021
41721
|
continue;
|
|
41022
41722
|
const line = call.location.line;
|
|
41023
|
-
const
|
|
41723
|
+
const enclosing = call.in_method ?? null;
|
|
41724
|
+
const range = handlerRanges.find((r) => line >= r.start && line <= r.end) ?? (enclosing && inlineHandlers.has(enclosing) ? { start: line, end: line, name: enclosing } : undefined);
|
|
41024
41725
|
if (!range)
|
|
41025
41726
|
continue;
|
|
41026
41727
|
const reason = isCrypto ? "crypto" : "sync-suffix";
|
|
@@ -41042,6 +41743,24 @@ class BlockingMainThreadPass {
|
|
|
41042
41743
|
}
|
|
41043
41744
|
return { blockingInHandlers };
|
|
41044
41745
|
}
|
|
41746
|
+
collectInlineHandlerNames(calls) {
|
|
41747
|
+
const names = new Set;
|
|
41748
|
+
for (const call of calls) {
|
|
41749
|
+
if (!ROUTER_METHODS.has(call.method_name))
|
|
41750
|
+
continue;
|
|
41751
|
+
for (const arg of call.arguments) {
|
|
41752
|
+
const match = FN_ARG_PARAMS_RE.exec((arg.expression ?? "").trim());
|
|
41753
|
+
if (!match)
|
|
41754
|
+
continue;
|
|
41755
|
+
const params = (match[1] ?? match[2] ?? "").split(",").map((p) => p.trim().toLowerCase()).filter((p) => p.length > 0);
|
|
41756
|
+
if (params.some((p) => HANDLER_PARAM_NAMES.has(p))) {
|
|
41757
|
+
names.add(`${call.method_name}_handler`);
|
|
41758
|
+
break;
|
|
41759
|
+
}
|
|
41760
|
+
}
|
|
41761
|
+
}
|
|
41762
|
+
return names;
|
|
41763
|
+
}
|
|
41045
41764
|
isRequestHandler(method) {
|
|
41046
41765
|
if (method.annotations.some((a) => HTTP_DECORATORS.has(a)))
|
|
41047
41766
|
return true;
|
|
@@ -41052,7 +41771,7 @@ class BlockingMainThreadPass {
|
|
|
41052
41771
|
}
|
|
41053
41772
|
}
|
|
41054
41773
|
|
|
41055
|
-
//
|
|
41774
|
+
// ../circle-ir/dist/analysis/passes/excessive-allocation-pass.js
|
|
41056
41775
|
var ALLOC_PATTERNS = {
|
|
41057
41776
|
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
41777
|
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 +41838,7 @@ class ExcessiveAllocationPass {
|
|
|
41119
41838
|
}
|
|
41120
41839
|
}
|
|
41121
41840
|
|
|
41122
|
-
//
|
|
41841
|
+
// ../circle-ir/dist/analysis/passes/missing-stream-pass.js
|
|
41123
41842
|
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
41843
|
var JS_STREAM_RE = /\.pipe\s*\(|\.on\s*\(\s*['"]data['"]|for\s+await\s*\(|\bcreateReadStream\b|\bstream\b/i;
|
|
41125
41844
|
var JAVA_WHOLE_READ_RE = /\bFiles\.readAllBytes\s*\(|\bFiles\.readAllLines\s*\(|\bFiles\.readString\s*\(|\bnew\s+BufferedReader\s*\(|\bFileInputStream\b/;
|
|
@@ -41266,7 +41985,7 @@ class MissingStreamPass {
|
|
|
41266
41985
|
}
|
|
41267
41986
|
}
|
|
41268
41987
|
|
|
41269
|
-
//
|
|
41988
|
+
// ../circle-ir/dist/analysis/passes/god-class-pass.js
|
|
41270
41989
|
var WMC_THRESHOLD = 47;
|
|
41271
41990
|
var LCOM2_THRESHOLD = 0.8;
|
|
41272
41991
|
var CBO_THRESHOLD = 14;
|
|
@@ -41432,7 +42151,7 @@ class GodClassPass {
|
|
|
41432
42151
|
}
|
|
41433
42152
|
}
|
|
41434
42153
|
|
|
41435
|
-
//
|
|
42154
|
+
// ../circle-ir/dist/analysis/passes/naming-convention-pass.js
|
|
41436
42155
|
var PASCAL_CASE_RE = /^[A-Z][A-Za-z0-9]*$/;
|
|
41437
42156
|
var CAMEL_CASE_RE = /^[a-z][a-zA-Z0-9]*$/;
|
|
41438
42157
|
var SNAKE_CASE_RE = /^[a-z_][a-z0-9_]*$/;
|
|
@@ -41572,7 +42291,7 @@ class NamingConventionPass {
|
|
|
41572
42291
|
}
|
|
41573
42292
|
}
|
|
41574
42293
|
|
|
41575
|
-
//
|
|
42294
|
+
// ../circle-ir/dist/analysis/passes/security-headers-pass.js
|
|
41576
42295
|
var HEADER_WRITE_METHODS = new Set([
|
|
41577
42296
|
"setHeader",
|
|
41578
42297
|
"addHeader",
|
|
@@ -42033,7 +42752,7 @@ function mapReturnValueToCorsRule(returnValue) {
|
|
|
42033
42752
|
};
|
|
42034
42753
|
}
|
|
42035
42754
|
|
|
42036
|
-
//
|
|
42755
|
+
// ../circle-ir/dist/analysis/passes/_fp-allowlists.js
|
|
42037
42756
|
var PEM_BODY_RE = /[A-Za-z0-9+/]{30,}/;
|
|
42038
42757
|
function pemHasInlineBody(lines, hitLineIdx) {
|
|
42039
42758
|
const end = Math.min(hitLineIdx + 5, lines.length);
|
|
@@ -42060,7 +42779,7 @@ function isProtocolMandatedCryptoFile(file, code) {
|
|
|
42060
42779
|
return false;
|
|
42061
42780
|
}
|
|
42062
42781
|
|
|
42063
|
-
//
|
|
42782
|
+
// ../circle-ir/dist/analysis/passes/scan-secrets-pass.js
|
|
42064
42783
|
function applyDemoDowngrade(demoPath, severity, level) {
|
|
42065
42784
|
if (!demoPath)
|
|
42066
42785
|
return { severity, level };
|
|
@@ -42638,7 +43357,7 @@ class ScanSecretsPass {
|
|
|
42638
43357
|
}
|
|
42639
43358
|
}
|
|
42640
43359
|
|
|
42641
|
-
//
|
|
43360
|
+
// ../circle-ir/dist/analysis/passes/python-receiver-taint-format-pass.js
|
|
42642
43361
|
class PythonReceiverTaintFormatPass {
|
|
42643
43362
|
name = "python-receiver-taint-format";
|
|
42644
43363
|
category = "security";
|
|
@@ -42690,7 +43409,7 @@ class PythonReceiverTaintFormatPass {
|
|
|
42690
43409
|
}
|
|
42691
43410
|
}
|
|
42692
43411
|
|
|
42693
|
-
//
|
|
43412
|
+
// ../circle-ir/dist/analysis/passes/spring4shell-pass.js
|
|
42694
43413
|
var CONTROLLER_ANNOTATIONS = new Set([
|
|
42695
43414
|
"Controller",
|
|
42696
43415
|
"RestController",
|
|
@@ -42898,7 +43617,7 @@ function isPotentialPojo(type) {
|
|
|
42898
43617
|
return first >= 65 && first <= 90;
|
|
42899
43618
|
}
|
|
42900
43619
|
|
|
42901
|
-
//
|
|
43620
|
+
// ../circle-ir/dist/analysis/passes/insecure-cookie-pass.js
|
|
42902
43621
|
var COOKIE_RESPONSE_RECEIVERS = new Set([
|
|
42903
43622
|
"res",
|
|
42904
43623
|
"response",
|
|
@@ -43134,7 +43853,7 @@ class InsecureCookiePass {
|
|
|
43134
43853
|
}
|
|
43135
43854
|
}
|
|
43136
43855
|
|
|
43137
|
-
//
|
|
43856
|
+
// ../circle-ir/dist/analysis/passes/weak-hash-pass.js
|
|
43138
43857
|
var WEAK_HASH_NAMES = new Set([
|
|
43139
43858
|
"md2",
|
|
43140
43859
|
"md4",
|
|
@@ -43354,7 +44073,7 @@ class WeakHashPass {
|
|
|
43354
44073
|
}
|
|
43355
44074
|
}
|
|
43356
44075
|
|
|
43357
|
-
//
|
|
44076
|
+
// ../circle-ir/dist/analysis/path-classification.js
|
|
43358
44077
|
var TEST_PATH_PATTERNS = [
|
|
43359
44078
|
/(^|\/)test\//i,
|
|
43360
44079
|
/(^|\/)tests\//i,
|
|
@@ -43391,7 +44110,7 @@ function isTestPath(filepath) {
|
|
|
43391
44110
|
return false;
|
|
43392
44111
|
}
|
|
43393
44112
|
|
|
43394
|
-
//
|
|
44113
|
+
// ../circle-ir/dist/analysis/passes/weak-crypto-pass.js
|
|
43395
44114
|
var WEAK_CIPHER_BASES = new Set([
|
|
43396
44115
|
"des",
|
|
43397
44116
|
"3des",
|
|
@@ -43896,7 +44615,7 @@ class WeakCryptoPass {
|
|
|
43896
44615
|
}
|
|
43897
44616
|
}
|
|
43898
44617
|
|
|
43899
|
-
//
|
|
44618
|
+
// ../circle-ir/dist/analysis/passes/weak-random-pass.js
|
|
43900
44619
|
var JAVA_RANDOM_METHODS = new Set([
|
|
43901
44620
|
"nextInt",
|
|
43902
44621
|
"nextLong",
|
|
@@ -44069,7 +44788,7 @@ class WeakRandomPass {
|
|
|
44069
44788
|
}
|
|
44070
44789
|
}
|
|
44071
44790
|
|
|
44072
|
-
//
|
|
44791
|
+
// ../circle-ir/dist/analysis/passes/_credential-helpers.js
|
|
44073
44792
|
var CRED_KEYWORD_RE2 = /(?:password|passwd|pwd|secret|api[_-]?key|auth[_-]?token|private[_-]?key|access[_-]?key|credential)/i;
|
|
44074
44793
|
function isCredentialIdentifier(name2) {
|
|
44075
44794
|
if (!name2)
|
|
@@ -44162,7 +44881,7 @@ function priorHashOf(varName, priorCalls) {
|
|
|
44162
44881
|
return false;
|
|
44163
44882
|
}
|
|
44164
44883
|
|
|
44165
|
-
//
|
|
44884
|
+
// ../circle-ir/dist/analysis/passes/weak-password-hash-pass.js
|
|
44166
44885
|
var FAST_HASH_NAMES = new Set([
|
|
44167
44886
|
"sha224",
|
|
44168
44887
|
"sha-224",
|
|
@@ -44321,7 +45040,7 @@ class WeakPasswordHashPass {
|
|
|
44321
45040
|
}
|
|
44322
45041
|
}
|
|
44323
45042
|
|
|
44324
|
-
//
|
|
45043
|
+
// ../circle-ir/dist/analysis/passes/weak-password-encoding-pass.js
|
|
44325
45044
|
function isBasicAuthContext(call, code) {
|
|
44326
45045
|
const line = call.location.line;
|
|
44327
45046
|
if (line < 1)
|
|
@@ -44433,7 +45152,7 @@ class WeakPasswordEncodingPass {
|
|
|
44433
45152
|
}
|
|
44434
45153
|
}
|
|
44435
45154
|
|
|
44436
|
-
//
|
|
45155
|
+
// ../circle-ir/dist/analysis/passes/info-disclosure-stacktrace-pass.js
|
|
44437
45156
|
var RESPONSE_RECEIVER_RE = /^(res|response|w|writer|ctx|c)$/i;
|
|
44438
45157
|
var LOGGER_RECEIVER_RE = /^(log|logger|slog|console|pino|winston|sentry)$/i;
|
|
44439
45158
|
var RESPONSE_SEND_METHODS = new Set([
|
|
@@ -44619,7 +45338,7 @@ class InfoDisclosureStacktracePass {
|
|
|
44619
45338
|
}
|
|
44620
45339
|
}
|
|
44621
45340
|
|
|
44622
|
-
//
|
|
45341
|
+
// ../circle-ir/dist/analysis/passes/unrestricted-file-upload-pass.js
|
|
44623
45342
|
var UPLOAD_NAME_RE = /(?:getOriginalFilename|getSubmittedFileName|originalname|originalName|\.filename|\.Filename|FileHeader\.Filename|UploadFile)/;
|
|
44624
45343
|
var FILE_SAFE_CALL_RE = /(?:secure_filename|FilenameUtils\.getExtension|\.lastIndexOf\(['"]\.['"]\)|ALLOWED_EXT|ALLOWED_EXTENSIONS|allowedExtensions|\bfileFilter\b|filepath\.Ext|path\.extname)/;
|
|
44625
45344
|
function lineWindow(lines, startLine, endLine) {
|
|
@@ -44770,7 +45489,7 @@ class UnrestrictedFileUploadPass {
|
|
|
44770
45489
|
}
|
|
44771
45490
|
}
|
|
44772
45491
|
|
|
44773
|
-
//
|
|
45492
|
+
// ../circle-ir/dist/analysis/passes/missing-sanitizer-gate-pass.js
|
|
44774
45493
|
var HTML_OUTPUT_SINKS = new Set([
|
|
44775
45494
|
"addAttribute",
|
|
44776
45495
|
"setAttribute",
|
|
@@ -44918,7 +45637,7 @@ function methodAcceptsHtmlShapedParam(method) {
|
|
|
44918
45637
|
return false;
|
|
44919
45638
|
}
|
|
44920
45639
|
|
|
44921
|
-
//
|
|
45640
|
+
// ../circle-ir/dist/analysis/passes/insecure-deserialization-config-pass.js
|
|
44922
45641
|
var ANY_TYPE_PERMISSION_RE = /\bAnyTypePermission\b/;
|
|
44923
45642
|
|
|
44924
45643
|
class InsecureDeserializationConfigPass {
|
|
@@ -44996,7 +45715,7 @@ class InsecureDeserializationConfigPass {
|
|
|
44996
45715
|
}
|
|
44997
45716
|
var INSECURE_TYPE_NAME_HANDLING_RE = /\bTypeNameHandling\s*=\s*(?:Newtonsoft\.Json\.)?TypeNameHandling\.(All|Auto|Objects|Arrays)\b/;
|
|
44998
45717
|
|
|
44999
|
-
//
|
|
45718
|
+
// ../circle-ir/dist/analysis/passes/plaintext-password-storage-pass.js
|
|
45000
45719
|
function isWriteStorageCall(call, language) {
|
|
45001
45720
|
const method = call.method_name ?? "";
|
|
45002
45721
|
const receiver = call.receiver ?? "";
|
|
@@ -45107,7 +45826,7 @@ class PlaintextPasswordStoragePass {
|
|
|
45107
45826
|
}
|
|
45108
45827
|
}
|
|
45109
45828
|
|
|
45110
|
-
//
|
|
45829
|
+
// ../circle-ir/dist/analysis/passes/cleartext-credential-transport-pass.js
|
|
45111
45830
|
var LOCALHOST_RE = /^(?:localhost|127\.0\.0\.1|0\.0\.0\.0)(?::\d+)?$/i;
|
|
45112
45831
|
function isInsecureHttpUrl(urlLiteral) {
|
|
45113
45832
|
if (!urlLiteral)
|
|
@@ -45235,7 +45954,7 @@ class CleartextCredentialTransportPass {
|
|
|
45235
45954
|
}
|
|
45236
45955
|
}
|
|
45237
45956
|
|
|
45238
|
-
//
|
|
45957
|
+
// ../circle-ir/dist/analysis/passes/tls-verify-disabled-pass.js
|
|
45239
45958
|
var PY_HTTP_METHODS = new Set([
|
|
45240
45959
|
"get",
|
|
45241
45960
|
"post",
|
|
@@ -45448,7 +46167,7 @@ class TlsVerifyDisabledPass {
|
|
|
45448
46167
|
}
|
|
45449
46168
|
}
|
|
45450
46169
|
|
|
45451
|
-
//
|
|
46170
|
+
// ../circle-ir/dist/analysis/passes/module-side-effect-pass.js
|
|
45452
46171
|
var JS_EXEC_METHODS = new Set([
|
|
45453
46172
|
"exec",
|
|
45454
46173
|
"spawn",
|
|
@@ -45679,7 +46398,7 @@ class ModuleSideEffectPass {
|
|
|
45679
46398
|
}
|
|
45680
46399
|
}
|
|
45681
46400
|
|
|
45682
|
-
//
|
|
46401
|
+
// ../circle-ir/dist/analysis/passes/cache-no-vary-pass.js
|
|
45683
46402
|
function isSharedCacheable(value) {
|
|
45684
46403
|
const v = value.toLowerCase();
|
|
45685
46404
|
if (/\b(private|no-store|no-cache)\b/.test(v))
|
|
@@ -45966,7 +46685,7 @@ class CacheNoVaryPass {
|
|
|
45966
46685
|
}
|
|
45967
46686
|
}
|
|
45968
46687
|
|
|
45969
|
-
//
|
|
46688
|
+
// ../circle-ir/dist/analysis/passes/jwt-verify-disabled-pass.js
|
|
45970
46689
|
var PY_VERIFY_SIGNATURE_FALSE_RE = /["']verify_signature["']\s*:\s*False\b/;
|
|
45971
46690
|
var PY_VERIFY_KW_FALSE_RE = /\bverify\s*=\s*False\b/;
|
|
45972
46691
|
var PY_ALG_NONE_RE = /\balgorithms\s*=\s*[\[\(]\s*["']none["']/i;
|
|
@@ -46091,7 +46810,7 @@ class JwtVerifyDisabledPass {
|
|
|
46091
46810
|
}
|
|
46092
46811
|
}
|
|
46093
46812
|
|
|
46094
|
-
//
|
|
46813
|
+
// ../circle-ir/dist/analysis/passes/csrf-protection-disabled-pass.js
|
|
46095
46814
|
var JAVA_CSRF_DISABLE_RE = /\.csrf\s*\([^)]*\)\s*\.\s*disable\b/;
|
|
46096
46815
|
var JAVA_CSRF_LAMBDA_DISABLE_RE = /\bcsrf\s*\(\s*\w+\s*->\s*\w+\s*\.\s*disable\s*\(/;
|
|
46097
46816
|
var JAVA_CSRF_METHODREF_RE = /\bcsrf\s*\(\s*[\w.]+::disable\s*\)/;
|
|
@@ -46227,7 +46946,7 @@ class CsrfProtectionDisabledPass {
|
|
|
46227
46946
|
}
|
|
46228
46947
|
}
|
|
46229
46948
|
|
|
46230
|
-
//
|
|
46949
|
+
// ../circle-ir/dist/analysis/passes/xml-entity-expansion-pass.js
|
|
46231
46950
|
var JAVA_FACTORIES = new Set([
|
|
46232
46951
|
"SAXParserFactory",
|
|
46233
46952
|
"DocumentBuilderFactory",
|
|
@@ -46367,7 +47086,7 @@ class XmlEntityExpansionPass {
|
|
|
46367
47086
|
}
|
|
46368
47087
|
}
|
|
46369
47088
|
|
|
46370
|
-
//
|
|
47089
|
+
// ../circle-ir/dist/analysis/passes/mass-assignment-pass.js
|
|
46371
47090
|
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
47091
|
var JS_OBJECT_SPREAD_RE = /\{\s*\.\.\.\s*(?:req|request|ctx|context)(?:\.request)?\s*\.\s*(?:body|query|params|form)\b/;
|
|
46373
47092
|
|
|
@@ -46451,7 +47170,7 @@ class MassAssignmentPass {
|
|
|
46451
47170
|
}
|
|
46452
47171
|
}
|
|
46453
47172
|
|
|
46454
|
-
//
|
|
47173
|
+
// ../circle-ir/dist/graph/import-graph.js
|
|
46455
47174
|
function dirname(filePath) {
|
|
46456
47175
|
const idx = filePath.lastIndexOf("/");
|
|
46457
47176
|
return idx >= 0 ? filePath.slice(0, idx) : "";
|
|
@@ -46584,7 +47303,7 @@ class ImportGraph2 {
|
|
|
46584
47303
|
}
|
|
46585
47304
|
}
|
|
46586
47305
|
|
|
46587
|
-
//
|
|
47306
|
+
// ../circle-ir/dist/analysis/passes/circular-dependency-pass.js
|
|
46588
47307
|
class CircularDependencyPass {
|
|
46589
47308
|
run(_projectGraph, importGraph) {
|
|
46590
47309
|
const findings = [];
|
|
@@ -46611,7 +47330,7 @@ class CircularDependencyPass {
|
|
|
46611
47330
|
}
|
|
46612
47331
|
}
|
|
46613
47332
|
|
|
46614
|
-
//
|
|
47333
|
+
// ../circle-ir/dist/analysis/passes/orphan-module-pass.js
|
|
46615
47334
|
class OrphanModulePass {
|
|
46616
47335
|
run(_projectGraph, importGraph) {
|
|
46617
47336
|
const findings = [];
|
|
@@ -46635,7 +47354,7 @@ class OrphanModulePass {
|
|
|
46635
47354
|
}
|
|
46636
47355
|
}
|
|
46637
47356
|
|
|
46638
|
-
//
|
|
47357
|
+
// ../circle-ir/dist/analysis/metrics/passes/size-metrics-pass.js
|
|
46639
47358
|
class SizeMetricsPass {
|
|
46640
47359
|
name = "size-metrics";
|
|
46641
47360
|
run(ctx) {
|
|
@@ -46691,7 +47410,7 @@ class SizeMetricsPass {
|
|
|
46691
47410
|
}
|
|
46692
47411
|
}
|
|
46693
47412
|
|
|
46694
|
-
//
|
|
47413
|
+
// ../circle-ir/dist/analysis/metrics/passes/complexity-metrics-pass.js
|
|
46695
47414
|
class ComplexityMetricsPass {
|
|
46696
47415
|
name = "complexity-metrics";
|
|
46697
47416
|
run(ctx) {
|
|
@@ -46755,7 +47474,7 @@ class ComplexityMetricsPass {
|
|
|
46755
47474
|
}
|
|
46756
47475
|
}
|
|
46757
47476
|
|
|
46758
|
-
//
|
|
47477
|
+
// ../circle-ir/dist/analysis/metrics/passes/halstead-metrics-pass.js
|
|
46759
47478
|
var KEYWORDS = new Set([
|
|
46760
47479
|
"if",
|
|
46761
47480
|
"else",
|
|
@@ -46910,7 +47629,7 @@ class HalsteadMetricsPass {
|
|
|
46910
47629
|
}
|
|
46911
47630
|
}
|
|
46912
47631
|
|
|
46913
|
-
//
|
|
47632
|
+
// ../circle-ir/dist/analysis/metrics/passes/data-flow-metrics-pass.js
|
|
46914
47633
|
class DataFlowMetricsPass {
|
|
46915
47634
|
name = "data-flow-metrics";
|
|
46916
47635
|
run(ctx) {
|
|
@@ -46928,7 +47647,7 @@ class DataFlowMetricsPass {
|
|
|
46928
47647
|
}
|
|
46929
47648
|
}
|
|
46930
47649
|
|
|
46931
|
-
//
|
|
47650
|
+
// ../circle-ir/dist/analysis/metrics/passes/coupling-metrics-pass.js
|
|
46932
47651
|
class CouplingMetricsPass {
|
|
46933
47652
|
name = "coupling-metrics";
|
|
46934
47653
|
run(ctx) {
|
|
@@ -47006,7 +47725,7 @@ class CouplingMetricsPass {
|
|
|
47006
47725
|
}
|
|
47007
47726
|
}
|
|
47008
47727
|
|
|
47009
|
-
//
|
|
47728
|
+
// ../circle-ir/dist/analysis/metrics/passes/inheritance-metrics-pass.js
|
|
47010
47729
|
class InheritanceMetricsPass {
|
|
47011
47730
|
name = "inheritance-metrics";
|
|
47012
47731
|
run(ctx) {
|
|
@@ -47066,7 +47785,7 @@ class InheritanceMetricsPass {
|
|
|
47066
47785
|
}
|
|
47067
47786
|
}
|
|
47068
47787
|
|
|
47069
|
-
//
|
|
47788
|
+
// ../circle-ir/dist/analysis/metrics/passes/cohesion-metrics-pass.js
|
|
47070
47789
|
class CohesionMetricsPass {
|
|
47071
47790
|
name = "cohesion-metrics";
|
|
47072
47791
|
run(ctx) {
|
|
@@ -47149,7 +47868,7 @@ class CohesionMetricsPass {
|
|
|
47149
47868
|
}
|
|
47150
47869
|
}
|
|
47151
47870
|
|
|
47152
|
-
//
|
|
47871
|
+
// ../circle-ir/dist/analysis/metrics/passes/documentation-metrics-pass.js
|
|
47153
47872
|
class DocumentationMetricsPass {
|
|
47154
47873
|
name = "documentation-metrics";
|
|
47155
47874
|
run(ctx) {
|
|
@@ -47202,7 +47921,7 @@ class DocumentationMetricsPass {
|
|
|
47202
47921
|
}
|
|
47203
47922
|
}
|
|
47204
47923
|
|
|
47205
|
-
//
|
|
47924
|
+
// ../circle-ir/dist/analysis/metrics/passes/composite-metrics-pass.js
|
|
47206
47925
|
class CompositeMetricsPass {
|
|
47207
47926
|
name = "composite-metrics";
|
|
47208
47927
|
run(ctx) {
|
|
@@ -47261,7 +47980,7 @@ class CompositeMetricsPass {
|
|
|
47261
47980
|
}
|
|
47262
47981
|
}
|
|
47263
47982
|
|
|
47264
|
-
//
|
|
47983
|
+
// ../circle-ir/dist/analysis/metrics/metric-runner.js
|
|
47265
47984
|
class MetricRunner {
|
|
47266
47985
|
passes = [
|
|
47267
47986
|
new SizeMetricsPass,
|
|
@@ -47283,7 +48002,7 @@ class MetricRunner {
|
|
|
47283
48002
|
return accumulated;
|
|
47284
48003
|
}
|
|
47285
48004
|
}
|
|
47286
|
-
//
|
|
48005
|
+
// ../circle-ir/dist/analyzer.js
|
|
47287
48006
|
var initialized = false;
|
|
47288
48007
|
async function initAnalyzer(options = {}) {
|
|
47289
48008
|
if (initialized)
|
|
@@ -47599,8 +48318,6 @@ async function analyze(code, filePath, language, options = {}) {
|
|
|
47599
48318
|
pipeline.add(new LanguageSourcesPass);
|
|
47600
48319
|
if (!disabledPasses.has("source-semantics"))
|
|
47601
48320
|
pipeline.add(new SourceSemanticsPass);
|
|
47602
|
-
if (!disabledPasses.has("library-profile-source-gate"))
|
|
47603
|
-
pipeline.add(new LibraryProfileSourceGatePass);
|
|
47604
48321
|
if (!disabledPasses.has("mybatis-annotation-sql-sink"))
|
|
47605
48322
|
pipeline.add(new MyBatisAnnotationSqlSinkPass);
|
|
47606
48323
|
pipeline.add(new SinkFilterPass);
|
|
@@ -47617,6 +48334,8 @@ async function analyze(code, filePath, language, options = {}) {
|
|
|
47617
48334
|
pipeline.add(new LibraryProfileSinkGatePass);
|
|
47618
48335
|
if (!disabledPasses.has("library-profile-xss-gate"))
|
|
47619
48336
|
pipeline.add(new LibraryProfileXssGatePass);
|
|
48337
|
+
if (!disabledPasses.has("library-profile-source-gate"))
|
|
48338
|
+
pipeline.add(new LibraryProfileSourceGatePass);
|
|
47620
48339
|
pipeline.add(new TaintPropagationPass);
|
|
47621
48340
|
pipeline.add(new InterproceduralPass({
|
|
47622
48341
|
enableEntryPointGate: options.enableEntryPointGate ?? true
|
|
@@ -47880,7 +48599,19 @@ async function analyzeProject(files, options = {}) {
|
|
|
47880
48599
|
const fileAnalyses = [];
|
|
47881
48600
|
const projectGraph = new ProjectGraph;
|
|
47882
48601
|
const sourceLinesByFile = new Map;
|
|
48602
|
+
const perFileBudgetMs = options.perFileBudgetMs ?? 0;
|
|
48603
|
+
const perFileStart = Date.now();
|
|
48604
|
+
let perFileBudgetExceeded = false;
|
|
47883
48605
|
for (const { code, filePath, language } of files) {
|
|
48606
|
+
if (perFileBudgetMs > 0 && Date.now() - perFileStart > perFileBudgetMs) {
|
|
48607
|
+
perFileBudgetExceeded = true;
|
|
48608
|
+
logger.warn("analyzeProject: per-file budget exceeded, skipping remaining files", {
|
|
48609
|
+
analysed: fileAnalyses.length,
|
|
48610
|
+
total: files.length,
|
|
48611
|
+
budgetMs: perFileBudgetMs
|
|
48612
|
+
});
|
|
48613
|
+
break;
|
|
48614
|
+
}
|
|
47884
48615
|
const ir = await analyze(code, filePath, language, options);
|
|
47885
48616
|
fileAnalyses.push({ file: filePath, analysis: ir });
|
|
47886
48617
|
projectGraph.addFile(filePath, new CodeGraph(ir));
|
|
@@ -47936,6 +48667,9 @@ async function analyzeProject(files, options = {}) {
|
|
|
47936
48667
|
if (crossFileResult.budgetExceeded) {
|
|
47937
48668
|
projectAnalysis.cross_file_budget_exceeded = true;
|
|
47938
48669
|
}
|
|
48670
|
+
if (perFileBudgetExceeded) {
|
|
48671
|
+
projectAnalysis.per_file_budget_exceeded = true;
|
|
48672
|
+
}
|
|
47939
48673
|
return projectAnalysis;
|
|
47940
48674
|
}
|
|
47941
48675
|
function deriveProjectName(paths) {
|
|
@@ -47955,7 +48689,7 @@ function deriveProjectRoot(paths) {
|
|
|
47955
48689
|
}
|
|
47956
48690
|
return common.join("/") || "/";
|
|
47957
48691
|
}
|
|
47958
|
-
//
|
|
48692
|
+
// ../circle-ir/dist/analysis/sbom.js
|
|
47959
48693
|
function purlVersion(spec) {
|
|
47960
48694
|
const stripped = spec.trim().replace(/^[\s^~=<>]+/, "");
|
|
47961
48695
|
if (/^v?[0-9][\w.\-+]*$/.test(stripped))
|
|
@@ -49011,7 +49745,7 @@ var colors = {
|
|
|
49011
49745
|
};
|
|
49012
49746
|
|
|
49013
49747
|
// src/version.ts
|
|
49014
|
-
var version = "4.9.
|
|
49748
|
+
var version = "4.9.19";
|
|
49015
49749
|
|
|
49016
49750
|
// src/formatters.ts
|
|
49017
49751
|
var LIBRARY_API_SURFACE_TAG2 = "library-api-surface:caller-responsibility";
|
|
@@ -49564,8 +50298,8 @@ function generateSarifResults(results, crossFileData) {
|
|
|
49564
50298
|
|
|
49565
50299
|
// src/build-info.ts
|
|
49566
50300
|
var buildInfo = {
|
|
49567
|
-
gitSha: "
|
|
49568
|
-
builtAt: "2026-09-
|
|
50301
|
+
gitSha: "edf0335",
|
|
50302
|
+
builtAt: "2026-09-19T15:34:15.780Z"
|
|
49569
50303
|
};
|
|
49570
50304
|
|
|
49571
50305
|
// src/utils/args.ts
|