cognium-dev 3.152.0 → 3.153.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.
Files changed (2) hide show
  1. package/dist/cli.js +497 -217
  2. 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] },
@@ -10968,6 +10964,9 @@ var DEFAULT_SINKS = [
10968
10964
  { method: "parseObject", class: "JSON", type: "deserialization", cwe: "CWE-502", severity: "high", arg_positions: [0], safe_if_class_literal_at: 1 },
10969
10965
  { method: "parseObject", class: "JSONObject", type: "deserialization", cwe: "CWE-502", severity: "high", arg_positions: [0], safe_if_class_literal_at: 1 },
10970
10966
  { method: "fromJson", class: "Gson", type: "deserialization", cwe: "CWE-502", severity: "medium", arg_positions: [0], safe_if_class_literal_at: 1 },
10967
+ { method: "readValue", class: "ObjectReader", type: "deserialization", cwe: "CWE-502", severity: "high", arg_positions: [0], safe_if_class_literal_at: 1 },
10968
+ { method: "convertValue", class: "ObjectMapper", type: "deserialization", cwe: "CWE-502", severity: "medium", arg_positions: [0], safe_if_class_literal_at: 1 },
10969
+ { method: "readObject", class: "Kryo", type: "deserialization", cwe: "CWE-502", severity: "high", arg_positions: [0], safe_if_class_literal_at: 1 },
10971
10970
  { method: "readObject", class: "XMLDecoder", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [] },
10972
10971
  { method: "ObjectInputStream", class: "constructor", type: "deserialization", cwe: "CWE-502", severity: "critical", arg_positions: [0] },
10973
10972
  { method: "search", class: "DirContext", type: "ldap_injection", cwe: "CWE-90", severity: "high", arg_positions: [0, 1] },
@@ -12455,7 +12454,21 @@ function argIsClassLiteral(call, position) {
12455
12454
  const expr = (arg.literal ?? arg.expression ?? "").trim();
12456
12455
  if (!expr)
12457
12456
  return false;
12458
- return CLASS_LITERAL_RE.test(expr);
12457
+ if (CLASS_LITERAL_RE.test(expr))
12458
+ return true;
12459
+ return TYPE_TOKEN_RE.test(expr);
12460
+ }
12461
+ var TYPE_TOKEN_RE = /^new\s+(?:TypeReference|TypeToken)\s*<[\s\S]*>\s*\(\s*\)\s*\{\s*\}$/;
12462
+ function argIsStringLiteral(call, position) {
12463
+ const arg = call.arguments.find((a) => a.position === position);
12464
+ if (!arg)
12465
+ return false;
12466
+ if (arg.literal !== undefined && arg.literal !== null && arg.literal !== "")
12467
+ return true;
12468
+ const expr = (arg.expression ?? "").trim();
12469
+ if (!expr)
12470
+ return false;
12471
+ return expr.startsWith('"') && expr.endsWith('"') && expr.length >= 2 || expr.startsWith("'") && expr.endsWith("'") && expr.length >= 2 || expr.startsWith('"""') && expr.endsWith('"""');
12459
12472
  }
12460
12473
  var CWE_78_RECEIVER_ALLOWLIST = new Set([
12461
12474
  "Runtime",
@@ -12649,6 +12662,9 @@ function findSinks(calls, patterns, typeHierarchy, language, sourceLines) {
12649
12662
  if (pattern.safe_if_class_literal_at !== undefined && argIsClassLiteral(call, pattern.safe_if_class_literal_at)) {
12650
12663
  continue;
12651
12664
  }
12665
+ if (pattern.safe_if_string_literal_at !== undefined && argIsStringLiteral(call, pattern.safe_if_string_literal_at)) {
12666
+ continue;
12667
+ }
12652
12668
  if (pattern.type === "command_injection") {
12653
12669
  if (call.is_constructor) {
12654
12670
  if (!CWE_78_RECEIVER_ALLOWLIST.has(call.method_name)) {
@@ -18460,6 +18476,470 @@ function applyLibraryApiSurfaceDowngrade(findings) {
18460
18476
  });
18461
18477
  }
18462
18478
 
18479
+ // ../circle-ir/dist/analysis/entry-point-detection.js
18480
+ var TIER_1_METHOD_ANNOTATIONS = new Set([
18481
+ "RequestMapping",
18482
+ "GetMapping",
18483
+ "PostMapping",
18484
+ "PutMapping",
18485
+ "DeleteMapping",
18486
+ "PatchMapping",
18487
+ "MessageMapping",
18488
+ "SubscribeMapping",
18489
+ "KafkaListener",
18490
+ "KafkaHandler",
18491
+ "RabbitListener",
18492
+ "RabbitHandler",
18493
+ "JmsListener",
18494
+ "StreamListener",
18495
+ "SqsListener",
18496
+ "SqsHandler",
18497
+ "EventListener",
18498
+ "Scheduled",
18499
+ "Path",
18500
+ "GET",
18501
+ "POST",
18502
+ "PUT",
18503
+ "DELETE",
18504
+ "PATCH",
18505
+ "HEAD",
18506
+ "OPTIONS",
18507
+ "DataBoundConstructor",
18508
+ "DataBoundSetter"
18509
+ ]);
18510
+ var TIER_1_CLASS_ANNOTATIONS = new Set([
18511
+ "RestController",
18512
+ "Controller",
18513
+ "Service",
18514
+ "Repository",
18515
+ "Component",
18516
+ "Path",
18517
+ "WebServlet",
18518
+ "ServerEndpoint",
18519
+ "FeignClient"
18520
+ ]);
18521
+ var TIER_1_BY_SUPERTYPE = new Map([
18522
+ ["HttpServlet", new Set(["doGet", "doPost", "doPut", "doDelete", "doHead", "doOptions", "doTrace", "service"])],
18523
+ ["GenericServlet", new Set(["service"])],
18524
+ ["Filter", new Set(["doFilter"])],
18525
+ ["HandlerInterceptor", new Set(["preHandle", "postHandle", "afterCompletion"])],
18526
+ ["AsyncHandlerInterceptor", new Set(["preHandle", "postHandle", "afterCompletion", "afterConcurrentHandlingStarted"])],
18527
+ ["CommandLineRunner", new Set(["run"])],
18528
+ ["ApplicationRunner", new Set(["run"])],
18529
+ ["SimpleChannelInboundHandler", new Set(["channelRead0", "messageReceived"])],
18530
+ ["ChannelInboundHandler", new Set(["channelRead", "channelReadComplete"])],
18531
+ ["ChannelInboundHandlerAdapter", new Set(["channelRead", "channelReadComplete"])],
18532
+ ["ChannelDuplexHandler", new Set(["channelRead", "channelReadComplete"])],
18533
+ ["NettyRequestProcessor", new Set(["process"])],
18534
+ ["Converter", new Set(["marshal", "unmarshal"])],
18535
+ ["SingleValueConverter", new Set(["fromString", "toString"])],
18536
+ ["ConverterMatcher", new Set(["marshal", "unmarshal"])],
18537
+ ["AbstractReflectionConverter", new Set(["marshal", "unmarshal", "doMarshal", "doUnmarshal"])],
18538
+ ["AbstractSingleValueConverter", new Set(["fromString", "toString"])],
18539
+ ["AbstractCollectionConverter", new Set(["marshal", "unmarshal"])]
18540
+ ]);
18541
+ var TIER_3_CLASS_SUFFIXES = [
18542
+ "Util",
18543
+ "Utils",
18544
+ "Helper",
18545
+ "Helpers"
18546
+ ];
18547
+ var TIER_3_PACKAGE_FRAGMENTS = [
18548
+ ".template.",
18549
+ ".templates.",
18550
+ ".engine.",
18551
+ ".engines."
18552
+ ];
18553
+ var TIER_3_JDK_FACADE_INTERFACES = new Set([
18554
+ "Collection",
18555
+ "List",
18556
+ "Set",
18557
+ "Map",
18558
+ "Queue",
18559
+ "Deque",
18560
+ "SortedSet",
18561
+ "SortedMap",
18562
+ "NavigableSet",
18563
+ "NavigableMap",
18564
+ "Iterator",
18565
+ "Iterable",
18566
+ "ListIterator",
18567
+ "Comparator",
18568
+ "Comparable",
18569
+ "Serializable",
18570
+ "Externalizable",
18571
+ "Cloneable"
18572
+ ]);
18573
+ function classNameLooksLikeUtility(name2) {
18574
+ if (!name2)
18575
+ return false;
18576
+ for (const suffix of TIER_3_CLASS_SUFFIXES) {
18577
+ if (name2.length > suffix.length && name2.endsWith(suffix))
18578
+ return true;
18579
+ }
18580
+ return false;
18581
+ }
18582
+ function packageLooksLikeTemplateOrEngine(pkg) {
18583
+ if (!pkg)
18584
+ return false;
18585
+ const padded = `.${pkg}.`;
18586
+ for (const frag of TIER_3_PACKAGE_FRAGMENTS) {
18587
+ if (padded.includes(frag))
18588
+ return true;
18589
+ }
18590
+ return false;
18591
+ }
18592
+ function implementsJdkFacade(t) {
18593
+ if (!t)
18594
+ return false;
18595
+ for (const impl of t.implements ?? []) {
18596
+ if (TIER_3_JDK_FACADE_INTERFACES.has(simpleTypeName(impl)))
18597
+ return true;
18598
+ }
18599
+ return false;
18600
+ }
18601
+ function classShapeIsLibraryFacade(enclosingType) {
18602
+ if (!enclosingType)
18603
+ return false;
18604
+ if (classNameLooksLikeUtility(enclosingType.name))
18605
+ return true;
18606
+ if (packageLooksLikeTemplateOrEngine(enclosingType.package))
18607
+ return true;
18608
+ if (implementsJdkFacade(enclosingType))
18609
+ return true;
18610
+ return false;
18611
+ }
18612
+ function annotationsInclude(annotations, targets) {
18613
+ if (!annotations || annotations.length === 0)
18614
+ return false;
18615
+ for (const raw of annotations) {
18616
+ const simple = raw.replace(/^@/, "").replace(/[<(].*$/, "").trim();
18617
+ if (targets.has(simple))
18618
+ return true;
18619
+ }
18620
+ return false;
18621
+ }
18622
+ function simpleTypeName(ref) {
18623
+ return ref.replace(/<.*$/, "").trim();
18624
+ }
18625
+ function looksLikeMainMethod(method) {
18626
+ if (method.name !== "main")
18627
+ return false;
18628
+ const params = method.parameters ?? [];
18629
+ if (params.length !== 1)
18630
+ return false;
18631
+ const t = (params[0].type ?? "").replace(/\s+/g, "");
18632
+ return t === "String[]" || t === "String..." || t === "java.lang.String[]";
18633
+ }
18634
+ function methodIsSupertypeLifecycleEntryPoint(method, enclosingType) {
18635
+ if (!method.name)
18636
+ return false;
18637
+ if (!enclosingType)
18638
+ return false;
18639
+ const candidates = [];
18640
+ if (enclosingType.extends)
18641
+ candidates.push(simpleTypeName(enclosingType.extends));
18642
+ for (const i2 of enclosingType.implements ?? [])
18643
+ candidates.push(simpleTypeName(i2));
18644
+ for (const supertype of candidates) {
18645
+ const lifecycleMethods = TIER_1_BY_SUPERTYPE.get(supertype);
18646
+ if (lifecycleMethods?.has(method.name))
18647
+ return true;
18648
+ }
18649
+ return false;
18650
+ }
18651
+ function classifyEntryPointTier(method, enclosingType, ctx) {
18652
+ const language = (ctx.language ?? "").toLowerCase();
18653
+ if (language !== "java")
18654
+ return "TIER_UNKNOWN";
18655
+ if (!method)
18656
+ return "TIER_UNKNOWN";
18657
+ if (classShapeIsLibraryFacade(enclosingType)) {
18658
+ return "TIER_3_LIBRARY_API";
18659
+ }
18660
+ if (annotationsInclude(method.annotations, TIER_1_METHOD_ANNOTATIONS)) {
18661
+ return "TIER_1_ENTRY_POINT";
18662
+ }
18663
+ if (enclosingType && annotationsInclude(enclosingType.annotations, TIER_1_CLASS_ANNOTATIONS)) {
18664
+ return "TIER_1_ENTRY_POINT";
18665
+ }
18666
+ if (methodIsSupertypeLifecycleEntryPoint(method, enclosingType)) {
18667
+ return "TIER_1_ENTRY_POINT";
18668
+ }
18669
+ if (looksLikeMainMethod(method)) {
18670
+ return "TIER_1_ENTRY_POINT";
18671
+ }
18672
+ return "TIER_3_LIBRARY_API";
18673
+ }
18674
+ function shouldGateInterproceduralParam(sourceType, enclosingMethod, enclosingType, ctx) {
18675
+ if (sourceType !== "interprocedural_param")
18676
+ return false;
18677
+ if (!enclosingMethod)
18678
+ return false;
18679
+ const tier = classifyEntryPointTier(enclosingMethod, enclosingType, ctx);
18680
+ return tier === "TIER_3_LIBRARY_API";
18681
+ }
18682
+
18683
+ // ../circle-ir/dist/analysis/require-entry-path.js
18684
+ var RULE_ID_REQUIRE_ENTRY_PATH = "require-entry-path";
18685
+ var MAX_VISITED_METHODS = 2000;
18686
+ function applyRequireEntryPath(fileAnalyses, options = {}) {
18687
+ const disabledSet = normalizeDisabled(options.disabledPasses);
18688
+ if (disabledSet.has(RULE_ID_REQUIRE_ENTRY_PATH))
18689
+ return;
18690
+ const graph = buildProjectMethodGraph(fileAnalyses);
18691
+ if (graph.methodsByKey.size === 0)
18692
+ return;
18693
+ const entryPointKeys = collectEntryPointKeys(graph);
18694
+ const profileResolver = makeProfileResolver(options.projectProfile);
18695
+ for (const fa of fileAnalyses) {
18696
+ const findings = fa.analysis.findings;
18697
+ if (!findings || findings.length === 0)
18698
+ continue;
18699
+ const kept = [];
18700
+ for (const finding of findings) {
18701
+ const decision = classifyFinding(finding, fa.analysis, graph, entryPointKeys, profileResolver(fa.file));
18702
+ switch (decision.action) {
18703
+ case "keep":
18704
+ kept.push(finding);
18705
+ break;
18706
+ case "annotate":
18707
+ kept.push({
18708
+ ...finding,
18709
+ entryPath: decision.entryPath,
18710
+ entryPathTier: decision.tier
18711
+ });
18712
+ break;
18713
+ case "drop":
18714
+ break;
18715
+ }
18716
+ }
18717
+ fa.analysis.findings = kept.length > 0 ? kept : undefined;
18718
+ }
18719
+ }
18720
+ function buildProjectMethodGraph(fileAnalyses) {
18721
+ const methodsByKey = new Map;
18722
+ const methodsByName = new Map;
18723
+ const callersOf = new Map;
18724
+ for (const fa of fileAnalyses) {
18725
+ const language = (fa.analysis.meta.language ?? "").toLowerCase();
18726
+ for (const type of fa.analysis.types ?? []) {
18727
+ for (const method of type.methods ?? []) {
18728
+ const key = makeMethodKey(fa.file, type.name, method.name, method.start_line);
18729
+ methodsByKey.set(key, {
18730
+ key,
18731
+ file: fa.file,
18732
+ className: type.name,
18733
+ method,
18734
+ enclosingType: type,
18735
+ language
18736
+ });
18737
+ const bucket = methodsByName.get(method.name);
18738
+ if (bucket)
18739
+ bucket.push(key);
18740
+ else
18741
+ methodsByName.set(method.name, [key]);
18742
+ }
18743
+ }
18744
+ }
18745
+ for (const fa of fileAnalyses) {
18746
+ const calls = fa.analysis.calls ?? [];
18747
+ for (const call of calls) {
18748
+ if (!call.in_method)
18749
+ continue;
18750
+ const callerKey = resolveCallerKey(fa, call.in_method, call.location.line);
18751
+ if (!callerKey)
18752
+ continue;
18753
+ const calleeKeys = resolveCalleeKeys(call, methodsByKey, methodsByName);
18754
+ if (calleeKeys.length === 0)
18755
+ continue;
18756
+ const code = call.receiver ? `${call.receiver}.${call.method_name}(...)` : `${call.method_name}(...)`;
18757
+ for (const calleeKey of calleeKeys) {
18758
+ const edge = {
18759
+ callerKey,
18760
+ calleeKey,
18761
+ callSiteLine: call.location.line,
18762
+ code
18763
+ };
18764
+ const bucket = callersOf.get(calleeKey);
18765
+ if (bucket)
18766
+ bucket.push(edge);
18767
+ else
18768
+ callersOf.set(calleeKey, [edge]);
18769
+ }
18770
+ }
18771
+ }
18772
+ return { methodsByKey, methodsByName, callersOf };
18773
+ }
18774
+ function makeMethodKey(file, className, methodName, startLine) {
18775
+ return `${file}|${className}#${methodName}@${startLine}`;
18776
+ }
18777
+ function resolveCallerKey(fa, inMethod, callLine) {
18778
+ for (const type of fa.analysis.types ?? []) {
18779
+ for (const method of type.methods ?? []) {
18780
+ if (method.name !== inMethod)
18781
+ continue;
18782
+ if (callLine >= method.start_line && callLine <= method.end_line) {
18783
+ return makeMethodKey(fa.file, type.name, method.name, method.start_line);
18784
+ }
18785
+ }
18786
+ }
18787
+ return null;
18788
+ }
18789
+ function resolveCalleeKeys(call, methodsByKey, methodsByName) {
18790
+ const candidates = methodsByName.get(call.method_name);
18791
+ if (!candidates || candidates.length === 0)
18792
+ return [];
18793
+ if (call.receiver_type) {
18794
+ const simple = call.receiver_type.replace(/<.*$/, "").trim();
18795
+ const matches = [];
18796
+ for (const key of candidates) {
18797
+ const rec = methodsByKey.get(key);
18798
+ if (rec?.className === simple)
18799
+ matches.push(key);
18800
+ }
18801
+ if (matches.length > 0)
18802
+ return matches;
18803
+ }
18804
+ return candidates;
18805
+ }
18806
+ function collectEntryPointKeys(graph) {
18807
+ const entryPoints = new Set;
18808
+ for (const rec of graph.methodsByKey.values()) {
18809
+ const tier = classifyEntryPointTier(rec.method, rec.enclosingType, {
18810
+ types: [rec.enclosingType],
18811
+ language: rec.language
18812
+ });
18813
+ if (tier === "TIER_1_ENTRY_POINT")
18814
+ entryPoints.add(rec.key);
18815
+ }
18816
+ return entryPoints;
18817
+ }
18818
+ function classifyFinding(finding, ir, graph, entryPointKeys, profile) {
18819
+ if (finding.category !== "security")
18820
+ return { action: "keep" };
18821
+ const isHighOrCritical = finding.severity === "high" || finding.severity === "critical";
18822
+ const language = (ir.meta.language ?? "").toLowerCase();
18823
+ if (language !== "java")
18824
+ return { action: "keep" };
18825
+ const containing = findContainingMethod(finding, ir, graph);
18826
+ if (!containing) {
18827
+ return { action: "keep" };
18828
+ }
18829
+ const bfs = reverseBfsToEntryPoint(containing.key, graph, entryPointKeys);
18830
+ if (bfs.status === "hit") {
18831
+ const entryPath = reconstructPath(bfs.entryKey, containing.key, bfs.parent, graph, finding);
18832
+ return {
18833
+ action: "annotate",
18834
+ entryPath,
18835
+ tier: "tier1-entry-point"
18836
+ };
18837
+ }
18838
+ if (bfs.status === "budget") {
18839
+ return { action: "keep" };
18840
+ }
18841
+ if (!isHighOrCritical)
18842
+ return { action: "keep" };
18843
+ if (!shouldDropUnderProfile(profile))
18844
+ return { action: "keep" };
18845
+ return { action: "drop" };
18846
+ }
18847
+ function findContainingMethod(finding, ir, graph) {
18848
+ const line = finding.line;
18849
+ for (const type of ir.types ?? []) {
18850
+ for (const method of type.methods ?? []) {
18851
+ if (line >= method.start_line && line <= method.end_line) {
18852
+ const key = makeMethodKey(finding.file, type.name, method.name, method.start_line);
18853
+ const rec = graph.methodsByKey.get(key);
18854
+ if (rec)
18855
+ return rec;
18856
+ }
18857
+ }
18858
+ }
18859
+ return null;
18860
+ }
18861
+ function reverseBfsToEntryPoint(startKey, graph, entryPointKeys) {
18862
+ const parent = new Map;
18863
+ const visited = new Set([startKey]);
18864
+ const queue = [startKey];
18865
+ if (entryPointKeys.has(startKey)) {
18866
+ return { status: "hit", entryKey: startKey, parent };
18867
+ }
18868
+ while (queue.length > 0) {
18869
+ if (visited.size > MAX_VISITED_METHODS) {
18870
+ return { status: "budget", entryKey: null, parent };
18871
+ }
18872
+ const current = queue.shift();
18873
+ const incoming = graph.callersOf.get(current) ?? [];
18874
+ incoming.sort((a, b) => a.callerKey.localeCompare(b.callerKey));
18875
+ for (const edge of incoming) {
18876
+ if (visited.has(edge.callerKey))
18877
+ continue;
18878
+ visited.add(edge.callerKey);
18879
+ parent.set(edge.callerKey, edge);
18880
+ if (entryPointKeys.has(edge.callerKey)) {
18881
+ return { status: "hit", entryKey: edge.callerKey, parent };
18882
+ }
18883
+ queue.push(edge.callerKey);
18884
+ }
18885
+ }
18886
+ return { status: "miss", entryKey: null, parent };
18887
+ }
18888
+ function reconstructPath(entryKey, sinkKey, parent, graph, finding) {
18889
+ const hops = [];
18890
+ let cursor = entryKey;
18891
+ const guard = new Set;
18892
+ while (cursor !== sinkKey) {
18893
+ if (guard.has(cursor))
18894
+ break;
18895
+ guard.add(cursor);
18896
+ const rec = graph.methodsByKey.get(cursor);
18897
+ const edge = parent.get(cursor);
18898
+ if (!rec || !edge)
18899
+ break;
18900
+ hops.push({
18901
+ file: rec.file,
18902
+ method: `${rec.className}.${rec.method.name}`,
18903
+ line: edge.callSiteLine,
18904
+ code: edge.code,
18905
+ variable: ""
18906
+ });
18907
+ cursor = edge.calleeKey;
18908
+ }
18909
+ const sinkRec = graph.methodsByKey.get(sinkKey);
18910
+ if (sinkRec) {
18911
+ hops.push({
18912
+ file: sinkRec.file,
18913
+ method: `${sinkRec.className}.${sinkRec.method.name}`,
18914
+ line: finding.line,
18915
+ code: finding.message,
18916
+ variable: ""
18917
+ });
18918
+ }
18919
+ return hops;
18920
+ }
18921
+ function shouldDropUnderProfile(profile) {
18922
+ if (profile === "unknown")
18923
+ return true;
18924
+ if (profile.startsWith("library/"))
18925
+ return false;
18926
+ return true;
18927
+ }
18928
+ function makeProfileResolver(input) {
18929
+ if (input === undefined)
18930
+ return () => "unknown";
18931
+ if (typeof input === "string")
18932
+ return () => input;
18933
+ return (file) => input.get(file) ?? "unknown";
18934
+ }
18935
+ function normalizeDisabled(input) {
18936
+ if (!input)
18937
+ return new Set;
18938
+ if (input instanceof Set)
18939
+ return input;
18940
+ return new Set(input);
18941
+ }
18942
+
18463
18943
  // ../circle-ir/dist/analysis/project-profile-transform.js
18464
18944
  var DOWNGRADE_ELIGIBLE_RULE_IDS = new Set([
18465
18945
  "code_injection",
@@ -30433,7 +30913,7 @@ var REFLECTION_SINK_METHODS = new Set([
30433
30913
  "loadClass",
30434
30914
  "defineClass"
30435
30915
  ]);
30436
- var TIER_1_CLASS_ANNOTATIONS = new Set([
30916
+ var TIER_1_CLASS_ANNOTATIONS2 = new Set([
30437
30917
  "RestController",
30438
30918
  "Controller",
30439
30919
  "Service",
@@ -30444,7 +30924,7 @@ var TIER_1_CLASS_ANNOTATIONS = new Set([
30444
30924
  "ServerEndpoint",
30445
30925
  "FeignClient"
30446
30926
  ]);
30447
- var TIER_1_METHOD_ANNOTATIONS = new Set([
30927
+ var TIER_1_METHOD_ANNOTATIONS2 = new Set([
30448
30928
  "RequestMapping",
30449
30929
  "GetMapping",
30450
30930
  "PostMapping",
@@ -30547,7 +31027,7 @@ class CliMainReflectionSuppressPass {
30547
31027
  let hasFrameworkSignal = false;
30548
31028
  for (const type of types) {
30549
31029
  for (const ann of type.annotations) {
30550
- if (TIER_1_CLASS_ANNOTATIONS.has(normalizeAnnotation(ann))) {
31030
+ if (TIER_1_CLASS_ANNOTATIONS2.has(normalizeAnnotation(ann))) {
30551
31031
  hasFrameworkSignal = true;
30552
31032
  break;
30553
31033
  }
@@ -30568,7 +31048,7 @@ class CliMainReflectionSuppressPass {
30568
31048
  break;
30569
31049
  for (const method of type.methods) {
30570
31050
  for (const ann of method.annotations) {
30571
- if (TIER_1_METHOD_ANNOTATIONS.has(normalizeAnnotation(ann))) {
31051
+ if (TIER_1_METHOD_ANNOTATIONS2.has(normalizeAnnotation(ann))) {
30572
31052
  hasFrameworkSignal = true;
30573
31053
  break;
30574
31054
  }
@@ -32031,210 +32511,6 @@ function findTaintBridges2(result) {
32031
32511
  return bridges;
32032
32512
  }
32033
32513
 
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
32514
  // ../circle-ir/dist/analysis/passes/interprocedural-pass.js
32239
32515
  class InterproceduralPass {
32240
32516
  name = "interprocedural";
@@ -41675,7 +41951,7 @@ function getNodeTypesForLanguage(language) {
41675
41951
  ]);
41676
41952
  }
41677
41953
  }
41678
- function makeProfileResolver(p) {
41954
+ function makeProfileResolver2(p) {
41679
41955
  if (p === undefined)
41680
41956
  return () => "unknown";
41681
41957
  if (typeof p === "string")
@@ -41744,7 +42020,7 @@ async function analyze(code, filePath, language, options = {}) {
41744
42020
  const nodeCache = collectAllNodes(tree.rootNode, getNodeTypesForLanguage(language));
41745
42021
  const meta = extractMeta(code, tree, filePath, language);
41746
42022
  if (options.projectProfile !== undefined) {
41747
- meta.projectProfile = makeProfileResolver(options.projectProfile)(filePath);
42023
+ meta.projectProfile = makeProfileResolver2(options.projectProfile)(filePath);
41748
42024
  }
41749
42025
  const types = extractTypes(tree, nodeCache, language);
41750
42026
  const calls = extractCalls(tree, nodeCache, language);
@@ -41935,7 +42211,7 @@ async function analyze(code, filePath, language, options = {}) {
41935
42211
  emitFindingsInstrumentation(filePath, findings, taint);
41936
42212
  const verifiedFindings = applyConfidenceFilter(findings, options.includeSpeculative === true);
41937
42213
  const downgradedFindings = applyLibraryApiSurfaceDowngrade(verifiedFindings);
41938
- const profiledFindings = applyProjectProfileTransform(downgradedFindings, makeProfileResolver(options.projectProfile));
42214
+ const profiledFindings = applyProjectProfileTransform(downgradedFindings, makeProfileResolver2(options.projectProfile));
41939
42215
  const cappedFindings = applyPerFileFindingCap(filePath, profiledFindings, options.perFileFindingCap ?? DEFAULT_PER_FILE_FINDING_CAP);
41940
42216
  return {
41941
42217
  meta,
@@ -42059,6 +42335,10 @@ async function analyzeProject(files, options = {}) {
42059
42335
  fa.analysis.findings = [...fa.analysis.findings ?? [], finding];
42060
42336
  }
42061
42337
  }
42338
+ applyRequireEntryPath(fileAnalyses, {
42339
+ projectProfile: options.projectProfile,
42340
+ disabledPasses: options.disabledPasses
42341
+ });
42062
42342
  const filePaths = files.map((f) => f.filePath);
42063
42343
  const totalLoc = fileAnalyses.reduce((sum, f) => sum + (f.analysis.meta.loc ?? 0), 0);
42064
42344
  const meta = {
@@ -42713,7 +42993,7 @@ var colors = {
42713
42993
  };
42714
42994
 
42715
42995
  // src/version.ts
42716
- var version = "3.152.0";
42996
+ var version = "3.153.0";
42717
42997
 
42718
42998
  // src/formatters.ts
42719
42999
  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.152.0",
3
+ "version": "3.153.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.152.0"
69
+ "circle-ir": "^3.153.0"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@types/node": "^25.5.0",