cognium-dev 3.38.0 → 3.39.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 +375 -2
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -18050,6 +18050,7 @@ class CrossFileResolver {
|
|
|
18050
18050
|
typeHierarchy;
|
|
18051
18051
|
fileIRs = new Map;
|
|
18052
18052
|
methodTaintInfo = new Map;
|
|
18053
|
+
fieldTaintInfo = new Map;
|
|
18053
18054
|
resolvedCalls = new Map;
|
|
18054
18055
|
constructor(symbolTable, typeHierarchy) {
|
|
18055
18056
|
this.symbolTable = symbolTable;
|
|
@@ -18060,6 +18061,7 @@ class CrossFileResolver {
|
|
|
18060
18061
|
this.symbolTable.addFromIR(ir, filePath);
|
|
18061
18062
|
this.typeHierarchy.addFromIR(ir, filePath);
|
|
18062
18063
|
this.analyzeMethodTaint(ir, filePath);
|
|
18064
|
+
this.analyzeFieldTaint(ir, filePath);
|
|
18063
18065
|
}
|
|
18064
18066
|
resolveCall(call, fromFile) {
|
|
18065
18067
|
const cacheKey = `${fromFile}:${call.location.line}:${call.method_name}`;
|
|
@@ -18226,6 +18228,113 @@ class CrossFileResolver {
|
|
|
18226
18228
|
}
|
|
18227
18229
|
}
|
|
18228
18230
|
}
|
|
18231
|
+
analyzeFieldTaint(ir, filePath) {
|
|
18232
|
+
const pkg = ir.meta.package || "";
|
|
18233
|
+
const ctorFieldRe = /^(\w+)\.(\w+)\(\) returns tainted field '([^']+)' \(from constructor param '([^']+)'\)/;
|
|
18234
|
+
for (const src of ir.taint.sources) {
|
|
18235
|
+
if (src.type !== "constructor_field")
|
|
18236
|
+
continue;
|
|
18237
|
+
const m = ctorFieldRe.exec(src.location);
|
|
18238
|
+
if (!m)
|
|
18239
|
+
continue;
|
|
18240
|
+
const [, className, , fieldName, sourceParam] = m;
|
|
18241
|
+
const typeFqn = pkg ? `${pkg}.${className}` : className;
|
|
18242
|
+
const type = ir.types.find((t) => t.name === className);
|
|
18243
|
+
if (!type)
|
|
18244
|
+
continue;
|
|
18245
|
+
const writerMethod = type.methods.find((mth) => mth.name === className && mth.parameters.some((p) => p.name === sourceParam)) ?? type.methods.find((mth) => mth.parameters.some((p) => p.name === sourceParam));
|
|
18246
|
+
if (!writerMethod)
|
|
18247
|
+
continue;
|
|
18248
|
+
const field = type.fields?.find((f) => f.name === fieldName);
|
|
18249
|
+
const key = `${typeFqn}.${fieldName}`;
|
|
18250
|
+
const existing = this.fieldTaintInfo.get(key);
|
|
18251
|
+
const writer = {
|
|
18252
|
+
methodFqn: `${typeFqn}.${writerMethod.name}`,
|
|
18253
|
+
methodName: writerMethod.name,
|
|
18254
|
+
writeLine: writerMethod.start_line,
|
|
18255
|
+
sourceType: "constructor_field",
|
|
18256
|
+
sourceLine: src.line
|
|
18257
|
+
};
|
|
18258
|
+
if (existing) {
|
|
18259
|
+
if (!existing.writers.some((w) => w.methodFqn === writer.methodFqn)) {
|
|
18260
|
+
existing.writers.push(writer);
|
|
18261
|
+
}
|
|
18262
|
+
} else {
|
|
18263
|
+
this.fieldTaintInfo.set(key, {
|
|
18264
|
+
typeFqn,
|
|
18265
|
+
fieldName,
|
|
18266
|
+
fieldType: field?.type ?? null,
|
|
18267
|
+
file: filePath,
|
|
18268
|
+
writers: [writer]
|
|
18269
|
+
});
|
|
18270
|
+
}
|
|
18271
|
+
}
|
|
18272
|
+
for (const type of ir.types) {
|
|
18273
|
+
const typeFqn = pkg ? `${pkg}.${type.name}` : type.name;
|
|
18274
|
+
for (const method of type.methods) {
|
|
18275
|
+
if (!method.name.startsWith("set") || method.name.length <= 3)
|
|
18276
|
+
continue;
|
|
18277
|
+
if (method.parameters.length !== 1)
|
|
18278
|
+
continue;
|
|
18279
|
+
const fieldName = method.name.charAt(3).toLowerCase() + method.name.substring(4);
|
|
18280
|
+
const field = type.fields?.find((f) => f.name === fieldName);
|
|
18281
|
+
if (!field)
|
|
18282
|
+
continue;
|
|
18283
|
+
const key = `${typeFqn}.${fieldName}`;
|
|
18284
|
+
const writer = {
|
|
18285
|
+
methodFqn: `${typeFqn}.${method.name}`,
|
|
18286
|
+
methodName: method.name,
|
|
18287
|
+
writeLine: method.start_line,
|
|
18288
|
+
sourceType: "setter_param",
|
|
18289
|
+
sourceLine: method.start_line
|
|
18290
|
+
};
|
|
18291
|
+
const existing = this.fieldTaintInfo.get(key);
|
|
18292
|
+
if (existing) {
|
|
18293
|
+
if (!existing.writers.some((w) => w.methodFqn === writer.methodFqn)) {
|
|
18294
|
+
existing.writers.push(writer);
|
|
18295
|
+
}
|
|
18296
|
+
} else {
|
|
18297
|
+
this.fieldTaintInfo.set(key, {
|
|
18298
|
+
typeFqn,
|
|
18299
|
+
fieldName,
|
|
18300
|
+
fieldType: field.type ?? null,
|
|
18301
|
+
file: filePath,
|
|
18302
|
+
writers: [writer]
|
|
18303
|
+
});
|
|
18304
|
+
}
|
|
18305
|
+
}
|
|
18306
|
+
}
|
|
18307
|
+
const injectAnnotations = new Set(["Autowired", "Inject", "Resource"]);
|
|
18308
|
+
for (const type of ir.types) {
|
|
18309
|
+
const typeFqn = pkg ? `${pkg}.${type.name}` : type.name;
|
|
18310
|
+
for (const field of type.fields ?? []) {
|
|
18311
|
+
if (!field.annotations?.some((a) => injectAnnotations.has(a)))
|
|
18312
|
+
continue;
|
|
18313
|
+
const key = `${typeFqn}.${field.name}`;
|
|
18314
|
+
const writer = {
|
|
18315
|
+
methodFqn: `${typeFqn}.<injected>`,
|
|
18316
|
+
methodName: "<injected>",
|
|
18317
|
+
writeLine: type.start_line,
|
|
18318
|
+
sourceType: "autowired_field",
|
|
18319
|
+
sourceLine: type.start_line
|
|
18320
|
+
};
|
|
18321
|
+
const existing = this.fieldTaintInfo.get(key);
|
|
18322
|
+
if (existing) {
|
|
18323
|
+
if (!existing.writers.some((w) => w.methodFqn === writer.methodFqn)) {
|
|
18324
|
+
existing.writers.push(writer);
|
|
18325
|
+
}
|
|
18326
|
+
} else {
|
|
18327
|
+
this.fieldTaintInfo.set(key, {
|
|
18328
|
+
typeFqn,
|
|
18329
|
+
fieldName: field.name,
|
|
18330
|
+
fieldType: field.type ?? null,
|
|
18331
|
+
file: filePath,
|
|
18332
|
+
writers: [writer]
|
|
18333
|
+
});
|
|
18334
|
+
}
|
|
18335
|
+
}
|
|
18336
|
+
}
|
|
18337
|
+
}
|
|
18229
18338
|
isMethodTaintSource(method, sources) {
|
|
18230
18339
|
const sourceAnnotations = ["RequestParam", "RequestBody", "PathVariable", "QueryParam"];
|
|
18231
18340
|
for (const param of method.parameters) {
|
|
@@ -18493,11 +18602,268 @@ class CrossFileResolver {
|
|
|
18493
18602
|
}
|
|
18494
18603
|
}
|
|
18495
18604
|
}
|
|
18605
|
+
if (tainted.size > 0) {
|
|
18606
|
+
const sinksInCaller = callerIR.taint.sinks.filter((s) => s.line >= method.start_line && s.line <= method.end_line);
|
|
18607
|
+
for (const sink of sinksInCaller) {
|
|
18608
|
+
const callsAtSink = callerIR.calls.filter((c) => c.location.line === sink.line);
|
|
18609
|
+
for (const sinkCall of callsAtSink) {
|
|
18610
|
+
for (const arg of sinkCall.arguments ?? []) {
|
|
18611
|
+
const matched = this.matchTaintedArg(arg, tainted);
|
|
18612
|
+
if (!matched)
|
|
18613
|
+
continue;
|
|
18614
|
+
const key = `${matched.origin.file}:${matched.origin.line}→${callerFile}:${sink.line}`;
|
|
18615
|
+
if (seen.has(key))
|
|
18616
|
+
continue;
|
|
18617
|
+
seen.add(key);
|
|
18618
|
+
const hops = [
|
|
18619
|
+
...matched.origin.hopChain,
|
|
18620
|
+
{ file: callerFile, line: sink.line, method: method.name, kind: "sink" }
|
|
18621
|
+
];
|
|
18622
|
+
const decay = Math.max(0.3, Math.pow(0.85, Math.max(hops.length - 1, 0)));
|
|
18623
|
+
paths.push({
|
|
18624
|
+
source: {
|
|
18625
|
+
file: matched.origin.file,
|
|
18626
|
+
line: matched.origin.line,
|
|
18627
|
+
type: matched.origin.type
|
|
18628
|
+
},
|
|
18629
|
+
sink: {
|
|
18630
|
+
file: callerFile,
|
|
18631
|
+
line: sink.line,
|
|
18632
|
+
type: sink.type,
|
|
18633
|
+
cwe: sink.cwe
|
|
18634
|
+
},
|
|
18635
|
+
hops,
|
|
18636
|
+
confidence: decay
|
|
18637
|
+
});
|
|
18638
|
+
}
|
|
18639
|
+
}
|
|
18640
|
+
}
|
|
18641
|
+
}
|
|
18496
18642
|
}
|
|
18497
18643
|
}
|
|
18498
18644
|
}
|
|
18499
18645
|
return paths;
|
|
18500
18646
|
}
|
|
18647
|
+
findFieldBindingTaintPaths() {
|
|
18648
|
+
const paths = [];
|
|
18649
|
+
const seen = new Set;
|
|
18650
|
+
if (this.fieldTaintInfo.size === 0)
|
|
18651
|
+
return paths;
|
|
18652
|
+
const fieldExprRe = /^(\w+)\.(\w+)$/;
|
|
18653
|
+
const methodIndex = this.buildMethodIndex();
|
|
18654
|
+
for (const [callerFile, callerIR] of this.fileIRs) {
|
|
18655
|
+
for (const type of callerIR.types) {
|
|
18656
|
+
const callerTypeFqn = callerIR.meta.package ? `${callerIR.meta.package}.${type.name}` : type.name;
|
|
18657
|
+
for (const method of type.methods) {
|
|
18658
|
+
const tainted = new Map;
|
|
18659
|
+
for (const src of callerIR.taint.sources) {
|
|
18660
|
+
if (src.type === "interprocedural_param")
|
|
18661
|
+
continue;
|
|
18662
|
+
if (src.line < method.start_line || src.line > method.end_line)
|
|
18663
|
+
continue;
|
|
18664
|
+
if (!src.variable)
|
|
18665
|
+
continue;
|
|
18666
|
+
tainted.set(src.variable, {
|
|
18667
|
+
file: callerFile,
|
|
18668
|
+
line: src.line,
|
|
18669
|
+
type: src.type,
|
|
18670
|
+
hopChain: [{ file: callerFile, line: src.line, method: method.name, kind: "source" }]
|
|
18671
|
+
});
|
|
18672
|
+
}
|
|
18673
|
+
const defsInMethod = callerIR.dfg.defs.filter((d) => d.kind === "local" && d.line >= method.start_line && d.line <= method.end_line && !!d.variable);
|
|
18674
|
+
for (const def of defsInMethod) {
|
|
18675
|
+
const usesAtLine = callerIR.dfg.uses.filter((u) => u.line === def.line);
|
|
18676
|
+
if (usesAtLine.length < 2)
|
|
18677
|
+
continue;
|
|
18678
|
+
let receiver = null;
|
|
18679
|
+
let fieldName = null;
|
|
18680
|
+
if (def.expression) {
|
|
18681
|
+
const exprMatch = fieldExprRe.exec(def.expression.trim());
|
|
18682
|
+
if (exprMatch) {
|
|
18683
|
+
receiver = exprMatch[1];
|
|
18684
|
+
fieldName = exprMatch[2];
|
|
18685
|
+
}
|
|
18686
|
+
}
|
|
18687
|
+
const resolveReceiverType = (rcv) => {
|
|
18688
|
+
const param = method.parameters.find((p) => p.name === rcv);
|
|
18689
|
+
if (param?.type)
|
|
18690
|
+
return param.type;
|
|
18691
|
+
const fieldOnSelf = type.fields?.find((f) => f.name === rcv);
|
|
18692
|
+
if (fieldOnSelf?.type)
|
|
18693
|
+
return fieldOnSelf.type;
|
|
18694
|
+
return null;
|
|
18695
|
+
};
|
|
18696
|
+
let receiverType = null;
|
|
18697
|
+
if (receiver && fieldName) {
|
|
18698
|
+
receiverType = resolveReceiverType(receiver);
|
|
18699
|
+
}
|
|
18700
|
+
if (!receiverType) {
|
|
18701
|
+
for (const rcvUse of usesAtLine) {
|
|
18702
|
+
if (!rcvUse.variable || rcvUse.variable === def.variable)
|
|
18703
|
+
continue;
|
|
18704
|
+
const rt = resolveReceiverType(rcvUse.variable);
|
|
18705
|
+
if (!rt)
|
|
18706
|
+
continue;
|
|
18707
|
+
const fieldUse = usesAtLine.find((u) => u !== rcvUse && !!u.variable && u.variable !== def.variable && u.variable !== rcvUse.variable && this.typeHasField(rt, u.variable));
|
|
18708
|
+
if (fieldUse) {
|
|
18709
|
+
receiver = rcvUse.variable;
|
|
18710
|
+
fieldName = fieldUse.variable;
|
|
18711
|
+
receiverType = rt;
|
|
18712
|
+
break;
|
|
18713
|
+
}
|
|
18714
|
+
}
|
|
18715
|
+
}
|
|
18716
|
+
if (!receiver || !fieldName || !receiverType)
|
|
18717
|
+
continue;
|
|
18718
|
+
const fieldKey = this.resolveFieldTaintKey(receiverType, fieldName, callerIR);
|
|
18719
|
+
if (!fieldKey)
|
|
18720
|
+
continue;
|
|
18721
|
+
const fieldInfo = this.fieldTaintInfo.get(fieldKey);
|
|
18722
|
+
if (!fieldInfo || fieldInfo.writers.length === 0)
|
|
18723
|
+
continue;
|
|
18724
|
+
const writer = fieldInfo.writers.find((w) => w.sourceType === "constructor_field" || w.sourceType === "autowired_field") ?? null;
|
|
18725
|
+
if (!writer)
|
|
18726
|
+
continue;
|
|
18727
|
+
const hopChain = [
|
|
18728
|
+
{
|
|
18729
|
+
file: fieldInfo.file,
|
|
18730
|
+
line: writer.sourceLine,
|
|
18731
|
+
method: writer.methodName,
|
|
18732
|
+
kind: "source"
|
|
18733
|
+
},
|
|
18734
|
+
{
|
|
18735
|
+
file: fieldInfo.file,
|
|
18736
|
+
line: writer.writeLine,
|
|
18737
|
+
method: writer.methodName,
|
|
18738
|
+
kind: "field_write"
|
|
18739
|
+
},
|
|
18740
|
+
{
|
|
18741
|
+
file: callerFile,
|
|
18742
|
+
line: def.line,
|
|
18743
|
+
method: method.name,
|
|
18744
|
+
kind: "field_read"
|
|
18745
|
+
}
|
|
18746
|
+
];
|
|
18747
|
+
tainted.set(def.variable, {
|
|
18748
|
+
file: fieldInfo.file,
|
|
18749
|
+
line: writer.sourceLine,
|
|
18750
|
+
type: writer.sourceType,
|
|
18751
|
+
hopChain
|
|
18752
|
+
});
|
|
18753
|
+
}
|
|
18754
|
+
if (tainted.size === 0)
|
|
18755
|
+
continue;
|
|
18756
|
+
const sinksInCaller = callerIR.taint.sinks.filter((s) => s.line >= method.start_line && s.line <= method.end_line);
|
|
18757
|
+
for (const sink of sinksInCaller) {
|
|
18758
|
+
const callsAtSink = callerIR.calls.filter((c) => c.location.line === sink.line);
|
|
18759
|
+
for (const sinkCall of callsAtSink) {
|
|
18760
|
+
for (const arg of sinkCall.arguments ?? []) {
|
|
18761
|
+
const matched = this.matchTaintedArg(arg, tainted);
|
|
18762
|
+
if (!matched)
|
|
18763
|
+
continue;
|
|
18764
|
+
const key = `fb:${matched.origin.file}:${matched.origin.line}→${callerFile}:${sink.line}`;
|
|
18765
|
+
if (seen.has(key))
|
|
18766
|
+
continue;
|
|
18767
|
+
seen.add(key);
|
|
18768
|
+
const hops = [
|
|
18769
|
+
...matched.origin.hopChain,
|
|
18770
|
+
{ file: callerFile, line: sink.line, method: method.name, kind: "sink" }
|
|
18771
|
+
];
|
|
18772
|
+
const decay = Math.max(0.3, Math.pow(0.85, Math.max(hops.length - 1, 0)));
|
|
18773
|
+
paths.push({
|
|
18774
|
+
source: {
|
|
18775
|
+
file: matched.origin.file,
|
|
18776
|
+
line: matched.origin.line,
|
|
18777
|
+
type: matched.origin.type
|
|
18778
|
+
},
|
|
18779
|
+
sink: {
|
|
18780
|
+
file: callerFile,
|
|
18781
|
+
line: sink.line,
|
|
18782
|
+
type: sink.type,
|
|
18783
|
+
cwe: sink.cwe
|
|
18784
|
+
},
|
|
18785
|
+
hops,
|
|
18786
|
+
confidence: decay
|
|
18787
|
+
});
|
|
18788
|
+
}
|
|
18789
|
+
}
|
|
18790
|
+
}
|
|
18791
|
+
const callsInMethod = callerIR.calls.filter((c) => c.location.line >= method.start_line && c.location.line <= method.end_line).sort((a, b) => a.location.line - b.location.line);
|
|
18792
|
+
for (const call of callsInMethod) {
|
|
18793
|
+
const resolved = this.resolveCall(call, callerFile);
|
|
18794
|
+
if (!resolved)
|
|
18795
|
+
continue;
|
|
18796
|
+
const callee = this.methodTaintInfo.get(resolved.targetMethod);
|
|
18797
|
+
if (!callee || callee.sanitizes || callee.taintedParams.length === 0)
|
|
18798
|
+
continue;
|
|
18799
|
+
for (let argIdx = 0;argIdx < call.arguments.length; argIdx++) {
|
|
18800
|
+
if (!callee.taintedParams.includes(argIdx))
|
|
18801
|
+
continue;
|
|
18802
|
+
const matched = this.matchTaintedArg(call.arguments[argIdx], tainted);
|
|
18803
|
+
if (!matched)
|
|
18804
|
+
continue;
|
|
18805
|
+
const calleeNode = methodIndex.get(resolved.targetMethod);
|
|
18806
|
+
if (!calleeNode)
|
|
18807
|
+
continue;
|
|
18808
|
+
const sinksInCallee = calleeNode.ir.taint.sinks.filter((s) => s.line >= calleeNode.method.start_line && s.line <= calleeNode.method.end_line);
|
|
18809
|
+
for (const sink of sinksInCallee) {
|
|
18810
|
+
const key = `fb:${matched.origin.file}:${matched.origin.line}→${callee.file}:${sink.line}`;
|
|
18811
|
+
if (seen.has(key))
|
|
18812
|
+
continue;
|
|
18813
|
+
seen.add(key);
|
|
18814
|
+
const hops = [
|
|
18815
|
+
...matched.origin.hopChain,
|
|
18816
|
+
{ file: callerFile, line: call.location.line, method: method.name, kind: "sink_call" },
|
|
18817
|
+
{ file: callee.file, line: sink.line, method: resolved.targetMethod, kind: "sink" }
|
|
18818
|
+
];
|
|
18819
|
+
const decay = Math.max(0.3, Math.pow(0.85, Math.max(hops.length - 1, 0)));
|
|
18820
|
+
paths.push({
|
|
18821
|
+
source: {
|
|
18822
|
+
file: matched.origin.file,
|
|
18823
|
+
line: matched.origin.line,
|
|
18824
|
+
type: matched.origin.type
|
|
18825
|
+
},
|
|
18826
|
+
sink: {
|
|
18827
|
+
file: callee.file,
|
|
18828
|
+
line: sink.line,
|
|
18829
|
+
type: sink.type,
|
|
18830
|
+
cwe: sink.cwe
|
|
18831
|
+
},
|
|
18832
|
+
hops,
|
|
18833
|
+
confidence: decay
|
|
18834
|
+
});
|
|
18835
|
+
}
|
|
18836
|
+
}
|
|
18837
|
+
}
|
|
18838
|
+
}
|
|
18839
|
+
}
|
|
18840
|
+
}
|
|
18841
|
+
return paths;
|
|
18842
|
+
}
|
|
18843
|
+
typeHasField(typeName, fieldName) {
|
|
18844
|
+
for (const [, ir] of this.fileIRs) {
|
|
18845
|
+
for (const t of ir.types) {
|
|
18846
|
+
if (t.name !== typeName)
|
|
18847
|
+
continue;
|
|
18848
|
+
if ((t.fields ?? []).some((f) => f.name === fieldName))
|
|
18849
|
+
return true;
|
|
18850
|
+
}
|
|
18851
|
+
}
|
|
18852
|
+
return false;
|
|
18853
|
+
}
|
|
18854
|
+
resolveFieldTaintKey(receiverType, fieldName, _callerIR) {
|
|
18855
|
+
const direct = `${receiverType}.${fieldName}`;
|
|
18856
|
+
if (this.fieldTaintInfo.has(direct))
|
|
18857
|
+
return direct;
|
|
18858
|
+
const suffix = `.${receiverType}.${fieldName}`;
|
|
18859
|
+
for (const key of this.fieldTaintInfo.keys()) {
|
|
18860
|
+
if (key === direct)
|
|
18861
|
+
return key;
|
|
18862
|
+
if (key.endsWith(suffix))
|
|
18863
|
+
return key;
|
|
18864
|
+
}
|
|
18865
|
+
return;
|
|
18866
|
+
}
|
|
18501
18867
|
matchTaintedArg(arg, tainted) {
|
|
18502
18868
|
if (tainted.size === 0)
|
|
18503
18869
|
return null;
|
|
@@ -18582,8 +18948,12 @@ class CrossFileResolver {
|
|
|
18582
18948
|
clear() {
|
|
18583
18949
|
this.fileIRs.clear();
|
|
18584
18950
|
this.methodTaintInfo.clear();
|
|
18951
|
+
this.fieldTaintInfo.clear();
|
|
18585
18952
|
this.resolvedCalls.clear();
|
|
18586
18953
|
}
|
|
18954
|
+
getFieldTaintInfo(typeFqn, fieldName) {
|
|
18955
|
+
return this.fieldTaintInfo.get(`${typeFqn}.${fieldName}`);
|
|
18956
|
+
}
|
|
18587
18957
|
}
|
|
18588
18958
|
// ../circle-ir/dist/graph/project-graph.js
|
|
18589
18959
|
class ProjectGraph {
|
|
@@ -18725,7 +19095,10 @@ class CrossFilePass {
|
|
|
18725
19095
|
confidence: 0.7
|
|
18726
19096
|
}];
|
|
18727
19097
|
});
|
|
18728
|
-
const ipPaths =
|
|
19098
|
+
const ipPaths = [
|
|
19099
|
+
...resolver.findInterproceduralTaintPaths(),
|
|
19100
|
+
...resolver.findFieldBindingTaintPaths()
|
|
19101
|
+
];
|
|
18729
19102
|
for (let i2 = 0;i2 < ipPaths.length; i2++) {
|
|
18730
19103
|
const p = ipPaths[i2];
|
|
18731
19104
|
const sinkIR = projectGraph.getIR(p.sink.file);
|
|
@@ -27217,7 +27590,7 @@ var colors = {
|
|
|
27217
27590
|
};
|
|
27218
27591
|
|
|
27219
27592
|
// src/version.ts
|
|
27220
|
-
var version = "3.
|
|
27593
|
+
var version = "3.39.0";
|
|
27221
27594
|
|
|
27222
27595
|
// src/formatters.ts
|
|
27223
27596
|
var SINK_SEVERITY = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cognium-dev",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.39.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",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"registry": "https://registry.npmjs.org/"
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
|
-
"circle-ir": "^3.
|
|
68
|
+
"circle-ir": "^3.39.0"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@types/node": "^25.5.0",
|