cognium-dev 3.75.0 → 3.78.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.
Files changed (2) hide show
  1. package/dist/cli.js +114 -6
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -23733,6 +23733,48 @@ function detectExpressionScanFlows(calls, sources, sinks, sanitizers, unreachabl
23733
23733
  }
23734
23734
  }
23735
23735
  }
23736
+ const aliasChains = [];
23737
+ {
23738
+ const codeLines2 = code.split(`
23739
+ `);
23740
+ for (let i2 = 0;i2 < codeLines2.length; i2++) {
23741
+ const ln = codeLines2[i2];
23742
+ if (ln.trimStart().startsWith("#"))
23743
+ continue;
23744
+ const m = ln.match(/^\s*([\p{L}\p{N}_]+)\s*=\s*([\p{L}\p{N}_]+)\s*$/u);
23745
+ if (!m)
23746
+ continue;
23747
+ const lineNum = i2 + 1;
23748
+ const lhs = m[1];
23749
+ if (derived.get(lhs) !== lineNum)
23750
+ continue;
23751
+ aliasChains.push({ lhs, upstream: m[2], line: lineNum });
23752
+ }
23753
+ }
23754
+ if (aliasChains.length > 0) {
23755
+ let changed = true;
23756
+ let guard = 0;
23757
+ while (changed && guard < aliasChains.length + 2) {
23758
+ changed = false;
23759
+ guard++;
23760
+ for (const { lhs, upstream } of aliasChains) {
23761
+ const upCov = aliasSanitizedFor.get(upstream);
23762
+ if (!upCov || upCov.size === 0)
23763
+ continue;
23764
+ let downCov = aliasSanitizedFor.get(lhs);
23765
+ if (!downCov) {
23766
+ downCov = new Set;
23767
+ aliasSanitizedFor.set(lhs, downCov);
23768
+ }
23769
+ for (const t of upCov) {
23770
+ if (!downCov.has(t)) {
23771
+ downCov.add(t);
23772
+ changed = true;
23773
+ }
23774
+ }
23775
+ }
23776
+ }
23777
+ }
23736
23778
  }
23737
23779
  }
23738
23780
  if (language === "rust" && typeof code === "string" && sourcesWithVar.length > 0) {
@@ -29292,6 +29334,17 @@ var COMMONS_DIGEST_METHODS = new Set([
29292
29334
  "sha",
29293
29335
  "shaHex"
29294
29336
  ]);
29337
+ var COMMONS_DIGEST_GETTERS = {
29338
+ getMd2Digest: "md2",
29339
+ getMd5Digest: "md5",
29340
+ getSha1Digest: "sha1",
29341
+ getShaDigest: "sha1"
29342
+ };
29343
+ var COMMONS_ALGO_CONSTANTS = {
29344
+ "MessageDigestAlgorithms.MD2": "md2",
29345
+ "MessageDigestAlgorithms.MD5": "md5",
29346
+ "MessageDigestAlgorithms.SHA_1": "sha1"
29347
+ };
29295
29348
  var PY_HASHLIB_WEAK = new Set(["md5", "sha1", "md4", "md2", "new"]);
29296
29349
  function stripQuotes4(s) {
29297
29350
  const trimmed = s.trim();
@@ -29308,16 +29361,68 @@ function literalAlgo(call, position) {
29308
29361
  const cleaned = stripQuotes4(raw).toLowerCase();
29309
29362
  return cleaned || null;
29310
29363
  }
29364
+ function resolveJavaAlgo(call, position, constProp, javaBindings) {
29365
+ const arg = call.arguments.find((a) => a.position === position);
29366
+ if (!arg)
29367
+ return null;
29368
+ if (arg.literal) {
29369
+ const cleaned = stripQuotes4(arg.literal).toLowerCase();
29370
+ if (cleaned)
29371
+ return cleaned;
29372
+ }
29373
+ const expr = (arg.expression ?? "").trim();
29374
+ if (expr.startsWith('"') || expr.startsWith("`") || expr.startsWith("'")) {
29375
+ const cleaned = stripQuotes4(expr).toLowerCase();
29376
+ if (cleaned)
29377
+ return cleaned;
29378
+ }
29379
+ if (COMMONS_ALGO_CONSTANTS[expr])
29380
+ return COMMONS_ALGO_CONSTANTS[expr];
29381
+ const tail = expr.split(".").slice(-2).join(".");
29382
+ if (COMMONS_ALGO_CONSTANTS[tail])
29383
+ return COMMONS_ALGO_CONSTANTS[tail];
29384
+ if (arg.variable && constProp) {
29385
+ const sym = constProp.symbols?.get(arg.variable);
29386
+ if (sym && sym.type === "string" && typeof sym.value === "string") {
29387
+ const cleaned = stripQuotes4(sym.value).toLowerCase();
29388
+ if (cleaned)
29389
+ return cleaned;
29390
+ }
29391
+ }
29392
+ if (arg.variable) {
29393
+ const bound = javaBindings.get(arg.variable);
29394
+ if (bound) {
29395
+ const cleaned = stripQuotes4(bound).toLowerCase();
29396
+ if (cleaned)
29397
+ return cleaned;
29398
+ }
29399
+ }
29400
+ return null;
29401
+ }
29402
+ function scanJavaStringBindings(code) {
29403
+ const out2 = new Map;
29404
+ if (!code)
29405
+ return out2;
29406
+ const re = /^[ \t]*(?:(?:public|private|protected|static|final|volatile)\s+){0,5}String\s+([A-Za-z_][A-Za-z0-9_]*)\s*=\s*("[^"]*")\s*;/gm;
29407
+ let m;
29408
+ while ((m = re.exec(code)) !== null) {
29409
+ if (m[1] && m[2])
29410
+ out2.set(m[1], m[2]);
29411
+ }
29412
+ return out2;
29413
+ }
29311
29414
 
29312
29415
  class WeakHashPass {
29313
29416
  name = "weak-hash";
29314
29417
  category = "security";
29315
29418
  run(ctx) {
29316
- const { graph, language } = ctx;
29419
+ const { graph, language, code } = ctx;
29317
29420
  const file = graph.ir.meta.file;
29318
29421
  const findings = [];
29422
+ const constProp = ctx.hasResult("constant-propagation") ? ctx.getResult("constant-propagation") : null;
29423
+ const javaBindings = language === "java" ? scanJavaStringBindings(code) : new Map;
29319
29424
  for (const call of graph.ir.calls) {
29320
- const detection = this.detect(call, language);
29425
+ const detection = this.detect(call, language, constProp, javaBindings);
29321
29426
  if (!detection)
29322
29427
  continue;
29323
29428
  const { algorithm, api } = detection;
@@ -29340,12 +29445,12 @@ class WeakHashPass {
29340
29445
  }
29341
29446
  return { findings };
29342
29447
  }
29343
- detect(call, language) {
29448
+ detect(call, language, constProp, javaBindings) {
29344
29449
  const method = call.method_name;
29345
29450
  const receiver = call.receiver ?? "";
29346
29451
  if (language === "java") {
29347
29452
  if (method === "getInstance" && (receiver === "MessageDigest" || receiver.endsWith(".MessageDigest"))) {
29348
- const algo = literalAlgo(call, 0);
29453
+ const algo = resolveJavaAlgo(call, 0, constProp, javaBindings);
29349
29454
  if (algo && WEAK_HASH_NAMES.has(algo)) {
29350
29455
  return { algorithm: algo, api: "MessageDigest.getInstance" };
29351
29456
  }
@@ -29355,6 +29460,9 @@ class WeakHashPass {
29355
29460
  const normalized = algoFromMethod === "sha" ? "sha1" : algoFromMethod;
29356
29461
  return { algorithm: normalized, api: `DigestUtils.${method}` };
29357
29462
  }
29463
+ if (COMMONS_DIGEST_GETTERS[method] && (receiver === "DigestUtils" || receiver.endsWith(".DigestUtils"))) {
29464
+ return { algorithm: COMMONS_DIGEST_GETTERS[method], api: `DigestUtils.${method}` };
29465
+ }
29358
29466
  return null;
29359
29467
  }
29360
29468
  if (language === "python") {
@@ -30789,7 +30897,7 @@ class JwtVerifyDisabledPass {
30789
30897
  out2.push({ pattern: "Algorithm.none()", api: "JWT.require" });
30790
30898
  }
30791
30899
  }
30792
- if (method === "parse" && receiver.includes("parser")) {
30900
+ if (method === "parse" && /\bJwts\s*\.\s*parser\s*\(/.test(receiver)) {
30793
30901
  out2.push({ pattern: "parse() instead of parseClaimsJws()", api: "Jwts.parser().parse" });
30794
30902
  }
30795
30903
  return out2;
@@ -32498,7 +32606,7 @@ var colors = {
32498
32606
  };
32499
32607
 
32500
32608
  // src/version.ts
32501
- var version = "3.75.0";
32609
+ var version = "3.78.0";
32502
32610
 
32503
32611
  // src/formatters.ts
32504
32612
  var SINK_SEVERITY = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cognium-dev",
3
- "version": "3.75.0",
3
+ "version": "3.78.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.75.0"
68
+ "circle-ir": "^3.78.0"
69
69
  },
70
70
  "devDependencies": {
71
71
  "@types/node": "^25.5.0",