cognium-dev 3.55.0 → 3.56.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 +156 -4
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -27514,6 +27514,113 @@ function detectHardcodedKeyJava(call) {
|
|
|
27514
27514
|
return `literal string`;
|
|
27515
27515
|
return null;
|
|
27516
27516
|
}
|
|
27517
|
+
function detectHardcodedKeyPython(call, constProp, literalBindings) {
|
|
27518
|
+
const arg = call.arguments.find((a) => a.position === 0);
|
|
27519
|
+
if (!arg)
|
|
27520
|
+
return null;
|
|
27521
|
+
const expr = (arg.expression ?? arg.literal ?? "").trim();
|
|
27522
|
+
if (!expr)
|
|
27523
|
+
return null;
|
|
27524
|
+
if (/^[bB][rR]?["'][^"']*["']$/.test(expr) || /^[rR][bB]["'][^"']*["']$/.test(expr)) {
|
|
27525
|
+
return `literal bytes ${expr.slice(0, 24)}${expr.length > 24 ? "…" : ""}`;
|
|
27526
|
+
}
|
|
27527
|
+
if (/^["'][^"']*["']$/.test(expr)) {
|
|
27528
|
+
return `literal string ${expr.slice(0, 24)}${expr.length > 24 ? "…" : ""}`;
|
|
27529
|
+
}
|
|
27530
|
+
if (arg.variable && constProp) {
|
|
27531
|
+
const sym = constProp.symbols.get(arg.variable);
|
|
27532
|
+
if (sym && sym.type === "string" && typeof sym.value === "string") {
|
|
27533
|
+
return `constant-propagated bytes from \`${arg.variable}\``;
|
|
27534
|
+
}
|
|
27535
|
+
}
|
|
27536
|
+
if (arg.variable) {
|
|
27537
|
+
const lit = literalBindings.get(arg.variable);
|
|
27538
|
+
if (lit) {
|
|
27539
|
+
return `literal-bound ${arg.variable} = ${lit.slice(0, 24)}${lit.length > 24 ? "…" : ""}`;
|
|
27540
|
+
}
|
|
27541
|
+
}
|
|
27542
|
+
return null;
|
|
27543
|
+
}
|
|
27544
|
+
function detectHardcodedKeyGo(call, constProp, literalBindings) {
|
|
27545
|
+
const arg = call.arguments.find((a) => a.position === 0);
|
|
27546
|
+
if (!arg)
|
|
27547
|
+
return null;
|
|
27548
|
+
const expr = (arg.literal ?? arg.expression ?? "").trim();
|
|
27549
|
+
if (!expr)
|
|
27550
|
+
return null;
|
|
27551
|
+
if (/^\[\s*\]\s*byte\s*\(\s*["'`][^"'`]*["'`]\s*\)$/.test(expr)) {
|
|
27552
|
+
return `literal []byte("…")`;
|
|
27553
|
+
}
|
|
27554
|
+
if (/^\[\s*\]\s*byte\s*\{[^}]*\}$/.test(expr)) {
|
|
27555
|
+
return `literal []byte{…} composite`;
|
|
27556
|
+
}
|
|
27557
|
+
if (arg.variable && constProp) {
|
|
27558
|
+
const sym = constProp.symbols.get(arg.variable);
|
|
27559
|
+
if (sym && sym.type === "string" && typeof sym.value === "string") {
|
|
27560
|
+
return `constant-propagated key from \`${arg.variable}\``;
|
|
27561
|
+
}
|
|
27562
|
+
}
|
|
27563
|
+
if (arg.variable) {
|
|
27564
|
+
const lit = literalBindings.get(arg.variable);
|
|
27565
|
+
if (lit) {
|
|
27566
|
+
return `literal-bound ${arg.variable} = ${lit.slice(0, 24)}${lit.length > 24 ? "…" : ""}`;
|
|
27567
|
+
}
|
|
27568
|
+
}
|
|
27569
|
+
return null;
|
|
27570
|
+
}
|
|
27571
|
+
function parseWeakRsaKeySizePython(call) {
|
|
27572
|
+
for (const arg of call.arguments) {
|
|
27573
|
+
const expr = (arg.expression ?? "").trim();
|
|
27574
|
+
const lit = (arg.literal ?? "").trim();
|
|
27575
|
+
const m = expr.match(/^key_size\s*=\s*(-?\d+)\s*$/);
|
|
27576
|
+
if (m && m[1]) {
|
|
27577
|
+
const n = parseInt(m[1], 10);
|
|
27578
|
+
if (Number.isFinite(n) && n > 0 && n < 2048)
|
|
27579
|
+
return n;
|
|
27580
|
+
return null;
|
|
27581
|
+
}
|
|
27582
|
+
if (/^key_size\s*=/.test(expr) && lit) {
|
|
27583
|
+
const n = parseInt(lit, 10);
|
|
27584
|
+
if (Number.isFinite(n) && n > 0 && n < 2048)
|
|
27585
|
+
return n;
|
|
27586
|
+
}
|
|
27587
|
+
}
|
|
27588
|
+
return null;
|
|
27589
|
+
}
|
|
27590
|
+
function scanLiteralBindings(code, language) {
|
|
27591
|
+
const out2 = new Map;
|
|
27592
|
+
if (!code)
|
|
27593
|
+
return out2;
|
|
27594
|
+
if (language === "python") {
|
|
27595
|
+
const re = /^[ \t]*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(b[rR]?["'][^"']*["']|[rR]?b["'][^"']*["']|["'][^"']*["'])\s*(?:$|#)/gm;
|
|
27596
|
+
let m;
|
|
27597
|
+
while ((m = re.exec(code)) !== null) {
|
|
27598
|
+
if (m[1] && m[2])
|
|
27599
|
+
out2.set(m[1], m[2]);
|
|
27600
|
+
}
|
|
27601
|
+
return out2;
|
|
27602
|
+
}
|
|
27603
|
+
if (language === "go") {
|
|
27604
|
+
const reByte = /^[ \t]*(?:var\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*(?::=|=)\s*(\[\s*\]\s*byte\s*\(\s*["'`][^"'`]*["'`]\s*\))/gm;
|
|
27605
|
+
let m;
|
|
27606
|
+
while ((m = reByte.exec(code)) !== null) {
|
|
27607
|
+
if (m[1] && m[2])
|
|
27608
|
+
out2.set(m[1], m[2]);
|
|
27609
|
+
}
|
|
27610
|
+
const reStr = /^[ \t]*(?:var|const)\s+([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(["'`][^"'`]*["'`])/gm;
|
|
27611
|
+
while ((m = reStr.exec(code)) !== null) {
|
|
27612
|
+
if (m[1] && m[2])
|
|
27613
|
+
out2.set(m[1], m[2]);
|
|
27614
|
+
}
|
|
27615
|
+
const reShort = /^[ \t]*([A-Za-z_][A-Za-z0-9_]*)\s*:=\s*(["'`][^"'`]*["'`])/gm;
|
|
27616
|
+
while ((m = reShort.exec(code)) !== null) {
|
|
27617
|
+
if (m[1] && m[2])
|
|
27618
|
+
out2.set(m[1], m[2]);
|
|
27619
|
+
}
|
|
27620
|
+
return out2;
|
|
27621
|
+
}
|
|
27622
|
+
return out2;
|
|
27623
|
+
}
|
|
27517
27624
|
var ISSUE_CWE = {
|
|
27518
27625
|
"weak-cipher": "CWE-327",
|
|
27519
27626
|
"ecb-mode": "CWE-327",
|
|
@@ -27527,11 +27634,13 @@ class WeakCryptoPass {
|
|
|
27527
27634
|
name = "weak-crypto";
|
|
27528
27635
|
category = "security";
|
|
27529
27636
|
run(ctx) {
|
|
27530
|
-
const { graph, language } = ctx;
|
|
27637
|
+
const { graph, language, code } = ctx;
|
|
27531
27638
|
const file = graph.ir.meta.file;
|
|
27532
27639
|
const findings = [];
|
|
27640
|
+
const constProp = ctx.hasResult("constant-propagation") ? ctx.getResult("constant-propagation") : null;
|
|
27641
|
+
const literalBindings = scanLiteralBindings(code, language);
|
|
27533
27642
|
for (const call of graph.ir.calls) {
|
|
27534
|
-
const detections = this.detect(call, language);
|
|
27643
|
+
const detections = this.detect(call, language, constProp, literalBindings);
|
|
27535
27644
|
for (const det of detections) {
|
|
27536
27645
|
const line = call.location.line;
|
|
27537
27646
|
findings.push({ line, language, ...det });
|
|
@@ -27584,7 +27693,7 @@ class WeakCryptoPass {
|
|
|
27584
27693
|
return "Use AES-GCM (authenticated) or ChaCha20-Poly1305. Avoid DES, " + "3DES, RC2, RC4, Blowfish, and ECB mode. For asymmetric encryption " + "use RSA-OAEP with ≥2048-bit keys or modern curve-based schemes.";
|
|
27585
27694
|
}
|
|
27586
27695
|
}
|
|
27587
|
-
detect(call, language) {
|
|
27696
|
+
detect(call, language, constProp, literalBindings) {
|
|
27588
27697
|
const method = call.method_name;
|
|
27589
27698
|
const receiver = call.receiver ?? "";
|
|
27590
27699
|
const out2 = [];
|
|
@@ -27644,6 +27753,12 @@ class WeakCryptoPass {
|
|
|
27644
27753
|
out2.push({ issue: "ecb-mode", detail: "AES.MODE_ECB", api: `${receiver}.new` });
|
|
27645
27754
|
}
|
|
27646
27755
|
}
|
|
27756
|
+
if (lastSeg === "aes" || lastSeg.endsWith(".aes") || WEAK_CIPHER_BASES.has(lastSeg)) {
|
|
27757
|
+
const keyDetail = detectHardcodedKeyPython(call, constProp, literalBindings);
|
|
27758
|
+
if (keyDetail) {
|
|
27759
|
+
out2.push({ issue: "hardcoded-key", detail: keyDetail, api: `${receiver}.new` });
|
|
27760
|
+
}
|
|
27761
|
+
}
|
|
27647
27762
|
}
|
|
27648
27763
|
const isHazmatAlgos = receiver === "algorithms" || receiver.endsWith(".algorithms");
|
|
27649
27764
|
if (isHazmatAlgos) {
|
|
@@ -27652,6 +27767,25 @@ class WeakCryptoPass {
|
|
|
27652
27767
|
if (WEAK_CIPHER_BASES.has(normalized)) {
|
|
27653
27768
|
out2.push({ issue: "weak-cipher", detail: normalized, api: `algorithms.${method}` });
|
|
27654
27769
|
}
|
|
27770
|
+
if (m === "aes") {
|
|
27771
|
+
const keyDetail = detectHardcodedKeyPython(call, constProp, literalBindings);
|
|
27772
|
+
if (keyDetail) {
|
|
27773
|
+
out2.push({ issue: "hardcoded-key", detail: keyDetail, api: `algorithms.${method}` });
|
|
27774
|
+
}
|
|
27775
|
+
}
|
|
27776
|
+
}
|
|
27777
|
+
if (method === "ECB" && (receiver === "modes" || receiver.endsWith(".modes"))) {
|
|
27778
|
+
out2.push({ issue: "ecb-mode", detail: "modes.ECB()", api: `${receiver}.ECB` });
|
|
27779
|
+
}
|
|
27780
|
+
if (method === "generate_private_key" && (receiver === "rsa" || receiver === "dsa" || receiver.endsWith(".rsa") || receiver.endsWith(".dsa"))) {
|
|
27781
|
+
const n = parseWeakRsaKeySizePython(call);
|
|
27782
|
+
if (n !== null) {
|
|
27783
|
+
out2.push({
|
|
27784
|
+
issue: "weak-rsa-key",
|
|
27785
|
+
detail: String(n),
|
|
27786
|
+
api: `${receiver}.generate_private_key`
|
|
27787
|
+
});
|
|
27788
|
+
}
|
|
27655
27789
|
}
|
|
27656
27790
|
return out2;
|
|
27657
27791
|
}
|
|
@@ -27693,6 +27827,24 @@ class WeakCryptoPass {
|
|
|
27693
27827
|
if ((method === "NewECBEncrypter" || method === "NewECBDecrypter") && receiver === "cipher") {
|
|
27694
27828
|
out2.push({ issue: "ecb-mode", detail: method, api: `cipher.${method}` });
|
|
27695
27829
|
}
|
|
27830
|
+
if (receiver === "aes" && method === "NewCipher" || receiver === "des" && (method === "NewCipher" || method === "NewTripleDESCipher") || receiver === "rc4" && method === "NewCipher") {
|
|
27831
|
+
const keyDetail = detectHardcodedKeyGo(call, constProp, literalBindings);
|
|
27832
|
+
if (keyDetail) {
|
|
27833
|
+
out2.push({ issue: "hardcoded-key", detail: keyDetail, api: `${receiver}.${method}` });
|
|
27834
|
+
}
|
|
27835
|
+
}
|
|
27836
|
+
if (receiver === "rsa" && method === "GenerateKey") {
|
|
27837
|
+
const bitsArg = call.arguments.find((a) => a.position === 1);
|
|
27838
|
+
const expr = (bitsArg?.literal ?? bitsArg?.expression ?? "").trim();
|
|
27839
|
+
const n = parseInt(expr, 10);
|
|
27840
|
+
if (Number.isFinite(n) && n > 0 && n < 2048) {
|
|
27841
|
+
out2.push({
|
|
27842
|
+
issue: "weak-rsa-key",
|
|
27843
|
+
detail: String(n),
|
|
27844
|
+
api: "rsa.GenerateKey"
|
|
27845
|
+
});
|
|
27846
|
+
}
|
|
27847
|
+
}
|
|
27696
27848
|
return out2;
|
|
27697
27849
|
}
|
|
27698
27850
|
return out2;
|
|
@@ -29838,7 +29990,7 @@ var colors = {
|
|
|
29838
29990
|
};
|
|
29839
29991
|
|
|
29840
29992
|
// src/version.ts
|
|
29841
|
-
var version = "3.
|
|
29993
|
+
var version = "3.56.0";
|
|
29842
29994
|
|
|
29843
29995
|
// src/formatters.ts
|
|
29844
29996
|
var SINK_SEVERITY = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cognium-dev",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.56.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.56.0"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@types/node": "^25.5.0",
|