cognium-dev 3.35.0 → 3.37.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 +109 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -19451,6 +19451,15 @@ function buildPythonTaintedVars(sourceCode) {
|
|
|
19451
19451
|
containerTainted.set(`${obj}['${section}']['${key}']`, i2 + 1);
|
|
19452
19452
|
continue;
|
|
19453
19453
|
}
|
|
19454
|
+
const containerAppendMatch = line.match(/^\s*(\w+)\.(append|extend|insert|add|push|put|appendleft)\s*\(\s*(.+?)\s*\)\s*$/);
|
|
19455
|
+
if (containerAppendMatch) {
|
|
19456
|
+
const [, receiver, , argExpr] = containerAppendMatch;
|
|
19457
|
+
const argIsTainted = [...tainted.keys()].some((v) => new RegExp(`\\b${v}\\b`).test(argExpr));
|
|
19458
|
+
const argIsDirectSource = PYTHON_TAINTED_PATTERNS2.some((p) => p.pattern.test(argExpr));
|
|
19459
|
+
if (argIsTainted || argIsDirectSource)
|
|
19460
|
+
tainted.set(receiver, tainted.get(receiver) ?? i2 + 1);
|
|
19461
|
+
continue;
|
|
19462
|
+
}
|
|
19454
19463
|
const augAssign = line.match(/^\s*(\w+)\s*\+=\s*(.+)$/);
|
|
19455
19464
|
if (augAssign) {
|
|
19456
19465
|
const [, augLhs, augRhs] = augAssign;
|
|
@@ -20513,6 +20522,28 @@ class TaintPropagationPass {
|
|
|
20513
20522
|
flows.push(f);
|
|
20514
20523
|
}
|
|
20515
20524
|
}
|
|
20525
|
+
const exprScanFlows = detectExpressionScanFlows(calls, sources, sinks, constProp.unreachableLines, ctx.code, ctx.language) ?? [];
|
|
20526
|
+
for (const f of exprScanFlows) {
|
|
20527
|
+
if (flows.some((x) => x.source_line === f.source_line && x.sink_line === f.sink_line && x.sink_type === f.sink_type))
|
|
20528
|
+
continue;
|
|
20529
|
+
const flowForCheck = {
|
|
20530
|
+
source: { line: f.source_line },
|
|
20531
|
+
sink: { line: f.sink_line },
|
|
20532
|
+
path: f.path.map((p) => ({ variable: p.variable, line: p.line }))
|
|
20533
|
+
};
|
|
20534
|
+
if (isCorrelatedPredicateFP(constProp, flowForCheck))
|
|
20535
|
+
continue;
|
|
20536
|
+
let isFP = false;
|
|
20537
|
+
for (const step of f.path) {
|
|
20538
|
+
if (isFalsePositive(constProp, step.line, step.variable).isFalsePositive) {
|
|
20539
|
+
isFP = true;
|
|
20540
|
+
break;
|
|
20541
|
+
}
|
|
20542
|
+
}
|
|
20543
|
+
if (isFP)
|
|
20544
|
+
continue;
|
|
20545
|
+
flows.push(f);
|
|
20546
|
+
}
|
|
20516
20547
|
return { flows };
|
|
20517
20548
|
}
|
|
20518
20549
|
}
|
|
@@ -20709,6 +20740,83 @@ function detectParameterSinkFlows(types, calls, sources, sinks, unreachableLines
|
|
|
20709
20740
|
}
|
|
20710
20741
|
return flows;
|
|
20711
20742
|
}
|
|
20743
|
+
function detectExpressionScanFlows(calls, sources, sinks, unreachableLines, code, language) {
|
|
20744
|
+
const flows = [];
|
|
20745
|
+
const sourcesWithVar = sources.filter((s) => typeof s.variable === "string" && s.variable.length > 0);
|
|
20746
|
+
if (sourcesWithVar.length === 0)
|
|
20747
|
+
return flows;
|
|
20748
|
+
if (language === "python" && typeof code === "string") {
|
|
20749
|
+
const derived = buildPythonTaintedVars(code);
|
|
20750
|
+
if (derived.size > 0) {
|
|
20751
|
+
let anchor = sourcesWithVar[0];
|
|
20752
|
+
for (const s of sourcesWithVar) {
|
|
20753
|
+
if (s.line < anchor.line)
|
|
20754
|
+
anchor = s;
|
|
20755
|
+
}
|
|
20756
|
+
const existingVars = new Set(sourcesWithVar.map((s) => s.variable));
|
|
20757
|
+
for (const [varName] of derived) {
|
|
20758
|
+
if (!varName || existingVars.has(varName))
|
|
20759
|
+
continue;
|
|
20760
|
+
sourcesWithVar.push({
|
|
20761
|
+
...anchor,
|
|
20762
|
+
variable: varName
|
|
20763
|
+
});
|
|
20764
|
+
existingVars.add(varName);
|
|
20765
|
+
}
|
|
20766
|
+
}
|
|
20767
|
+
}
|
|
20768
|
+
const reCache = new Map;
|
|
20769
|
+
for (const s of sourcesWithVar) {
|
|
20770
|
+
if (reCache.has(s.variable))
|
|
20771
|
+
continue;
|
|
20772
|
+
const escaped = s.variable.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
20773
|
+
reCache.set(s.variable, new RegExp(`\\b${escaped}\\b`));
|
|
20774
|
+
}
|
|
20775
|
+
const callsByLine = new Map;
|
|
20776
|
+
for (const call of calls) {
|
|
20777
|
+
const existing = callsByLine.get(call.location.line) ?? [];
|
|
20778
|
+
existing.push(call);
|
|
20779
|
+
callsByLine.set(call.location.line, existing);
|
|
20780
|
+
}
|
|
20781
|
+
for (const sink of sinks) {
|
|
20782
|
+
if (unreachableLines.has(sink.line))
|
|
20783
|
+
continue;
|
|
20784
|
+
const callsAtSink = callsByLine.get(sink.line) ?? [];
|
|
20785
|
+
for (const call of callsAtSink) {
|
|
20786
|
+
for (const arg of call.arguments) {
|
|
20787
|
+
if (sink.argPositions && sink.argPositions.length > 0 && !sink.argPositions.includes(arg.position)) {
|
|
20788
|
+
continue;
|
|
20789
|
+
}
|
|
20790
|
+
const expr = arg.expression;
|
|
20791
|
+
if (!expr)
|
|
20792
|
+
continue;
|
|
20793
|
+
for (const source of sourcesWithVar) {
|
|
20794
|
+
if (source.line >= sink.line)
|
|
20795
|
+
continue;
|
|
20796
|
+
const re = reCache.get(source.variable);
|
|
20797
|
+
if (!re || !re.test(expr))
|
|
20798
|
+
continue;
|
|
20799
|
+
if (flows.some((f) => f.source_line === source.line && f.sink_line === sink.line && f.sink_type === sink.type))
|
|
20800
|
+
continue;
|
|
20801
|
+
flows.push({
|
|
20802
|
+
source_line: source.line,
|
|
20803
|
+
sink_line: sink.line,
|
|
20804
|
+
source_type: source.type,
|
|
20805
|
+
sink_type: sink.type,
|
|
20806
|
+
path: [
|
|
20807
|
+
{ variable: source.variable, line: source.line, type: "source" },
|
|
20808
|
+
{ variable: source.variable, line: sink.line, type: "sink" }
|
|
20809
|
+
],
|
|
20810
|
+
confidence: source.confidence * sink.confidence * 0.7,
|
|
20811
|
+
sanitized: false
|
|
20812
|
+
});
|
|
20813
|
+
break;
|
|
20814
|
+
}
|
|
20815
|
+
}
|
|
20816
|
+
}
|
|
20817
|
+
}
|
|
20818
|
+
return flows;
|
|
20819
|
+
}
|
|
20712
20820
|
|
|
20713
20821
|
// ../circle-ir/dist/analysis/interprocedural.js
|
|
20714
20822
|
function analyzeInterprocedural2(graphOrTypes, callsOrSources, dfgOrSinks, sourcesOrSanitizers, sinksOrOptions, sanitizersArg, optionsArg = {}) {
|
|
@@ -26875,7 +26983,7 @@ var colors = {
|
|
|
26875
26983
|
};
|
|
26876
26984
|
|
|
26877
26985
|
// src/version.ts
|
|
26878
|
-
var version = "3.
|
|
26986
|
+
var version = "3.37.0";
|
|
26879
26987
|
|
|
26880
26988
|
// src/formatters.ts
|
|
26881
26989
|
var SINK_SEVERITY = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cognium-dev",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.37.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.37.0"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@types/node": "^25.5.0",
|