cognium-dev 3.148.0 → 3.150.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 +284 -6
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -30343,7 +30343,7 @@ class SinkSemanticsPass {
|
|
|
30343
30343
|
return { droppedCount: 0, registrySize: 0 };
|
|
30344
30344
|
}
|
|
30345
30345
|
const registry = buildRegistry(entries);
|
|
30346
|
-
const sinks = graph.ir.taint.sinks;
|
|
30346
|
+
const sinks = ctx.hasResult("sink-filter") ? ctx.getResult("sink-filter").sinks : graph.ir.taint.sinks;
|
|
30347
30347
|
let droppedCount = 0;
|
|
30348
30348
|
const kept = sinks.filter((sink) => {
|
|
30349
30349
|
if (!sink.class || !sink.method)
|
|
@@ -30366,6 +30366,194 @@ class SinkSemanticsPass {
|
|
|
30366
30366
|
}
|
|
30367
30367
|
}
|
|
30368
30368
|
|
|
30369
|
+
// ../circle-ir/dist/analysis/passes/cli-main-reflection-suppress-pass.js
|
|
30370
|
+
var REFLECTION_SINK_METHODS = new Set([
|
|
30371
|
+
"forName",
|
|
30372
|
+
"newInstance",
|
|
30373
|
+
"invoke",
|
|
30374
|
+
"getMethod",
|
|
30375
|
+
"getDeclaredMethod",
|
|
30376
|
+
"getConstructor",
|
|
30377
|
+
"getDeclaredConstructor",
|
|
30378
|
+
"loadClass",
|
|
30379
|
+
"defineClass"
|
|
30380
|
+
]);
|
|
30381
|
+
var TIER_1_CLASS_ANNOTATIONS = new Set([
|
|
30382
|
+
"RestController",
|
|
30383
|
+
"Controller",
|
|
30384
|
+
"Service",
|
|
30385
|
+
"Repository",
|
|
30386
|
+
"Component",
|
|
30387
|
+
"Path",
|
|
30388
|
+
"WebServlet",
|
|
30389
|
+
"ServerEndpoint",
|
|
30390
|
+
"FeignClient"
|
|
30391
|
+
]);
|
|
30392
|
+
var TIER_1_METHOD_ANNOTATIONS = new Set([
|
|
30393
|
+
"RequestMapping",
|
|
30394
|
+
"GetMapping",
|
|
30395
|
+
"PostMapping",
|
|
30396
|
+
"PutMapping",
|
|
30397
|
+
"DeleteMapping",
|
|
30398
|
+
"PatchMapping",
|
|
30399
|
+
"MessageMapping",
|
|
30400
|
+
"SubscribeMapping",
|
|
30401
|
+
"KafkaListener",
|
|
30402
|
+
"KafkaHandler",
|
|
30403
|
+
"RabbitListener",
|
|
30404
|
+
"RabbitHandler",
|
|
30405
|
+
"JmsListener",
|
|
30406
|
+
"StreamListener",
|
|
30407
|
+
"SqsListener",
|
|
30408
|
+
"SqsHandler",
|
|
30409
|
+
"EventListener",
|
|
30410
|
+
"Scheduled",
|
|
30411
|
+
"Path",
|
|
30412
|
+
"GET",
|
|
30413
|
+
"POST",
|
|
30414
|
+
"PUT",
|
|
30415
|
+
"DELETE",
|
|
30416
|
+
"PATCH",
|
|
30417
|
+
"HEAD",
|
|
30418
|
+
"OPTIONS",
|
|
30419
|
+
"DataBoundConstructor",
|
|
30420
|
+
"DataBoundSetter"
|
|
30421
|
+
]);
|
|
30422
|
+
var TIER_1_SUPERTYPES = new Set([
|
|
30423
|
+
"HttpServlet",
|
|
30424
|
+
"GenericServlet",
|
|
30425
|
+
"Filter",
|
|
30426
|
+
"HandlerInterceptor",
|
|
30427
|
+
"AsyncHandlerInterceptor",
|
|
30428
|
+
"CommandLineRunner",
|
|
30429
|
+
"ApplicationRunner",
|
|
30430
|
+
"SimpleChannelInboundHandler",
|
|
30431
|
+
"ChannelInboundHandler",
|
|
30432
|
+
"ChannelInboundHandlerAdapter",
|
|
30433
|
+
"ChannelDuplexHandler",
|
|
30434
|
+
"NettyRequestProcessor",
|
|
30435
|
+
"Converter",
|
|
30436
|
+
"SingleValueConverter",
|
|
30437
|
+
"ConverterMatcher",
|
|
30438
|
+
"AbstractReflectionConverter",
|
|
30439
|
+
"AbstractSingleValueConverter",
|
|
30440
|
+
"AbstractCollectionConverter"
|
|
30441
|
+
]);
|
|
30442
|
+
function normalizeAnnotation(raw) {
|
|
30443
|
+
let s = raw.trim();
|
|
30444
|
+
if (s.startsWith("@"))
|
|
30445
|
+
s = s.slice(1);
|
|
30446
|
+
const parenIdx = s.indexOf("(");
|
|
30447
|
+
if (parenIdx >= 0)
|
|
30448
|
+
s = s.slice(0, parenIdx);
|
|
30449
|
+
const genericIdx = s.indexOf("<");
|
|
30450
|
+
if (genericIdx >= 0)
|
|
30451
|
+
s = s.slice(0, genericIdx);
|
|
30452
|
+
const dotIdx = s.lastIndexOf(".");
|
|
30453
|
+
if (dotIdx >= 0)
|
|
30454
|
+
s = s.slice(dotIdx + 1);
|
|
30455
|
+
return s.trim();
|
|
30456
|
+
}
|
|
30457
|
+
function normalizeSupertype(raw) {
|
|
30458
|
+
let s = raw.trim();
|
|
30459
|
+
const genericIdx = s.indexOf("<");
|
|
30460
|
+
if (genericIdx >= 0)
|
|
30461
|
+
s = s.slice(0, genericIdx);
|
|
30462
|
+
const dotIdx = s.lastIndexOf(".");
|
|
30463
|
+
if (dotIdx >= 0)
|
|
30464
|
+
s = s.slice(dotIdx + 1);
|
|
30465
|
+
return s.trim();
|
|
30466
|
+
}
|
|
30467
|
+
function isMainMethod(name2, paramTypes) {
|
|
30468
|
+
if (name2 !== "main")
|
|
30469
|
+
return false;
|
|
30470
|
+
if (paramTypes.length !== 1)
|
|
30471
|
+
return false;
|
|
30472
|
+
const t = paramTypes[0];
|
|
30473
|
+
if (!t)
|
|
30474
|
+
return false;
|
|
30475
|
+
const bare = t.replace(/\s+/g, "");
|
|
30476
|
+
return bare === "String[]" || bare === "java.lang.String[]";
|
|
30477
|
+
}
|
|
30478
|
+
|
|
30479
|
+
class CliMainReflectionSuppressPass {
|
|
30480
|
+
name = "cli-main-reflection-suppress";
|
|
30481
|
+
category = "security";
|
|
30482
|
+
run(ctx) {
|
|
30483
|
+
const { graph, language } = ctx;
|
|
30484
|
+
if (language !== "java") {
|
|
30485
|
+
return { cliMainSignal: false, droppedCount: 0 };
|
|
30486
|
+
}
|
|
30487
|
+
const types = graph.ir.types;
|
|
30488
|
+
if (!types || types.length === 0) {
|
|
30489
|
+
return { cliMainSignal: false, droppedCount: 0 };
|
|
30490
|
+
}
|
|
30491
|
+
let hasMain = false;
|
|
30492
|
+
let hasFrameworkSignal = false;
|
|
30493
|
+
for (const type of types) {
|
|
30494
|
+
for (const ann of type.annotations) {
|
|
30495
|
+
if (TIER_1_CLASS_ANNOTATIONS.has(normalizeAnnotation(ann))) {
|
|
30496
|
+
hasFrameworkSignal = true;
|
|
30497
|
+
break;
|
|
30498
|
+
}
|
|
30499
|
+
}
|
|
30500
|
+
if (hasFrameworkSignal)
|
|
30501
|
+
break;
|
|
30502
|
+
if (type.extends && TIER_1_SUPERTYPES.has(normalizeSupertype(type.extends))) {
|
|
30503
|
+
hasFrameworkSignal = true;
|
|
30504
|
+
break;
|
|
30505
|
+
}
|
|
30506
|
+
for (const impl of type.implements) {
|
|
30507
|
+
if (TIER_1_SUPERTYPES.has(normalizeSupertype(impl))) {
|
|
30508
|
+
hasFrameworkSignal = true;
|
|
30509
|
+
break;
|
|
30510
|
+
}
|
|
30511
|
+
}
|
|
30512
|
+
if (hasFrameworkSignal)
|
|
30513
|
+
break;
|
|
30514
|
+
for (const method of type.methods) {
|
|
30515
|
+
for (const ann of method.annotations) {
|
|
30516
|
+
if (TIER_1_METHOD_ANNOTATIONS.has(normalizeAnnotation(ann))) {
|
|
30517
|
+
hasFrameworkSignal = true;
|
|
30518
|
+
break;
|
|
30519
|
+
}
|
|
30520
|
+
}
|
|
30521
|
+
if (hasFrameworkSignal)
|
|
30522
|
+
break;
|
|
30523
|
+
if (!hasMain) {
|
|
30524
|
+
const paramTypes = method.parameters.map((p) => p.type);
|
|
30525
|
+
if (isMainMethod(method.name, paramTypes)) {
|
|
30526
|
+
hasMain = true;
|
|
30527
|
+
}
|
|
30528
|
+
}
|
|
30529
|
+
}
|
|
30530
|
+
if (hasFrameworkSignal)
|
|
30531
|
+
break;
|
|
30532
|
+
}
|
|
30533
|
+
const cliMainSignal = hasMain && !hasFrameworkSignal;
|
|
30534
|
+
if (!cliMainSignal) {
|
|
30535
|
+
return { cliMainSignal: false, droppedCount: 0 };
|
|
30536
|
+
}
|
|
30537
|
+
const sinks = ctx.hasResult("sink-filter") ? ctx.getResult("sink-filter").sinks : graph.ir.taint.sinks;
|
|
30538
|
+
let droppedCount = 0;
|
|
30539
|
+
const kept = sinks.filter((sink) => {
|
|
30540
|
+
if (sink.type !== "code_injection")
|
|
30541
|
+
return true;
|
|
30542
|
+
if (!sink.method)
|
|
30543
|
+
return true;
|
|
30544
|
+
if (!REFLECTION_SINK_METHODS.has(sink.method))
|
|
30545
|
+
return true;
|
|
30546
|
+
droppedCount++;
|
|
30547
|
+
return false;
|
|
30548
|
+
});
|
|
30549
|
+
if (droppedCount > 0) {
|
|
30550
|
+
sinks.length = 0;
|
|
30551
|
+
sinks.push(...kept);
|
|
30552
|
+
}
|
|
30553
|
+
return { cliMainSignal: true, droppedCount };
|
|
30554
|
+
}
|
|
30555
|
+
}
|
|
30556
|
+
|
|
30369
30557
|
// ../circle-ir/dist/analysis/passes/taint-propagation-pass.js
|
|
30370
30558
|
class TaintPropagationPass {
|
|
30371
30559
|
name = "taint-propagation";
|
|
@@ -31733,7 +31921,7 @@ function findTaintBridges2(result) {
|
|
|
31733
31921
|
}
|
|
31734
31922
|
|
|
31735
31923
|
// ../circle-ir/dist/analysis/entry-point-detection.js
|
|
31736
|
-
var
|
|
31924
|
+
var TIER_1_METHOD_ANNOTATIONS2 = new Set([
|
|
31737
31925
|
"RequestMapping",
|
|
31738
31926
|
"GetMapping",
|
|
31739
31927
|
"PostMapping",
|
|
@@ -31763,7 +31951,7 @@ var TIER_1_METHOD_ANNOTATIONS = new Set([
|
|
|
31763
31951
|
"DataBoundConstructor",
|
|
31764
31952
|
"DataBoundSetter"
|
|
31765
31953
|
]);
|
|
31766
|
-
var
|
|
31954
|
+
var TIER_1_CLASS_ANNOTATIONS2 = new Set([
|
|
31767
31955
|
"RestController",
|
|
31768
31956
|
"Controller",
|
|
31769
31957
|
"Service",
|
|
@@ -31913,10 +32101,10 @@ function classifyEntryPointTier(method, enclosingType, ctx) {
|
|
|
31913
32101
|
if (classShapeIsLibraryFacade(enclosingType)) {
|
|
31914
32102
|
return "TIER_3_LIBRARY_API";
|
|
31915
32103
|
}
|
|
31916
|
-
if (annotationsInclude(method.annotations,
|
|
32104
|
+
if (annotationsInclude(method.annotations, TIER_1_METHOD_ANNOTATIONS2)) {
|
|
31917
32105
|
return "TIER_1_ENTRY_POINT";
|
|
31918
32106
|
}
|
|
31919
|
-
if (enclosingType && annotationsInclude(enclosingType.annotations,
|
|
32107
|
+
if (enclosingType && annotationsInclude(enclosingType.annotations, TIER_1_CLASS_ANNOTATIONS2)) {
|
|
31920
32108
|
return "TIER_1_ENTRY_POINT";
|
|
31921
32109
|
}
|
|
31922
32110
|
if (methodIsSupertypeLifecycleEntryPoint(method, enclosingType)) {
|
|
@@ -32899,6 +33087,37 @@ var CLOSE_METHODS = new Set([
|
|
|
32899
33087
|
"shutdownNow",
|
|
32900
33088
|
"terminate"
|
|
32901
33089
|
]);
|
|
33090
|
+
var WRAPPER_CTORS = new Set([
|
|
33091
|
+
"BufferedInputStream",
|
|
33092
|
+
"BufferedOutputStream",
|
|
33093
|
+
"BufferedReader",
|
|
33094
|
+
"BufferedWriter",
|
|
33095
|
+
"InputStreamReader",
|
|
33096
|
+
"OutputStreamWriter",
|
|
33097
|
+
"DataInputStream",
|
|
33098
|
+
"DataOutputStream",
|
|
33099
|
+
"PrintStream",
|
|
33100
|
+
"PrintWriter",
|
|
33101
|
+
"LineNumberReader",
|
|
33102
|
+
"PushbackInputStream",
|
|
33103
|
+
"PushbackReader",
|
|
33104
|
+
"SequenceInputStream",
|
|
33105
|
+
"GZIPInputStream",
|
|
33106
|
+
"GZIPOutputStream",
|
|
33107
|
+
"ZipInputStream",
|
|
33108
|
+
"ZipOutputStream",
|
|
33109
|
+
"InflaterInputStream",
|
|
33110
|
+
"DeflaterOutputStream",
|
|
33111
|
+
"CheckedInputStream",
|
|
33112
|
+
"CheckedOutputStream"
|
|
33113
|
+
]);
|
|
33114
|
+
var WORKER_METHODS = new Set([
|
|
33115
|
+
"run",
|
|
33116
|
+
"call",
|
|
33117
|
+
"accept",
|
|
33118
|
+
"get",
|
|
33119
|
+
"apply"
|
|
33120
|
+
]);
|
|
32902
33121
|
|
|
32903
33122
|
class ResourceLeakPass {
|
|
32904
33123
|
name = "resource-leak";
|
|
@@ -32935,6 +33154,12 @@ class ResourceLeakPass {
|
|
|
32935
33154
|
if (this.isFactoryMethod(methodInfo.method)) {
|
|
32936
33155
|
continue;
|
|
32937
33156
|
}
|
|
33157
|
+
if (this.isWrappedByCloseableCtor(graph.ir.calls, resourceVar, openLine, methodEnd)) {
|
|
33158
|
+
continue;
|
|
33159
|
+
}
|
|
33160
|
+
if (this.isClosedInNestedWorker(graph, codeLines, resourceVar, methodInfo, openLine, methodEnd)) {
|
|
33161
|
+
continue;
|
|
33162
|
+
}
|
|
32938
33163
|
const closeCall = graph.ir.calls.find((c) => CLOSE_METHODS.has(c.method_name) && c.receiver === resourceVar && c.location.line > openLine && c.location.line <= methodEnd);
|
|
32939
33164
|
const snippet = (codeLines[openLine - 1] ?? "").trim();
|
|
32940
33165
|
if (!closeCall) {
|
|
@@ -33031,6 +33256,57 @@ class ResourceLeakPass {
|
|
|
33031
33256
|
return false;
|
|
33032
33257
|
return FACTORY_METHOD_NAME_RE.test(method.name);
|
|
33033
33258
|
}
|
|
33259
|
+
isWrappedByCloseableCtor(calls, variable, fromLine, toLine) {
|
|
33260
|
+
for (const call of calls) {
|
|
33261
|
+
if (!WRAPPER_CTORS.has(call.method_name))
|
|
33262
|
+
continue;
|
|
33263
|
+
if (call.location.line < fromLine || call.location.line > toLine)
|
|
33264
|
+
continue;
|
|
33265
|
+
for (const arg of call.arguments) {
|
|
33266
|
+
if (arg.variable === variable)
|
|
33267
|
+
return true;
|
|
33268
|
+
}
|
|
33269
|
+
}
|
|
33270
|
+
return false;
|
|
33271
|
+
}
|
|
33272
|
+
isClosedInNestedWorker(graph, lines, variable, methodInfo, fromLine, toLine) {
|
|
33273
|
+
const fieldNames = new Set(methodInfo.type.fields.map((f) => f.name));
|
|
33274
|
+
let candidateField = null;
|
|
33275
|
+
if (fieldNames.has(variable)) {
|
|
33276
|
+
candidateField = variable;
|
|
33277
|
+
} else {
|
|
33278
|
+
const thisAssignRe = new RegExp(`(?:\\bthis\\s*\\.\\s*)?(\\w+)\\s*=\\s*${escapeRegex2(variable)}\\b`);
|
|
33279
|
+
for (let l = fromLine;l <= toLine && l <= lines.length; l++) {
|
|
33280
|
+
const m = thisAssignRe.exec(lines[l - 1] ?? "");
|
|
33281
|
+
if (m && fieldNames.has(m[1])) {
|
|
33282
|
+
candidateField = m[1];
|
|
33283
|
+
break;
|
|
33284
|
+
}
|
|
33285
|
+
}
|
|
33286
|
+
}
|
|
33287
|
+
if (!candidateField)
|
|
33288
|
+
return false;
|
|
33289
|
+
for (const call of graph.ir.calls) {
|
|
33290
|
+
if (call.receiver !== candidateField)
|
|
33291
|
+
continue;
|
|
33292
|
+
if (!CLOSE_METHODS.has(call.method_name))
|
|
33293
|
+
continue;
|
|
33294
|
+
const closeLine = call.location.line;
|
|
33295
|
+
if (closeLine < fromLine || closeLine > toLine)
|
|
33296
|
+
continue;
|
|
33297
|
+
const enclosing = graph.methodAtLine(closeLine);
|
|
33298
|
+
if (!enclosing)
|
|
33299
|
+
continue;
|
|
33300
|
+
if (enclosing.method === methodInfo.method)
|
|
33301
|
+
continue;
|
|
33302
|
+
if (!WORKER_METHODS.has(enclosing.method.name))
|
|
33303
|
+
continue;
|
|
33304
|
+
if (enclosing.method.start_line > fromLine && enclosing.method.start_line <= toLine) {
|
|
33305
|
+
return true;
|
|
33306
|
+
}
|
|
33307
|
+
}
|
|
33308
|
+
return false;
|
|
33309
|
+
}
|
|
33034
33310
|
}
|
|
33035
33311
|
|
|
33036
33312
|
// ../circle-ir/dist/graph/scope-graph.js
|
|
@@ -41355,6 +41631,8 @@ async function analyze(code, filePath, language, options = {}) {
|
|
|
41355
41631
|
pipeline.add(new SinkFilterPass);
|
|
41356
41632
|
if (!disabledPasses.has("sink-semantics"))
|
|
41357
41633
|
pipeline.add(new SinkSemanticsPass);
|
|
41634
|
+
if (!disabledPasses.has("cli-main-reflection-suppress"))
|
|
41635
|
+
pipeline.add(new CliMainReflectionSuppressPass);
|
|
41358
41636
|
pipeline.add(new TaintPropagationPass);
|
|
41359
41637
|
pipeline.add(new InterproceduralPass({
|
|
41360
41638
|
enableEntryPointGate: options.enableEntryPointGate ?? true
|
|
@@ -42282,7 +42560,7 @@ var colors = {
|
|
|
42282
42560
|
};
|
|
42283
42561
|
|
|
42284
42562
|
// src/version.ts
|
|
42285
|
-
var version = "3.
|
|
42563
|
+
var version = "3.150.0";
|
|
42286
42564
|
|
|
42287
42565
|
// src/formatters.ts
|
|
42288
42566
|
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.150.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.150.0"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@types/node": "^25.5.0",
|