cognium-dev 3.192.0 → 3.193.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 +87 -12
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -15947,22 +15947,36 @@ class CrossFileResolver {
|
|
|
15947
15947
|
if (source.type === "interprocedural_param")
|
|
15948
15948
|
continue;
|
|
15949
15949
|
const sourceVar = source.variable ?? this.getLocalDefVarAt(ir, source.line);
|
|
15950
|
+
const reachable = sourceVar ? this.collectTaintReachable(ir, sourceVar, source.line, filePath) : undefined;
|
|
15950
15951
|
for (const call of ir.calls) {
|
|
15951
15952
|
if (call.location.line < source.line)
|
|
15952
15953
|
continue;
|
|
15953
15954
|
const resolved = this.resolveCall(call, filePath);
|
|
15954
15955
|
if (!resolved || resolved.targetFile === filePath)
|
|
15955
15956
|
continue;
|
|
15956
|
-
if (
|
|
15957
|
-
|
|
15958
|
-
|
|
15959
|
-
|
|
15960
|
-
|
|
15961
|
-
|
|
15962
|
-
|
|
15963
|
-
|
|
15964
|
-
|
|
15957
|
+
if (reachable) {
|
|
15958
|
+
let matchedName;
|
|
15959
|
+
for (const arg of call.arguments) {
|
|
15960
|
+
if (arg.variable && reachable.names.has(arg.variable)) {
|
|
15961
|
+
matchedName = arg.variable;
|
|
15962
|
+
break;
|
|
15963
|
+
}
|
|
15964
|
+
if (arg.expression) {
|
|
15965
|
+
for (const v of reachable.names) {
|
|
15966
|
+
if (new RegExp(`\\b${v}\\b`).test(arg.expression)) {
|
|
15967
|
+
matchedName = v;
|
|
15968
|
+
break;
|
|
15969
|
+
}
|
|
15970
|
+
}
|
|
15971
|
+
if (matchedName)
|
|
15972
|
+
break;
|
|
15973
|
+
}
|
|
15974
|
+
}
|
|
15975
|
+
if (!matchedName)
|
|
15976
|
+
continue;
|
|
15977
|
+
if (this.taintClobbered(ir, call.location.line, matchedName, reachable.defIds)) {
|
|
15965
15978
|
continue;
|
|
15979
|
+
}
|
|
15966
15980
|
}
|
|
15967
15981
|
const targetIR = this.fileIRs.get(resolved.targetFile);
|
|
15968
15982
|
if (!targetIR || targetIR.taint.sinks.length === 0)
|
|
@@ -16023,7 +16037,8 @@ class CrossFileResolver {
|
|
|
16023
16037
|
file: callerFile,
|
|
16024
16038
|
line: src.line,
|
|
16025
16039
|
type: src.type,
|
|
16026
|
-
hopChain: [{ file: callerFile, line: src.line, method: method.name, kind: "source" }]
|
|
16040
|
+
hopChain: [{ file: callerFile, line: src.line, method: method.name, kind: "source" }],
|
|
16041
|
+
defIds: this.collectTaintReachable(callerIR, src.variable, src.line, callerFile).defIds
|
|
16027
16042
|
});
|
|
16028
16043
|
}
|
|
16029
16044
|
const callsInMethod = callerIdx.callsByMethod.get(method) ?? [];
|
|
@@ -16052,7 +16067,8 @@ class CrossFileResolver {
|
|
|
16052
16067
|
file: sourceFile,
|
|
16053
16068
|
line: sourceLine,
|
|
16054
16069
|
type: sourceType,
|
|
16055
|
-
hopChain: baseChain
|
|
16070
|
+
hopChain: baseChain,
|
|
16071
|
+
defIds: this.forwardReachableDefs(callerIR, [def.id], callerFile)
|
|
16056
16072
|
});
|
|
16057
16073
|
}
|
|
16058
16074
|
}
|
|
@@ -16065,6 +16081,9 @@ class CrossFileResolver {
|
|
|
16065
16081
|
const matched = this.matchTaintedArg(arg, tainted);
|
|
16066
16082
|
if (!matched)
|
|
16067
16083
|
continue;
|
|
16084
|
+
if (this.taintClobbered(callerIR, call.location.line, matched.var, matched.origin.defIds)) {
|
|
16085
|
+
continue;
|
|
16086
|
+
}
|
|
16068
16087
|
const calleeNode = methodIndex.get(resolved.targetMethod);
|
|
16069
16088
|
if (!calleeNode)
|
|
16070
16089
|
continue;
|
|
@@ -16398,6 +16417,62 @@ class CrossFileResolver {
|
|
|
16398
16417
|
}
|
|
16399
16418
|
return;
|
|
16400
16419
|
}
|
|
16420
|
+
collectTaintReachable(ir, sourceVar, sourceLine, filePath) {
|
|
16421
|
+
const defs = ir.dfg.defs;
|
|
16422
|
+
let seedDefs = defs.filter((d) => d.variable === sourceVar && d.line === sourceLine);
|
|
16423
|
+
if (seedDefs.length === 0) {
|
|
16424
|
+
const named = defs.filter((d) => d.variable === sourceVar).sort((a, b) => a.line - b.line);
|
|
16425
|
+
if (named.length > 0)
|
|
16426
|
+
seedDefs = [named[0]];
|
|
16427
|
+
}
|
|
16428
|
+
const defIds = this.forwardReachableDefs(ir, seedDefs.map((d) => d.id), filePath);
|
|
16429
|
+
const names = new Set([sourceVar]);
|
|
16430
|
+
for (const d of defs) {
|
|
16431
|
+
if (d.variable && defIds.has(d.id))
|
|
16432
|
+
names.add(d.variable);
|
|
16433
|
+
}
|
|
16434
|
+
return { names, defIds };
|
|
16435
|
+
}
|
|
16436
|
+
forwardReachableDefs(ir, seedDefIds, filePath) {
|
|
16437
|
+
const defIds = new Set(seedDefIds);
|
|
16438
|
+
const chains = ir.dfg.chains;
|
|
16439
|
+
if (!chains || chains.length === 0 || seedDefIds.length === 0)
|
|
16440
|
+
return defIds;
|
|
16441
|
+
const lineByDefId = new Map;
|
|
16442
|
+
for (const d of ir.dfg.defs)
|
|
16443
|
+
lineByDefId.set(d.id, d.line);
|
|
16444
|
+
const crossFileCallLines = new Set;
|
|
16445
|
+
for (const call of ir.calls) {
|
|
16446
|
+
const resolved = this.resolveCall(call, filePath);
|
|
16447
|
+
if (resolved && resolved.targetFile !== filePath) {
|
|
16448
|
+
crossFileCallLines.add(call.location.line);
|
|
16449
|
+
}
|
|
16450
|
+
}
|
|
16451
|
+
const frontier = [...seedDefIds];
|
|
16452
|
+
const visited = new Set(frontier);
|
|
16453
|
+
while (frontier.length > 0) {
|
|
16454
|
+
const cur = frontier.shift();
|
|
16455
|
+
for (const ch of chains) {
|
|
16456
|
+
if (ch.from_def !== cur || visited.has(ch.to_def))
|
|
16457
|
+
continue;
|
|
16458
|
+
visited.add(ch.to_def);
|
|
16459
|
+
const toLine = lineByDefId.get(ch.to_def);
|
|
16460
|
+
if (toLine !== undefined && crossFileCallLines.has(toLine))
|
|
16461
|
+
continue;
|
|
16462
|
+
defIds.add(ch.to_def);
|
|
16463
|
+
frontier.push(ch.to_def);
|
|
16464
|
+
}
|
|
16465
|
+
}
|
|
16466
|
+
return defIds;
|
|
16467
|
+
}
|
|
16468
|
+
taintClobbered(ir, callLine, varName, taintDefIds) {
|
|
16469
|
+
if (!taintDefIds || taintDefIds.size === 0)
|
|
16470
|
+
return false;
|
|
16471
|
+
const use = ir.dfg.uses.find((u) => u.line === callLine && u.variable === varName && u.def_id !== null);
|
|
16472
|
+
if (!use || use.def_id === null)
|
|
16473
|
+
return false;
|
|
16474
|
+
return !taintDefIds.has(use.def_id);
|
|
16475
|
+
}
|
|
16401
16476
|
findRealSourceLineInMethod(ir, method) {
|
|
16402
16477
|
for (const src of ir.taint.sources) {
|
|
16403
16478
|
if (src.type === "interprocedural_param")
|
|
@@ -46004,7 +46079,7 @@ var colors = {
|
|
|
46004
46079
|
};
|
|
46005
46080
|
|
|
46006
46081
|
// src/version.ts
|
|
46007
|
-
var version = "3.
|
|
46082
|
+
var version = "3.193.0";
|
|
46008
46083
|
|
|
46009
46084
|
// src/formatters.ts
|
|
46010
46085
|
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.193.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.193.0"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@types/node": "^25.5.0",
|