cognium-dev 3.152.0 → 3.154.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +664 -252
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -10611,10 +10611,6 @@ var DEFAULT_SINKS = [
|
|
|
10611
10611
|
{ method: "FileOutputStream", class: "constructor", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
|
|
10612
10612
|
{ method: "FileReader", class: "constructor", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
|
|
10613
10613
|
{ method: "FileWriter", class: "constructor", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
|
|
10614
|
-
{ method: "getResource", class: "ClassLoader", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
|
|
10615
|
-
{ method: "getResourceAsStream", class: "ClassLoader", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
|
|
10616
|
-
{ method: "getResource", class: "Class", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
|
|
10617
|
-
{ method: "getResourceAsStream", class: "Class", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
|
|
10618
10614
|
{ method: "get", class: "Paths", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
|
|
10619
10615
|
{ method: "of", class: "Path", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
|
|
10620
10616
|
{ method: "readAllBytes", class: "Files", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
|
|
@@ -10627,9 +10623,6 @@ var DEFAULT_SINKS = [
|
|
|
10627
10623
|
{ method: "newBufferedWriter", class: "Files", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
|
|
10628
10624
|
{ method: "copy", class: "Files", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0, 1] },
|
|
10629
10625
|
{ method: "move", class: "Files", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0, 1] },
|
|
10630
|
-
{ method: "exists", class: "Files", type: "path_traversal", cwe: "CWE-22", severity: "medium", arg_positions: [0] },
|
|
10631
|
-
{ method: "isDirectory", class: "Files", type: "path_traversal", cwe: "CWE-22", severity: "medium", arg_positions: [0] },
|
|
10632
|
-
{ method: "isRegularFile", class: "Files", type: "path_traversal", cwe: "CWE-22", severity: "medium", arg_positions: [0] },
|
|
10633
10626
|
{ method: "RandomAccessFile", class: "constructor", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
|
|
10634
10627
|
{ method: "resolveURI", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
|
|
10635
10628
|
{ method: "resolve", class: "SourceResolver", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
|
|
@@ -10968,6 +10961,9 @@ var DEFAULT_SINKS = [
|
|
|
10968
10961
|
{ method: "parseObject", class: "JSON", type: "deserialization", cwe: "CWE-502", severity: "high", arg_positions: [0], safe_if_class_literal_at: 1 },
|
|
10969
10962
|
{ method: "parseObject", class: "JSONObject", type: "deserialization", cwe: "CWE-502", severity: "high", arg_positions: [0], safe_if_class_literal_at: 1 },
|
|
10970
10963
|
{ method: "fromJson", class: "Gson", type: "deserialization", cwe: "CWE-502", severity: "medium", arg_positions: [0], safe_if_class_literal_at: 1 },
|
|
10964
|
+
{ method: "readValue", class: "ObjectReader", type: "deserialization", cwe: "CWE-502", severity: "high", arg_positions: [0], safe_if_class_literal_at: 1 },
|
|
10965
|
+
{ method: "convertValue", class: "ObjectMapper", type: "deserialization", cwe: "CWE-502", severity: "medium", arg_positions: [0], safe_if_class_literal_at: 1 },
|
|
10966
|
+
{ method: "readObject", class: "Kryo", type: "deserialization", cwe: "CWE-502", severity: "high", arg_positions: [0], safe_if_class_literal_at: 1 },
|
|
10971
10967
|
{ method: "readObject", class: "XMLDecoder", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [] },
|
|
10972
10968
|
{ method: "ObjectInputStream", class: "constructor", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0] },
|
|
10973
10969
|
{ method: "search", class: "DirContext", type: "ldap_injection", cwe: "CWE-90", severity: "high", arg_positions: [0, 1] },
|
|
@@ -12455,7 +12451,21 @@ function argIsClassLiteral(call, position) {
|
|
|
12455
12451
|
const expr = (arg.literal ?? arg.expression ?? "").trim();
|
|
12456
12452
|
if (!expr)
|
|
12457
12453
|
return false;
|
|
12458
|
-
|
|
12454
|
+
if (CLASS_LITERAL_RE.test(expr))
|
|
12455
|
+
return true;
|
|
12456
|
+
return TYPE_TOKEN_RE.test(expr);
|
|
12457
|
+
}
|
|
12458
|
+
var TYPE_TOKEN_RE = /^new\s+(?:TypeReference|TypeToken)\s*<[\s\S]*>\s*\(\s*\)\s*\{\s*\}$/;
|
|
12459
|
+
function argIsStringLiteral(call, position) {
|
|
12460
|
+
const arg = call.arguments.find((a) => a.position === position);
|
|
12461
|
+
if (!arg)
|
|
12462
|
+
return false;
|
|
12463
|
+
if (arg.literal !== undefined && arg.literal !== null && arg.literal !== "")
|
|
12464
|
+
return true;
|
|
12465
|
+
const expr = (arg.expression ?? "").trim();
|
|
12466
|
+
if (!expr)
|
|
12467
|
+
return false;
|
|
12468
|
+
return expr.startsWith('"') && expr.endsWith('"') && expr.length >= 2 || expr.startsWith("'") && expr.endsWith("'") && expr.length >= 2 || expr.startsWith('"""') && expr.endsWith('"""');
|
|
12459
12469
|
}
|
|
12460
12470
|
var CWE_78_RECEIVER_ALLOWLIST = new Set([
|
|
12461
12471
|
"Runtime",
|
|
@@ -12649,6 +12659,9 @@ function findSinks(calls, patterns, typeHierarchy, language, sourceLines) {
|
|
|
12649
12659
|
if (pattern.safe_if_class_literal_at !== undefined && argIsClassLiteral(call, pattern.safe_if_class_literal_at)) {
|
|
12650
12660
|
continue;
|
|
12651
12661
|
}
|
|
12662
|
+
if (pattern.safe_if_string_literal_at !== undefined && argIsStringLiteral(call, pattern.safe_if_string_literal_at)) {
|
|
12663
|
+
continue;
|
|
12664
|
+
}
|
|
12652
12665
|
if (pattern.type === "command_injection") {
|
|
12653
12666
|
if (call.is_constructor) {
|
|
12654
12667
|
if (!CWE_78_RECEIVER_ALLOWLIST.has(call.method_name)) {
|
|
@@ -18460,6 +18473,470 @@ function applyLibraryApiSurfaceDowngrade(findings) {
|
|
|
18460
18473
|
});
|
|
18461
18474
|
}
|
|
18462
18475
|
|
|
18476
|
+
// ../circle-ir/dist/analysis/entry-point-detection.js
|
|
18477
|
+
var TIER_1_METHOD_ANNOTATIONS = new Set([
|
|
18478
|
+
"RequestMapping",
|
|
18479
|
+
"GetMapping",
|
|
18480
|
+
"PostMapping",
|
|
18481
|
+
"PutMapping",
|
|
18482
|
+
"DeleteMapping",
|
|
18483
|
+
"PatchMapping",
|
|
18484
|
+
"MessageMapping",
|
|
18485
|
+
"SubscribeMapping",
|
|
18486
|
+
"KafkaListener",
|
|
18487
|
+
"KafkaHandler",
|
|
18488
|
+
"RabbitListener",
|
|
18489
|
+
"RabbitHandler",
|
|
18490
|
+
"JmsListener",
|
|
18491
|
+
"StreamListener",
|
|
18492
|
+
"SqsListener",
|
|
18493
|
+
"SqsHandler",
|
|
18494
|
+
"EventListener",
|
|
18495
|
+
"Scheduled",
|
|
18496
|
+
"Path",
|
|
18497
|
+
"GET",
|
|
18498
|
+
"POST",
|
|
18499
|
+
"PUT",
|
|
18500
|
+
"DELETE",
|
|
18501
|
+
"PATCH",
|
|
18502
|
+
"HEAD",
|
|
18503
|
+
"OPTIONS",
|
|
18504
|
+
"DataBoundConstructor",
|
|
18505
|
+
"DataBoundSetter"
|
|
18506
|
+
]);
|
|
18507
|
+
var TIER_1_CLASS_ANNOTATIONS = new Set([
|
|
18508
|
+
"RestController",
|
|
18509
|
+
"Controller",
|
|
18510
|
+
"Service",
|
|
18511
|
+
"Repository",
|
|
18512
|
+
"Component",
|
|
18513
|
+
"Path",
|
|
18514
|
+
"WebServlet",
|
|
18515
|
+
"ServerEndpoint",
|
|
18516
|
+
"FeignClient"
|
|
18517
|
+
]);
|
|
18518
|
+
var TIER_1_BY_SUPERTYPE = new Map([
|
|
18519
|
+
["HttpServlet", new Set(["doGet", "doPost", "doPut", "doDelete", "doHead", "doOptions", "doTrace", "service"])],
|
|
18520
|
+
["GenericServlet", new Set(["service"])],
|
|
18521
|
+
["Filter", new Set(["doFilter"])],
|
|
18522
|
+
["HandlerInterceptor", new Set(["preHandle", "postHandle", "afterCompletion"])],
|
|
18523
|
+
["AsyncHandlerInterceptor", new Set(["preHandle", "postHandle", "afterCompletion", "afterConcurrentHandlingStarted"])],
|
|
18524
|
+
["CommandLineRunner", new Set(["run"])],
|
|
18525
|
+
["ApplicationRunner", new Set(["run"])],
|
|
18526
|
+
["SimpleChannelInboundHandler", new Set(["channelRead0", "messageReceived"])],
|
|
18527
|
+
["ChannelInboundHandler", new Set(["channelRead", "channelReadComplete"])],
|
|
18528
|
+
["ChannelInboundHandlerAdapter", new Set(["channelRead", "channelReadComplete"])],
|
|
18529
|
+
["ChannelDuplexHandler", new Set(["channelRead", "channelReadComplete"])],
|
|
18530
|
+
["NettyRequestProcessor", new Set(["process"])],
|
|
18531
|
+
["Converter", new Set(["marshal", "unmarshal"])],
|
|
18532
|
+
["SingleValueConverter", new Set(["fromString", "toString"])],
|
|
18533
|
+
["ConverterMatcher", new Set(["marshal", "unmarshal"])],
|
|
18534
|
+
["AbstractReflectionConverter", new Set(["marshal", "unmarshal", "doMarshal", "doUnmarshal"])],
|
|
18535
|
+
["AbstractSingleValueConverter", new Set(["fromString", "toString"])],
|
|
18536
|
+
["AbstractCollectionConverter", new Set(["marshal", "unmarshal"])]
|
|
18537
|
+
]);
|
|
18538
|
+
var TIER_3_CLASS_SUFFIXES = [
|
|
18539
|
+
"Util",
|
|
18540
|
+
"Utils",
|
|
18541
|
+
"Helper",
|
|
18542
|
+
"Helpers"
|
|
18543
|
+
];
|
|
18544
|
+
var TIER_3_PACKAGE_FRAGMENTS = [
|
|
18545
|
+
".template.",
|
|
18546
|
+
".templates.",
|
|
18547
|
+
".engine.",
|
|
18548
|
+
".engines."
|
|
18549
|
+
];
|
|
18550
|
+
var TIER_3_JDK_FACADE_INTERFACES = new Set([
|
|
18551
|
+
"Collection",
|
|
18552
|
+
"List",
|
|
18553
|
+
"Set",
|
|
18554
|
+
"Map",
|
|
18555
|
+
"Queue",
|
|
18556
|
+
"Deque",
|
|
18557
|
+
"SortedSet",
|
|
18558
|
+
"SortedMap",
|
|
18559
|
+
"NavigableSet",
|
|
18560
|
+
"NavigableMap",
|
|
18561
|
+
"Iterator",
|
|
18562
|
+
"Iterable",
|
|
18563
|
+
"ListIterator",
|
|
18564
|
+
"Comparator",
|
|
18565
|
+
"Comparable",
|
|
18566
|
+
"Serializable",
|
|
18567
|
+
"Externalizable",
|
|
18568
|
+
"Cloneable"
|
|
18569
|
+
]);
|
|
18570
|
+
function classNameLooksLikeUtility(name2) {
|
|
18571
|
+
if (!name2)
|
|
18572
|
+
return false;
|
|
18573
|
+
for (const suffix of TIER_3_CLASS_SUFFIXES) {
|
|
18574
|
+
if (name2.length > suffix.length && name2.endsWith(suffix))
|
|
18575
|
+
return true;
|
|
18576
|
+
}
|
|
18577
|
+
return false;
|
|
18578
|
+
}
|
|
18579
|
+
function packageLooksLikeTemplateOrEngine(pkg) {
|
|
18580
|
+
if (!pkg)
|
|
18581
|
+
return false;
|
|
18582
|
+
const padded = `.${pkg}.`;
|
|
18583
|
+
for (const frag of TIER_3_PACKAGE_FRAGMENTS) {
|
|
18584
|
+
if (padded.includes(frag))
|
|
18585
|
+
return true;
|
|
18586
|
+
}
|
|
18587
|
+
return false;
|
|
18588
|
+
}
|
|
18589
|
+
function implementsJdkFacade(t) {
|
|
18590
|
+
if (!t)
|
|
18591
|
+
return false;
|
|
18592
|
+
for (const impl of t.implements ?? []) {
|
|
18593
|
+
if (TIER_3_JDK_FACADE_INTERFACES.has(simpleTypeName(impl)))
|
|
18594
|
+
return true;
|
|
18595
|
+
}
|
|
18596
|
+
return false;
|
|
18597
|
+
}
|
|
18598
|
+
function classShapeIsLibraryFacade(enclosingType) {
|
|
18599
|
+
if (!enclosingType)
|
|
18600
|
+
return false;
|
|
18601
|
+
if (classNameLooksLikeUtility(enclosingType.name))
|
|
18602
|
+
return true;
|
|
18603
|
+
if (packageLooksLikeTemplateOrEngine(enclosingType.package))
|
|
18604
|
+
return true;
|
|
18605
|
+
if (implementsJdkFacade(enclosingType))
|
|
18606
|
+
return true;
|
|
18607
|
+
return false;
|
|
18608
|
+
}
|
|
18609
|
+
function annotationsInclude(annotations, targets) {
|
|
18610
|
+
if (!annotations || annotations.length === 0)
|
|
18611
|
+
return false;
|
|
18612
|
+
for (const raw of annotations) {
|
|
18613
|
+
const simple = raw.replace(/^@/, "").replace(/[<(].*$/, "").trim();
|
|
18614
|
+
if (targets.has(simple))
|
|
18615
|
+
return true;
|
|
18616
|
+
}
|
|
18617
|
+
return false;
|
|
18618
|
+
}
|
|
18619
|
+
function simpleTypeName(ref) {
|
|
18620
|
+
return ref.replace(/<.*$/, "").trim();
|
|
18621
|
+
}
|
|
18622
|
+
function looksLikeMainMethod(method) {
|
|
18623
|
+
if (method.name !== "main")
|
|
18624
|
+
return false;
|
|
18625
|
+
const params = method.parameters ?? [];
|
|
18626
|
+
if (params.length !== 1)
|
|
18627
|
+
return false;
|
|
18628
|
+
const t = (params[0].type ?? "").replace(/\s+/g, "");
|
|
18629
|
+
return t === "String[]" || t === "String..." || t === "java.lang.String[]";
|
|
18630
|
+
}
|
|
18631
|
+
function methodIsSupertypeLifecycleEntryPoint(method, enclosingType) {
|
|
18632
|
+
if (!method.name)
|
|
18633
|
+
return false;
|
|
18634
|
+
if (!enclosingType)
|
|
18635
|
+
return false;
|
|
18636
|
+
const candidates = [];
|
|
18637
|
+
if (enclosingType.extends)
|
|
18638
|
+
candidates.push(simpleTypeName(enclosingType.extends));
|
|
18639
|
+
for (const i2 of enclosingType.implements ?? [])
|
|
18640
|
+
candidates.push(simpleTypeName(i2));
|
|
18641
|
+
for (const supertype of candidates) {
|
|
18642
|
+
const lifecycleMethods = TIER_1_BY_SUPERTYPE.get(supertype);
|
|
18643
|
+
if (lifecycleMethods?.has(method.name))
|
|
18644
|
+
return true;
|
|
18645
|
+
}
|
|
18646
|
+
return false;
|
|
18647
|
+
}
|
|
18648
|
+
function classifyEntryPointTier(method, enclosingType, ctx) {
|
|
18649
|
+
const language = (ctx.language ?? "").toLowerCase();
|
|
18650
|
+
if (language !== "java")
|
|
18651
|
+
return "TIER_UNKNOWN";
|
|
18652
|
+
if (!method)
|
|
18653
|
+
return "TIER_UNKNOWN";
|
|
18654
|
+
if (classShapeIsLibraryFacade(enclosingType)) {
|
|
18655
|
+
return "TIER_3_LIBRARY_API";
|
|
18656
|
+
}
|
|
18657
|
+
if (annotationsInclude(method.annotations, TIER_1_METHOD_ANNOTATIONS)) {
|
|
18658
|
+
return "TIER_1_ENTRY_POINT";
|
|
18659
|
+
}
|
|
18660
|
+
if (enclosingType && annotationsInclude(enclosingType.annotations, TIER_1_CLASS_ANNOTATIONS)) {
|
|
18661
|
+
return "TIER_1_ENTRY_POINT";
|
|
18662
|
+
}
|
|
18663
|
+
if (methodIsSupertypeLifecycleEntryPoint(method, enclosingType)) {
|
|
18664
|
+
return "TIER_1_ENTRY_POINT";
|
|
18665
|
+
}
|
|
18666
|
+
if (looksLikeMainMethod(method)) {
|
|
18667
|
+
return "TIER_1_ENTRY_POINT";
|
|
18668
|
+
}
|
|
18669
|
+
return "TIER_3_LIBRARY_API";
|
|
18670
|
+
}
|
|
18671
|
+
function shouldGateInterproceduralParam(sourceType, enclosingMethod, enclosingType, ctx) {
|
|
18672
|
+
if (sourceType !== "interprocedural_param")
|
|
18673
|
+
return false;
|
|
18674
|
+
if (!enclosingMethod)
|
|
18675
|
+
return false;
|
|
18676
|
+
const tier = classifyEntryPointTier(enclosingMethod, enclosingType, ctx);
|
|
18677
|
+
return tier === "TIER_3_LIBRARY_API";
|
|
18678
|
+
}
|
|
18679
|
+
|
|
18680
|
+
// ../circle-ir/dist/analysis/require-entry-path.js
|
|
18681
|
+
var RULE_ID_REQUIRE_ENTRY_PATH = "require-entry-path";
|
|
18682
|
+
var MAX_VISITED_METHODS = 2000;
|
|
18683
|
+
function applyRequireEntryPath(fileAnalyses, options = {}) {
|
|
18684
|
+
const disabledSet = normalizeDisabled(options.disabledPasses);
|
|
18685
|
+
if (disabledSet.has(RULE_ID_REQUIRE_ENTRY_PATH))
|
|
18686
|
+
return;
|
|
18687
|
+
const graph = buildProjectMethodGraph(fileAnalyses);
|
|
18688
|
+
if (graph.methodsByKey.size === 0)
|
|
18689
|
+
return;
|
|
18690
|
+
const entryPointKeys = collectEntryPointKeys(graph);
|
|
18691
|
+
const profileResolver = makeProfileResolver(options.projectProfile);
|
|
18692
|
+
for (const fa of fileAnalyses) {
|
|
18693
|
+
const findings = fa.analysis.findings;
|
|
18694
|
+
if (!findings || findings.length === 0)
|
|
18695
|
+
continue;
|
|
18696
|
+
const kept = [];
|
|
18697
|
+
for (const finding of findings) {
|
|
18698
|
+
const decision = classifyFinding(finding, fa.analysis, graph, entryPointKeys, profileResolver(fa.file));
|
|
18699
|
+
switch (decision.action) {
|
|
18700
|
+
case "keep":
|
|
18701
|
+
kept.push(finding);
|
|
18702
|
+
break;
|
|
18703
|
+
case "annotate":
|
|
18704
|
+
kept.push({
|
|
18705
|
+
...finding,
|
|
18706
|
+
entryPath: decision.entryPath,
|
|
18707
|
+
entryPathTier: decision.tier
|
|
18708
|
+
});
|
|
18709
|
+
break;
|
|
18710
|
+
case "drop":
|
|
18711
|
+
break;
|
|
18712
|
+
}
|
|
18713
|
+
}
|
|
18714
|
+
fa.analysis.findings = kept.length > 0 ? kept : undefined;
|
|
18715
|
+
}
|
|
18716
|
+
}
|
|
18717
|
+
function buildProjectMethodGraph(fileAnalyses) {
|
|
18718
|
+
const methodsByKey = new Map;
|
|
18719
|
+
const methodsByName = new Map;
|
|
18720
|
+
const callersOf = new Map;
|
|
18721
|
+
for (const fa of fileAnalyses) {
|
|
18722
|
+
const language = (fa.analysis.meta.language ?? "").toLowerCase();
|
|
18723
|
+
for (const type of fa.analysis.types ?? []) {
|
|
18724
|
+
for (const method of type.methods ?? []) {
|
|
18725
|
+
const key = makeMethodKey(fa.file, type.name, method.name, method.start_line);
|
|
18726
|
+
methodsByKey.set(key, {
|
|
18727
|
+
key,
|
|
18728
|
+
file: fa.file,
|
|
18729
|
+
className: type.name,
|
|
18730
|
+
method,
|
|
18731
|
+
enclosingType: type,
|
|
18732
|
+
language
|
|
18733
|
+
});
|
|
18734
|
+
const bucket = methodsByName.get(method.name);
|
|
18735
|
+
if (bucket)
|
|
18736
|
+
bucket.push(key);
|
|
18737
|
+
else
|
|
18738
|
+
methodsByName.set(method.name, [key]);
|
|
18739
|
+
}
|
|
18740
|
+
}
|
|
18741
|
+
}
|
|
18742
|
+
for (const fa of fileAnalyses) {
|
|
18743
|
+
const calls = fa.analysis.calls ?? [];
|
|
18744
|
+
for (const call of calls) {
|
|
18745
|
+
if (!call.in_method)
|
|
18746
|
+
continue;
|
|
18747
|
+
const callerKey = resolveCallerKey(fa, call.in_method, call.location.line);
|
|
18748
|
+
if (!callerKey)
|
|
18749
|
+
continue;
|
|
18750
|
+
const calleeKeys = resolveCalleeKeys(call, methodsByKey, methodsByName);
|
|
18751
|
+
if (calleeKeys.length === 0)
|
|
18752
|
+
continue;
|
|
18753
|
+
const code = call.receiver ? `${call.receiver}.${call.method_name}(...)` : `${call.method_name}(...)`;
|
|
18754
|
+
for (const calleeKey of calleeKeys) {
|
|
18755
|
+
const edge = {
|
|
18756
|
+
callerKey,
|
|
18757
|
+
calleeKey,
|
|
18758
|
+
callSiteLine: call.location.line,
|
|
18759
|
+
code
|
|
18760
|
+
};
|
|
18761
|
+
const bucket = callersOf.get(calleeKey);
|
|
18762
|
+
if (bucket)
|
|
18763
|
+
bucket.push(edge);
|
|
18764
|
+
else
|
|
18765
|
+
callersOf.set(calleeKey, [edge]);
|
|
18766
|
+
}
|
|
18767
|
+
}
|
|
18768
|
+
}
|
|
18769
|
+
return { methodsByKey, methodsByName, callersOf };
|
|
18770
|
+
}
|
|
18771
|
+
function makeMethodKey(file, className, methodName, startLine) {
|
|
18772
|
+
return `${file}|${className}#${methodName}@${startLine}`;
|
|
18773
|
+
}
|
|
18774
|
+
function resolveCallerKey(fa, inMethod, callLine) {
|
|
18775
|
+
for (const type of fa.analysis.types ?? []) {
|
|
18776
|
+
for (const method of type.methods ?? []) {
|
|
18777
|
+
if (method.name !== inMethod)
|
|
18778
|
+
continue;
|
|
18779
|
+
if (callLine >= method.start_line && callLine <= method.end_line) {
|
|
18780
|
+
return makeMethodKey(fa.file, type.name, method.name, method.start_line);
|
|
18781
|
+
}
|
|
18782
|
+
}
|
|
18783
|
+
}
|
|
18784
|
+
return null;
|
|
18785
|
+
}
|
|
18786
|
+
function resolveCalleeKeys(call, methodsByKey, methodsByName) {
|
|
18787
|
+
const candidates = methodsByName.get(call.method_name);
|
|
18788
|
+
if (!candidates || candidates.length === 0)
|
|
18789
|
+
return [];
|
|
18790
|
+
if (call.receiver_type) {
|
|
18791
|
+
const simple = call.receiver_type.replace(/<.*$/, "").trim();
|
|
18792
|
+
const matches = [];
|
|
18793
|
+
for (const key of candidates) {
|
|
18794
|
+
const rec = methodsByKey.get(key);
|
|
18795
|
+
if (rec?.className === simple)
|
|
18796
|
+
matches.push(key);
|
|
18797
|
+
}
|
|
18798
|
+
if (matches.length > 0)
|
|
18799
|
+
return matches;
|
|
18800
|
+
}
|
|
18801
|
+
return candidates;
|
|
18802
|
+
}
|
|
18803
|
+
function collectEntryPointKeys(graph) {
|
|
18804
|
+
const entryPoints = new Set;
|
|
18805
|
+
for (const rec of graph.methodsByKey.values()) {
|
|
18806
|
+
const tier = classifyEntryPointTier(rec.method, rec.enclosingType, {
|
|
18807
|
+
types: [rec.enclosingType],
|
|
18808
|
+
language: rec.language
|
|
18809
|
+
});
|
|
18810
|
+
if (tier === "TIER_1_ENTRY_POINT")
|
|
18811
|
+
entryPoints.add(rec.key);
|
|
18812
|
+
}
|
|
18813
|
+
return entryPoints;
|
|
18814
|
+
}
|
|
18815
|
+
function classifyFinding(finding, ir, graph, entryPointKeys, profile) {
|
|
18816
|
+
if (finding.category !== "security")
|
|
18817
|
+
return { action: "keep" };
|
|
18818
|
+
const isHighOrCritical = finding.severity === "high" || finding.severity === "critical";
|
|
18819
|
+
const language = (ir.meta.language ?? "").toLowerCase();
|
|
18820
|
+
if (language !== "java")
|
|
18821
|
+
return { action: "keep" };
|
|
18822
|
+
const containing = findContainingMethod(finding, ir, graph);
|
|
18823
|
+
if (!containing) {
|
|
18824
|
+
return { action: "keep" };
|
|
18825
|
+
}
|
|
18826
|
+
const bfs = reverseBfsToEntryPoint(containing.key, graph, entryPointKeys);
|
|
18827
|
+
if (bfs.status === "hit") {
|
|
18828
|
+
const entryPath = reconstructPath(bfs.entryKey, containing.key, bfs.parent, graph, finding);
|
|
18829
|
+
return {
|
|
18830
|
+
action: "annotate",
|
|
18831
|
+
entryPath,
|
|
18832
|
+
tier: "tier1-entry-point"
|
|
18833
|
+
};
|
|
18834
|
+
}
|
|
18835
|
+
if (bfs.status === "budget") {
|
|
18836
|
+
return { action: "keep" };
|
|
18837
|
+
}
|
|
18838
|
+
if (!isHighOrCritical)
|
|
18839
|
+
return { action: "keep" };
|
|
18840
|
+
if (!shouldDropUnderProfile(profile))
|
|
18841
|
+
return { action: "keep" };
|
|
18842
|
+
return { action: "drop" };
|
|
18843
|
+
}
|
|
18844
|
+
function findContainingMethod(finding, ir, graph) {
|
|
18845
|
+
const line = finding.line;
|
|
18846
|
+
for (const type of ir.types ?? []) {
|
|
18847
|
+
for (const method of type.methods ?? []) {
|
|
18848
|
+
if (line >= method.start_line && line <= method.end_line) {
|
|
18849
|
+
const key = makeMethodKey(finding.file, type.name, method.name, method.start_line);
|
|
18850
|
+
const rec = graph.methodsByKey.get(key);
|
|
18851
|
+
if (rec)
|
|
18852
|
+
return rec;
|
|
18853
|
+
}
|
|
18854
|
+
}
|
|
18855
|
+
}
|
|
18856
|
+
return null;
|
|
18857
|
+
}
|
|
18858
|
+
function reverseBfsToEntryPoint(startKey, graph, entryPointKeys) {
|
|
18859
|
+
const parent = new Map;
|
|
18860
|
+
const visited = new Set([startKey]);
|
|
18861
|
+
const queue = [startKey];
|
|
18862
|
+
if (entryPointKeys.has(startKey)) {
|
|
18863
|
+
return { status: "hit", entryKey: startKey, parent };
|
|
18864
|
+
}
|
|
18865
|
+
while (queue.length > 0) {
|
|
18866
|
+
if (visited.size > MAX_VISITED_METHODS) {
|
|
18867
|
+
return { status: "budget", entryKey: null, parent };
|
|
18868
|
+
}
|
|
18869
|
+
const current = queue.shift();
|
|
18870
|
+
const incoming = graph.callersOf.get(current) ?? [];
|
|
18871
|
+
incoming.sort((a, b) => a.callerKey.localeCompare(b.callerKey));
|
|
18872
|
+
for (const edge of incoming) {
|
|
18873
|
+
if (visited.has(edge.callerKey))
|
|
18874
|
+
continue;
|
|
18875
|
+
visited.add(edge.callerKey);
|
|
18876
|
+
parent.set(edge.callerKey, edge);
|
|
18877
|
+
if (entryPointKeys.has(edge.callerKey)) {
|
|
18878
|
+
return { status: "hit", entryKey: edge.callerKey, parent };
|
|
18879
|
+
}
|
|
18880
|
+
queue.push(edge.callerKey);
|
|
18881
|
+
}
|
|
18882
|
+
}
|
|
18883
|
+
return { status: "miss", entryKey: null, parent };
|
|
18884
|
+
}
|
|
18885
|
+
function reconstructPath(entryKey, sinkKey, parent, graph, finding) {
|
|
18886
|
+
const hops = [];
|
|
18887
|
+
let cursor = entryKey;
|
|
18888
|
+
const guard = new Set;
|
|
18889
|
+
while (cursor !== sinkKey) {
|
|
18890
|
+
if (guard.has(cursor))
|
|
18891
|
+
break;
|
|
18892
|
+
guard.add(cursor);
|
|
18893
|
+
const rec = graph.methodsByKey.get(cursor);
|
|
18894
|
+
const edge = parent.get(cursor);
|
|
18895
|
+
if (!rec || !edge)
|
|
18896
|
+
break;
|
|
18897
|
+
hops.push({
|
|
18898
|
+
file: rec.file,
|
|
18899
|
+
method: `${rec.className}.${rec.method.name}`,
|
|
18900
|
+
line: edge.callSiteLine,
|
|
18901
|
+
code: edge.code,
|
|
18902
|
+
variable: ""
|
|
18903
|
+
});
|
|
18904
|
+
cursor = edge.calleeKey;
|
|
18905
|
+
}
|
|
18906
|
+
const sinkRec = graph.methodsByKey.get(sinkKey);
|
|
18907
|
+
if (sinkRec) {
|
|
18908
|
+
hops.push({
|
|
18909
|
+
file: sinkRec.file,
|
|
18910
|
+
method: `${sinkRec.className}.${sinkRec.method.name}`,
|
|
18911
|
+
line: finding.line,
|
|
18912
|
+
code: finding.message,
|
|
18913
|
+
variable: ""
|
|
18914
|
+
});
|
|
18915
|
+
}
|
|
18916
|
+
return hops;
|
|
18917
|
+
}
|
|
18918
|
+
function shouldDropUnderProfile(profile) {
|
|
18919
|
+
if (profile === "unknown")
|
|
18920
|
+
return true;
|
|
18921
|
+
if (profile.startsWith("library/"))
|
|
18922
|
+
return false;
|
|
18923
|
+
return true;
|
|
18924
|
+
}
|
|
18925
|
+
function makeProfileResolver(input) {
|
|
18926
|
+
if (input === undefined)
|
|
18927
|
+
return () => "unknown";
|
|
18928
|
+
if (typeof input === "string")
|
|
18929
|
+
return () => input;
|
|
18930
|
+
return (file) => input.get(file) ?? "unknown";
|
|
18931
|
+
}
|
|
18932
|
+
function normalizeDisabled(input) {
|
|
18933
|
+
if (!input)
|
|
18934
|
+
return new Set;
|
|
18935
|
+
if (input instanceof Set)
|
|
18936
|
+
return input;
|
|
18937
|
+
return new Set(input);
|
|
18938
|
+
}
|
|
18939
|
+
|
|
18463
18940
|
// ../circle-ir/dist/analysis/project-profile-transform.js
|
|
18464
18941
|
var DOWNGRADE_ELIGIBLE_RULE_IDS = new Set([
|
|
18465
18942
|
"code_injection",
|
|
@@ -30433,7 +30910,7 @@ var REFLECTION_SINK_METHODS = new Set([
|
|
|
30433
30910
|
"loadClass",
|
|
30434
30911
|
"defineClass"
|
|
30435
30912
|
]);
|
|
30436
|
-
var
|
|
30913
|
+
var TIER_1_CLASS_ANNOTATIONS2 = new Set([
|
|
30437
30914
|
"RestController",
|
|
30438
30915
|
"Controller",
|
|
30439
30916
|
"Service",
|
|
@@ -30444,7 +30921,7 @@ var TIER_1_CLASS_ANNOTATIONS = new Set([
|
|
|
30444
30921
|
"ServerEndpoint",
|
|
30445
30922
|
"FeignClient"
|
|
30446
30923
|
]);
|
|
30447
|
-
var
|
|
30924
|
+
var TIER_1_METHOD_ANNOTATIONS2 = new Set([
|
|
30448
30925
|
"RequestMapping",
|
|
30449
30926
|
"GetMapping",
|
|
30450
30927
|
"PostMapping",
|
|
@@ -30547,7 +31024,7 @@ class CliMainReflectionSuppressPass {
|
|
|
30547
31024
|
let hasFrameworkSignal = false;
|
|
30548
31025
|
for (const type of types) {
|
|
30549
31026
|
for (const ann of type.annotations) {
|
|
30550
|
-
if (
|
|
31027
|
+
if (TIER_1_CLASS_ANNOTATIONS2.has(normalizeAnnotation(ann))) {
|
|
30551
31028
|
hasFrameworkSignal = true;
|
|
30552
31029
|
break;
|
|
30553
31030
|
}
|
|
@@ -30568,7 +31045,7 @@ class CliMainReflectionSuppressPass {
|
|
|
30568
31045
|
break;
|
|
30569
31046
|
for (const method of type.methods) {
|
|
30570
31047
|
for (const ann of method.annotations) {
|
|
30571
|
-
if (
|
|
31048
|
+
if (TIER_1_METHOD_ANNOTATIONS2.has(normalizeAnnotation(ann))) {
|
|
30572
31049
|
hasFrameworkSignal = true;
|
|
30573
31050
|
break;
|
|
30574
31051
|
}
|
|
@@ -30585,52 +31062,183 @@ class CliMainReflectionSuppressPass {
|
|
|
30585
31062
|
if (hasFrameworkSignal)
|
|
30586
31063
|
break;
|
|
30587
31064
|
}
|
|
30588
|
-
const cliMainSignal = hasMain && !hasFrameworkSignal;
|
|
30589
|
-
if (!cliMainSignal) {
|
|
30590
|
-
return { cliMainSignal: false, droppedCount: 0 };
|
|
31065
|
+
const cliMainSignal = hasMain && !hasFrameworkSignal;
|
|
31066
|
+
if (!cliMainSignal) {
|
|
31067
|
+
return { cliMainSignal: false, droppedCount: 0 };
|
|
31068
|
+
}
|
|
31069
|
+
const sinks = ctx.hasResult("sink-filter") ? ctx.getResult("sink-filter").sinks : graph.ir.taint.sinks;
|
|
31070
|
+
let droppedCount = 0;
|
|
31071
|
+
const kept = sinks.filter((sink) => {
|
|
31072
|
+
if (sink.type !== "code_injection")
|
|
31073
|
+
return true;
|
|
31074
|
+
if (!sink.method)
|
|
31075
|
+
return true;
|
|
31076
|
+
if (!REFLECTION_SINK_METHODS.has(sink.method))
|
|
31077
|
+
return true;
|
|
31078
|
+
droppedCount++;
|
|
31079
|
+
return false;
|
|
31080
|
+
});
|
|
31081
|
+
if (droppedCount > 0) {
|
|
31082
|
+
sinks.length = 0;
|
|
31083
|
+
sinks.push(...kept);
|
|
31084
|
+
}
|
|
31085
|
+
return { cliMainSignal: true, droppedCount };
|
|
31086
|
+
}
|
|
31087
|
+
}
|
|
31088
|
+
|
|
31089
|
+
// ../circle-ir/dist/analysis/passes/library-profile-sink-gate-pass.js
|
|
31090
|
+
var DROPPED_SINK_TYPES = new Set([
|
|
31091
|
+
"log_injection"
|
|
31092
|
+
]);
|
|
31093
|
+
function isLibraryShape2(profile) {
|
|
31094
|
+
if (!profile || profile === "unknown")
|
|
31095
|
+
return false;
|
|
31096
|
+
return profile.startsWith("library/");
|
|
31097
|
+
}
|
|
31098
|
+
|
|
31099
|
+
class LibraryProfileSinkGatePass {
|
|
31100
|
+
name = "library-profile-sink-gate";
|
|
31101
|
+
category = "security";
|
|
31102
|
+
run(ctx) {
|
|
31103
|
+
const { graph } = ctx;
|
|
31104
|
+
const profile = graph.ir.meta.projectProfile;
|
|
31105
|
+
if (!isLibraryShape2(profile)) {
|
|
31106
|
+
return {
|
|
31107
|
+
profile,
|
|
31108
|
+
applied: false,
|
|
31109
|
+
dropped: 0,
|
|
31110
|
+
droppedByType: {}
|
|
31111
|
+
};
|
|
31112
|
+
}
|
|
31113
|
+
const sinks = ctx.hasResult("sink-filter") ? ctx.getResult("sink-filter").sinks : graph.ir.taint.sinks;
|
|
31114
|
+
if (sinks.length === 0) {
|
|
31115
|
+
return {
|
|
31116
|
+
profile,
|
|
31117
|
+
applied: true,
|
|
31118
|
+
dropped: 0,
|
|
31119
|
+
droppedByType: {}
|
|
31120
|
+
};
|
|
31121
|
+
}
|
|
31122
|
+
const droppedByType = {};
|
|
31123
|
+
const kept = [];
|
|
31124
|
+
for (const sink of sinks) {
|
|
31125
|
+
if (DROPPED_SINK_TYPES.has(sink.type)) {
|
|
31126
|
+
droppedByType[sink.type] = (droppedByType[sink.type] ?? 0) + 1;
|
|
31127
|
+
continue;
|
|
31128
|
+
}
|
|
31129
|
+
kept.push(sink);
|
|
31130
|
+
}
|
|
31131
|
+
const dropped = sinks.length - kept.length;
|
|
31132
|
+
if (dropped > 0) {
|
|
31133
|
+
sinks.length = 0;
|
|
31134
|
+
sinks.push(...kept);
|
|
31135
|
+
}
|
|
31136
|
+
return {
|
|
31137
|
+
profile,
|
|
31138
|
+
applied: true,
|
|
31139
|
+
dropped,
|
|
31140
|
+
droppedByType
|
|
31141
|
+
};
|
|
31142
|
+
}
|
|
31143
|
+
}
|
|
31144
|
+
var CWE22_SPECULATIVE_SOURCE_TYPES = new Set([
|
|
31145
|
+
"interprocedural_param",
|
|
31146
|
+
"constructor_field"
|
|
31147
|
+
]);
|
|
31148
|
+
|
|
31149
|
+
class LibraryProfileCwe22PathGatePass {
|
|
31150
|
+
name = "library-profile-cwe22-path-gate";
|
|
31151
|
+
category = "security";
|
|
31152
|
+
run(ctx) {
|
|
31153
|
+
const { graph } = ctx;
|
|
31154
|
+
const profile = graph.ir.meta.projectProfile;
|
|
31155
|
+
if (!isLibraryShape2(profile)) {
|
|
31156
|
+
return {
|
|
31157
|
+
profile,
|
|
31158
|
+
applied: false,
|
|
31159
|
+
dropped: 0,
|
|
31160
|
+
droppedBySourceType: {}
|
|
31161
|
+
};
|
|
31162
|
+
}
|
|
31163
|
+
const flows = graph.ir.taint.flows;
|
|
31164
|
+
if (!flows || flows.length === 0) {
|
|
31165
|
+
return {
|
|
31166
|
+
profile,
|
|
31167
|
+
applied: true,
|
|
31168
|
+
dropped: 0,
|
|
31169
|
+
droppedBySourceType: {}
|
|
31170
|
+
};
|
|
31171
|
+
}
|
|
31172
|
+
const droppedBySourceType = {};
|
|
31173
|
+
const kept = [];
|
|
31174
|
+
for (const flow of flows) {
|
|
31175
|
+
if (flow.sink_type === "path_traversal" && CWE22_SPECULATIVE_SOURCE_TYPES.has(flow.source_type)) {
|
|
31176
|
+
droppedBySourceType[flow.source_type] = (droppedBySourceType[flow.source_type] ?? 0) + 1;
|
|
31177
|
+
continue;
|
|
31178
|
+
}
|
|
31179
|
+
kept.push(flow);
|
|
30591
31180
|
}
|
|
30592
|
-
const
|
|
30593
|
-
|
|
30594
|
-
|
|
30595
|
-
|
|
30596
|
-
return true;
|
|
30597
|
-
if (!sink.method)
|
|
30598
|
-
return true;
|
|
30599
|
-
if (!REFLECTION_SINK_METHODS.has(sink.method))
|
|
30600
|
-
return true;
|
|
30601
|
-
droppedCount++;
|
|
30602
|
-
return false;
|
|
30603
|
-
});
|
|
30604
|
-
if (droppedCount > 0) {
|
|
30605
|
-
sinks.length = 0;
|
|
30606
|
-
sinks.push(...kept);
|
|
31181
|
+
const dropped = flows.length - kept.length;
|
|
31182
|
+
if (dropped > 0) {
|
|
31183
|
+
flows.length = 0;
|
|
31184
|
+
flows.push(...kept);
|
|
30607
31185
|
}
|
|
30608
|
-
return {
|
|
31186
|
+
return {
|
|
31187
|
+
profile,
|
|
31188
|
+
applied: true,
|
|
31189
|
+
dropped,
|
|
31190
|
+
droppedBySourceType
|
|
31191
|
+
};
|
|
30609
31192
|
}
|
|
30610
31193
|
}
|
|
30611
31194
|
|
|
30612
|
-
// ../circle-ir/dist/analysis/passes/library-profile-
|
|
30613
|
-
var
|
|
30614
|
-
"
|
|
31195
|
+
// ../circle-ir/dist/analysis/passes/library-profile-xss-gate-pass.js
|
|
31196
|
+
var XSS_NON_HTML_OUTPUT_CLASSES = new Set([
|
|
31197
|
+
"StringBuilder",
|
|
31198
|
+
"StringBuffer",
|
|
31199
|
+
"CharArrayWriter",
|
|
31200
|
+
"ByteArrayOutputStream",
|
|
31201
|
+
"PrintStream",
|
|
31202
|
+
"System",
|
|
31203
|
+
"HttpRequest",
|
|
31204
|
+
"HttpRequestBuilder",
|
|
31205
|
+
"HttpResponse",
|
|
31206
|
+
"HttpSession",
|
|
31207
|
+
"ServletRequest",
|
|
31208
|
+
"HttpServletRequest",
|
|
31209
|
+
"RedisOutputStream",
|
|
31210
|
+
"SafeEncoder",
|
|
31211
|
+
"RESP2",
|
|
31212
|
+
"Protocol",
|
|
31213
|
+
"JSONUtil",
|
|
31214
|
+
"JSON",
|
|
31215
|
+
"ObjectMapper",
|
|
31216
|
+
"JsonReader",
|
|
31217
|
+
"Logger",
|
|
31218
|
+
"LoggerFactory",
|
|
31219
|
+
"Log",
|
|
31220
|
+
"Slf4jLogger",
|
|
31221
|
+
"RequestContext",
|
|
31222
|
+
"Context"
|
|
30615
31223
|
]);
|
|
30616
|
-
function
|
|
31224
|
+
function isLibraryShape3(profile) {
|
|
30617
31225
|
if (!profile || profile === "unknown")
|
|
30618
31226
|
return false;
|
|
30619
31227
|
return profile.startsWith("library/");
|
|
30620
31228
|
}
|
|
30621
31229
|
|
|
30622
|
-
class
|
|
30623
|
-
name = "library-profile-
|
|
31230
|
+
class LibraryProfileXssGatePass {
|
|
31231
|
+
name = "library-profile-xss-gate";
|
|
30624
31232
|
category = "security";
|
|
30625
31233
|
run(ctx) {
|
|
30626
31234
|
const { graph } = ctx;
|
|
30627
31235
|
const profile = graph.ir.meta.projectProfile;
|
|
30628
|
-
if (!
|
|
31236
|
+
if (!isLibraryShape3(profile)) {
|
|
30629
31237
|
return {
|
|
30630
31238
|
profile,
|
|
30631
31239
|
applied: false,
|
|
30632
31240
|
dropped: 0,
|
|
30633
|
-
|
|
31241
|
+
droppedByClass: {}
|
|
30634
31242
|
};
|
|
30635
31243
|
}
|
|
30636
31244
|
const sinks = ctx.hasResult("sink-filter") ? ctx.getResult("sink-filter").sinks : graph.ir.taint.sinks;
|
|
@@ -30639,14 +31247,14 @@ class LibraryProfileSinkGatePass {
|
|
|
30639
31247
|
profile,
|
|
30640
31248
|
applied: true,
|
|
30641
31249
|
dropped: 0,
|
|
30642
|
-
|
|
31250
|
+
droppedByClass: {}
|
|
30643
31251
|
};
|
|
30644
31252
|
}
|
|
30645
|
-
const
|
|
31253
|
+
const droppedByClass = {};
|
|
30646
31254
|
const kept = [];
|
|
30647
31255
|
for (const sink of sinks) {
|
|
30648
|
-
if (
|
|
30649
|
-
|
|
31256
|
+
if (sink.type === "xss" && sink.class && XSS_NON_HTML_OUTPUT_CLASSES.has(sink.class)) {
|
|
31257
|
+
droppedByClass[sink.class] = (droppedByClass[sink.class] ?? 0) + 1;
|
|
30650
31258
|
continue;
|
|
30651
31259
|
}
|
|
30652
31260
|
kept.push(sink);
|
|
@@ -30660,7 +31268,7 @@ class LibraryProfileSinkGatePass {
|
|
|
30660
31268
|
profile,
|
|
30661
31269
|
applied: true,
|
|
30662
31270
|
dropped,
|
|
30663
|
-
|
|
31271
|
+
droppedByClass
|
|
30664
31272
|
};
|
|
30665
31273
|
}
|
|
30666
31274
|
}
|
|
@@ -32031,210 +32639,6 @@ function findTaintBridges2(result) {
|
|
|
32031
32639
|
return bridges;
|
|
32032
32640
|
}
|
|
32033
32641
|
|
|
32034
|
-
// ../circle-ir/dist/analysis/entry-point-detection.js
|
|
32035
|
-
var TIER_1_METHOD_ANNOTATIONS2 = new Set([
|
|
32036
|
-
"RequestMapping",
|
|
32037
|
-
"GetMapping",
|
|
32038
|
-
"PostMapping",
|
|
32039
|
-
"PutMapping",
|
|
32040
|
-
"DeleteMapping",
|
|
32041
|
-
"PatchMapping",
|
|
32042
|
-
"MessageMapping",
|
|
32043
|
-
"SubscribeMapping",
|
|
32044
|
-
"KafkaListener",
|
|
32045
|
-
"KafkaHandler",
|
|
32046
|
-
"RabbitListener",
|
|
32047
|
-
"RabbitHandler",
|
|
32048
|
-
"JmsListener",
|
|
32049
|
-
"StreamListener",
|
|
32050
|
-
"SqsListener",
|
|
32051
|
-
"SqsHandler",
|
|
32052
|
-
"EventListener",
|
|
32053
|
-
"Scheduled",
|
|
32054
|
-
"Path",
|
|
32055
|
-
"GET",
|
|
32056
|
-
"POST",
|
|
32057
|
-
"PUT",
|
|
32058
|
-
"DELETE",
|
|
32059
|
-
"PATCH",
|
|
32060
|
-
"HEAD",
|
|
32061
|
-
"OPTIONS",
|
|
32062
|
-
"DataBoundConstructor",
|
|
32063
|
-
"DataBoundSetter"
|
|
32064
|
-
]);
|
|
32065
|
-
var TIER_1_CLASS_ANNOTATIONS2 = new Set([
|
|
32066
|
-
"RestController",
|
|
32067
|
-
"Controller",
|
|
32068
|
-
"Service",
|
|
32069
|
-
"Repository",
|
|
32070
|
-
"Component",
|
|
32071
|
-
"Path",
|
|
32072
|
-
"WebServlet",
|
|
32073
|
-
"ServerEndpoint",
|
|
32074
|
-
"FeignClient"
|
|
32075
|
-
]);
|
|
32076
|
-
var TIER_1_BY_SUPERTYPE = new Map([
|
|
32077
|
-
["HttpServlet", new Set(["doGet", "doPost", "doPut", "doDelete", "doHead", "doOptions", "doTrace", "service"])],
|
|
32078
|
-
["GenericServlet", new Set(["service"])],
|
|
32079
|
-
["Filter", new Set(["doFilter"])],
|
|
32080
|
-
["HandlerInterceptor", new Set(["preHandle", "postHandle", "afterCompletion"])],
|
|
32081
|
-
["AsyncHandlerInterceptor", new Set(["preHandle", "postHandle", "afterCompletion", "afterConcurrentHandlingStarted"])],
|
|
32082
|
-
["CommandLineRunner", new Set(["run"])],
|
|
32083
|
-
["ApplicationRunner", new Set(["run"])],
|
|
32084
|
-
["SimpleChannelInboundHandler", new Set(["channelRead0", "messageReceived"])],
|
|
32085
|
-
["ChannelInboundHandler", new Set(["channelRead", "channelReadComplete"])],
|
|
32086
|
-
["ChannelInboundHandlerAdapter", new Set(["channelRead", "channelReadComplete"])],
|
|
32087
|
-
["ChannelDuplexHandler", new Set(["channelRead", "channelReadComplete"])],
|
|
32088
|
-
["NettyRequestProcessor", new Set(["process"])],
|
|
32089
|
-
["Converter", new Set(["marshal", "unmarshal"])],
|
|
32090
|
-
["SingleValueConverter", new Set(["fromString", "toString"])],
|
|
32091
|
-
["ConverterMatcher", new Set(["marshal", "unmarshal"])],
|
|
32092
|
-
["AbstractReflectionConverter", new Set(["marshal", "unmarshal", "doMarshal", "doUnmarshal"])],
|
|
32093
|
-
["AbstractSingleValueConverter", new Set(["fromString", "toString"])],
|
|
32094
|
-
["AbstractCollectionConverter", new Set(["marshal", "unmarshal"])]
|
|
32095
|
-
]);
|
|
32096
|
-
var TIER_3_CLASS_SUFFIXES = [
|
|
32097
|
-
"Util",
|
|
32098
|
-
"Utils",
|
|
32099
|
-
"Helper",
|
|
32100
|
-
"Helpers"
|
|
32101
|
-
];
|
|
32102
|
-
var TIER_3_PACKAGE_FRAGMENTS = [
|
|
32103
|
-
".template.",
|
|
32104
|
-
".templates.",
|
|
32105
|
-
".engine.",
|
|
32106
|
-
".engines."
|
|
32107
|
-
];
|
|
32108
|
-
var TIER_3_JDK_FACADE_INTERFACES = new Set([
|
|
32109
|
-
"Collection",
|
|
32110
|
-
"List",
|
|
32111
|
-
"Set",
|
|
32112
|
-
"Map",
|
|
32113
|
-
"Queue",
|
|
32114
|
-
"Deque",
|
|
32115
|
-
"SortedSet",
|
|
32116
|
-
"SortedMap",
|
|
32117
|
-
"NavigableSet",
|
|
32118
|
-
"NavigableMap",
|
|
32119
|
-
"Iterator",
|
|
32120
|
-
"Iterable",
|
|
32121
|
-
"ListIterator",
|
|
32122
|
-
"Comparator",
|
|
32123
|
-
"Comparable",
|
|
32124
|
-
"Serializable",
|
|
32125
|
-
"Externalizable",
|
|
32126
|
-
"Cloneable"
|
|
32127
|
-
]);
|
|
32128
|
-
function classNameLooksLikeUtility(name2) {
|
|
32129
|
-
if (!name2)
|
|
32130
|
-
return false;
|
|
32131
|
-
for (const suffix of TIER_3_CLASS_SUFFIXES) {
|
|
32132
|
-
if (name2.length > suffix.length && name2.endsWith(suffix))
|
|
32133
|
-
return true;
|
|
32134
|
-
}
|
|
32135
|
-
return false;
|
|
32136
|
-
}
|
|
32137
|
-
function packageLooksLikeTemplateOrEngine(pkg) {
|
|
32138
|
-
if (!pkg)
|
|
32139
|
-
return false;
|
|
32140
|
-
const padded = `.${pkg}.`;
|
|
32141
|
-
for (const frag of TIER_3_PACKAGE_FRAGMENTS) {
|
|
32142
|
-
if (padded.includes(frag))
|
|
32143
|
-
return true;
|
|
32144
|
-
}
|
|
32145
|
-
return false;
|
|
32146
|
-
}
|
|
32147
|
-
function implementsJdkFacade(t) {
|
|
32148
|
-
if (!t)
|
|
32149
|
-
return false;
|
|
32150
|
-
for (const impl of t.implements ?? []) {
|
|
32151
|
-
if (TIER_3_JDK_FACADE_INTERFACES.has(simpleTypeName(impl)))
|
|
32152
|
-
return true;
|
|
32153
|
-
}
|
|
32154
|
-
return false;
|
|
32155
|
-
}
|
|
32156
|
-
function classShapeIsLibraryFacade(enclosingType) {
|
|
32157
|
-
if (!enclosingType)
|
|
32158
|
-
return false;
|
|
32159
|
-
if (classNameLooksLikeUtility(enclosingType.name))
|
|
32160
|
-
return true;
|
|
32161
|
-
if (packageLooksLikeTemplateOrEngine(enclosingType.package))
|
|
32162
|
-
return true;
|
|
32163
|
-
if (implementsJdkFacade(enclosingType))
|
|
32164
|
-
return true;
|
|
32165
|
-
return false;
|
|
32166
|
-
}
|
|
32167
|
-
function annotationsInclude(annotations, targets) {
|
|
32168
|
-
if (!annotations || annotations.length === 0)
|
|
32169
|
-
return false;
|
|
32170
|
-
for (const raw of annotations) {
|
|
32171
|
-
const simple = raw.replace(/^@/, "").replace(/[<(].*$/, "").trim();
|
|
32172
|
-
if (targets.has(simple))
|
|
32173
|
-
return true;
|
|
32174
|
-
}
|
|
32175
|
-
return false;
|
|
32176
|
-
}
|
|
32177
|
-
function simpleTypeName(ref) {
|
|
32178
|
-
return ref.replace(/<.*$/, "").trim();
|
|
32179
|
-
}
|
|
32180
|
-
function looksLikeMainMethod(method) {
|
|
32181
|
-
if (method.name !== "main")
|
|
32182
|
-
return false;
|
|
32183
|
-
const params = method.parameters ?? [];
|
|
32184
|
-
if (params.length !== 1)
|
|
32185
|
-
return false;
|
|
32186
|
-
const t = (params[0].type ?? "").replace(/\s+/g, "");
|
|
32187
|
-
return t === "String[]" || t === "String..." || t === "java.lang.String[]";
|
|
32188
|
-
}
|
|
32189
|
-
function methodIsSupertypeLifecycleEntryPoint(method, enclosingType) {
|
|
32190
|
-
if (!method.name)
|
|
32191
|
-
return false;
|
|
32192
|
-
if (!enclosingType)
|
|
32193
|
-
return false;
|
|
32194
|
-
const candidates = [];
|
|
32195
|
-
if (enclosingType.extends)
|
|
32196
|
-
candidates.push(simpleTypeName(enclosingType.extends));
|
|
32197
|
-
for (const i2 of enclosingType.implements ?? [])
|
|
32198
|
-
candidates.push(simpleTypeName(i2));
|
|
32199
|
-
for (const supertype of candidates) {
|
|
32200
|
-
const lifecycleMethods = TIER_1_BY_SUPERTYPE.get(supertype);
|
|
32201
|
-
if (lifecycleMethods?.has(method.name))
|
|
32202
|
-
return true;
|
|
32203
|
-
}
|
|
32204
|
-
return false;
|
|
32205
|
-
}
|
|
32206
|
-
function classifyEntryPointTier(method, enclosingType, ctx) {
|
|
32207
|
-
const language = (ctx.language ?? "").toLowerCase();
|
|
32208
|
-
if (language !== "java")
|
|
32209
|
-
return "TIER_UNKNOWN";
|
|
32210
|
-
if (!method)
|
|
32211
|
-
return "TIER_UNKNOWN";
|
|
32212
|
-
if (classShapeIsLibraryFacade(enclosingType)) {
|
|
32213
|
-
return "TIER_3_LIBRARY_API";
|
|
32214
|
-
}
|
|
32215
|
-
if (annotationsInclude(method.annotations, TIER_1_METHOD_ANNOTATIONS2)) {
|
|
32216
|
-
return "TIER_1_ENTRY_POINT";
|
|
32217
|
-
}
|
|
32218
|
-
if (enclosingType && annotationsInclude(enclosingType.annotations, TIER_1_CLASS_ANNOTATIONS2)) {
|
|
32219
|
-
return "TIER_1_ENTRY_POINT";
|
|
32220
|
-
}
|
|
32221
|
-
if (methodIsSupertypeLifecycleEntryPoint(method, enclosingType)) {
|
|
32222
|
-
return "TIER_1_ENTRY_POINT";
|
|
32223
|
-
}
|
|
32224
|
-
if (looksLikeMainMethod(method)) {
|
|
32225
|
-
return "TIER_1_ENTRY_POINT";
|
|
32226
|
-
}
|
|
32227
|
-
return "TIER_3_LIBRARY_API";
|
|
32228
|
-
}
|
|
32229
|
-
function shouldGateInterproceduralParam(sourceType, enclosingMethod, enclosingType, ctx) {
|
|
32230
|
-
if (sourceType !== "interprocedural_param")
|
|
32231
|
-
return false;
|
|
32232
|
-
if (!enclosingMethod)
|
|
32233
|
-
return false;
|
|
32234
|
-
const tier = classifyEntryPointTier(enclosingMethod, enclosingType, ctx);
|
|
32235
|
-
return tier === "TIER_3_LIBRARY_API";
|
|
32236
|
-
}
|
|
32237
|
-
|
|
32238
32642
|
// ../circle-ir/dist/analysis/passes/interprocedural-pass.js
|
|
32239
32643
|
class InterproceduralPass {
|
|
32240
32644
|
name = "interprocedural";
|
|
@@ -41675,7 +42079,7 @@ function getNodeTypesForLanguage(language) {
|
|
|
41675
42079
|
]);
|
|
41676
42080
|
}
|
|
41677
42081
|
}
|
|
41678
|
-
function
|
|
42082
|
+
function makeProfileResolver2(p) {
|
|
41679
42083
|
if (p === undefined)
|
|
41680
42084
|
return () => "unknown";
|
|
41681
42085
|
if (typeof p === "string")
|
|
@@ -41744,7 +42148,7 @@ async function analyze(code, filePath, language, options = {}) {
|
|
|
41744
42148
|
const nodeCache = collectAllNodes(tree.rootNode, getNodeTypesForLanguage(language));
|
|
41745
42149
|
const meta = extractMeta(code, tree, filePath, language);
|
|
41746
42150
|
if (options.projectProfile !== undefined) {
|
|
41747
|
-
meta.projectProfile =
|
|
42151
|
+
meta.projectProfile = makeProfileResolver2(options.projectProfile)(filePath);
|
|
41748
42152
|
}
|
|
41749
42153
|
const types = extractTypes(tree, nodeCache, language);
|
|
41750
42154
|
const calls = extractCalls(tree, nodeCache, language);
|
|
@@ -41783,10 +42187,14 @@ async function analyze(code, filePath, language, options = {}) {
|
|
|
41783
42187
|
pipeline.add(new CliMainReflectionSuppressPass);
|
|
41784
42188
|
if (!disabledPasses.has("library-profile-sink-gate"))
|
|
41785
42189
|
pipeline.add(new LibraryProfileSinkGatePass);
|
|
42190
|
+
if (!disabledPasses.has("library-profile-xss-gate"))
|
|
42191
|
+
pipeline.add(new LibraryProfileXssGatePass);
|
|
41786
42192
|
pipeline.add(new TaintPropagationPass);
|
|
41787
42193
|
pipeline.add(new InterproceduralPass({
|
|
41788
42194
|
enableEntryPointGate: options.enableEntryPointGate ?? true
|
|
41789
42195
|
}));
|
|
42196
|
+
if (!disabledPasses.has("library-profile-cwe22-path-gate"))
|
|
42197
|
+
pipeline.add(new LibraryProfileCwe22PathGatePass);
|
|
41790
42198
|
if (!disabledPasses.has("scan-secrets"))
|
|
41791
42199
|
pipeline.add(new ScanSecretsPass);
|
|
41792
42200
|
if (!disabledPasses.has("dead-code"))
|
|
@@ -41935,7 +42343,7 @@ async function analyze(code, filePath, language, options = {}) {
|
|
|
41935
42343
|
emitFindingsInstrumentation(filePath, findings, taint);
|
|
41936
42344
|
const verifiedFindings = applyConfidenceFilter(findings, options.includeSpeculative === true);
|
|
41937
42345
|
const downgradedFindings = applyLibraryApiSurfaceDowngrade(verifiedFindings);
|
|
41938
|
-
const profiledFindings = applyProjectProfileTransform(downgradedFindings,
|
|
42346
|
+
const profiledFindings = applyProjectProfileTransform(downgradedFindings, makeProfileResolver2(options.projectProfile));
|
|
41939
42347
|
const cappedFindings = applyPerFileFindingCap(filePath, profiledFindings, options.perFileFindingCap ?? DEFAULT_PER_FILE_FINDING_CAP);
|
|
41940
42348
|
return {
|
|
41941
42349
|
meta,
|
|
@@ -42059,6 +42467,10 @@ async function analyzeProject(files, options = {}) {
|
|
|
42059
42467
|
fa.analysis.findings = [...fa.analysis.findings ?? [], finding];
|
|
42060
42468
|
}
|
|
42061
42469
|
}
|
|
42470
|
+
applyRequireEntryPath(fileAnalyses, {
|
|
42471
|
+
projectProfile: options.projectProfile,
|
|
42472
|
+
disabledPasses: options.disabledPasses
|
|
42473
|
+
});
|
|
42062
42474
|
const filePaths = files.map((f) => f.filePath);
|
|
42063
42475
|
const totalLoc = fileAnalyses.reduce((sum, f) => sum + (f.analysis.meta.loc ?? 0), 0);
|
|
42064
42476
|
const meta = {
|
|
@@ -42713,7 +43125,7 @@ var colors = {
|
|
|
42713
43125
|
};
|
|
42714
43126
|
|
|
42715
43127
|
// src/version.ts
|
|
42716
|
-
var version = "3.
|
|
43128
|
+
var version = "3.154.0";
|
|
42717
43129
|
|
|
42718
43130
|
// src/formatters.ts
|
|
42719
43131
|
var LIBRARY_API_SURFACE_TAG2 = "library-api-surface:caller-responsibility";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cognium-dev",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.154.0",
|
|
4
4
|
"description": "Static Application Security Testing CLI for detecting security vulnerabilities via taint tracking",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
68
|
"@cognium/project-profile-detect": "^1.1.0",
|
|
69
|
-
"circle-ir": "^3.
|
|
69
|
+
"circle-ir": "^3.154.0"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@types/node": "^25.5.0",
|