cognium-dev 4.6.0 → 4.7.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 +106 -4
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -12332,7 +12332,7 @@ var DEFAULT_SINKS = [
12332
12332
  { method: "ExecuteScalarAsync", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12333
12333
  { method: "ExecuteReaderAsync", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12334
12334
  { method: "ExecuteNonQueryAsync", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12335
- { method: "Start", class: "Process", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12335
+ { method: "Start", class: "Process", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1], languages: ["csharp"] },
12336
12336
  { method: "ProcessStartInfo", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1], languages: ["csharp"] },
12337
12337
  { method: "ReadAllText", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
12338
12338
  { method: "ReadAllBytes", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
@@ -12366,6 +12366,11 @@ var DEFAULT_SINKS = [
12366
12366
  { method: "HtmlString", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0], languages: ["csharp"] },
12367
12367
  { method: "DirectorySearcher", type: "ldap_injection", cwe: "CWE-90", severity: "high", arg_positions: [0], languages: ["csharp"] },
12368
12368
  { method: "DirectoryEntry", type: "ldap_injection", cwe: "CWE-90", severity: "high", arg_positions: [0], languages: ["csharp"] },
12369
+ { method: "Redirect", type: "open_redirect", cwe: "CWE-601", severity: "medium", arg_positions: [0], languages: ["csharp"] },
12370
+ { method: "RedirectPermanent", type: "open_redirect", cwe: "CWE-601", severity: "medium", arg_positions: [0], languages: ["csharp"] },
12371
+ { method: "AddHeader", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["csharp"] },
12372
+ { method: "AppendHeader", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["csharp"] },
12373
+ { method: "Parse", class: "BsonDocument", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["csharp"] },
12369
12374
  { method: "SelectSingleNode", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
12370
12375
  { method: "SelectNodes", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
12371
12376
  { method: "Compile", class: "XPathExpression", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
@@ -25638,12 +25643,13 @@ function findCSharpRequestSources(sourceCode, language) {
25638
25643
  const assignRe = /^\s*(?:var\s+|[A-Za-z_][\w.<>\[\]]*\s+)?([A-Za-z_]\w*)\s*=\s*(.+?);?\s*$/;
25639
25644
  const requestReadRe = /\bRequest\s*\.\s*(?:Query|Form|Headers|Cookies|QueryString|RouteValues|Body|Files|Params)\b/;
25640
25645
  const consoleReadRe = /\bConsole\s*\.\s*ReadLine\s*\(/;
25646
+ const envReadRe = /\bEnvironment\s*\.\s*GetEnvironmentVariables?\s*(?:\(|\[)/;
25641
25647
  for (let i2 = 0;i2 < lines.length; i2++) {
25642
25648
  const m = assignRe.exec(lines[i2]);
25643
25649
  if (!m)
25644
25650
  continue;
25645
25651
  const [, varName, rhs] = m;
25646
- const type = requestReadRe.test(rhs) ? "http_param" : consoleReadRe.test(rhs) ? "io_input" : null;
25652
+ const type = requestReadRe.test(rhs) ? "http_param" : consoleReadRe.test(rhs) ? "io_input" : envReadRe.test(rhs) ? "env_input" : null;
25647
25653
  if (!type)
25648
25654
  continue;
25649
25655
  const lineNumber = i2 + 1;
@@ -33360,7 +33366,10 @@ class SinkFilterPass {
33360
33366
  const sourceLines = ctx.code.split(`
33361
33367
  `);
33362
33368
  const sanitizedByType = csharpSanitizedVarsByType(ctx.code);
33369
+ const xxeHardened = /\bXmlResolver\s*=\s*null\b/.test(ctx.code) || /\bDtdProcessing\s*=\s*(?:DtdProcessing\s*\.\s*)?(?:Prohibit|Ignore)\b/.test(ctx.code);
33363
33370
  filtered = filtered.filter((sink) => {
33371
+ if (sink.type === "xxe" && xxeHardened)
33372
+ return false;
33364
33373
  const sinkLineText = sourceLines[sink.line - 1] ?? "";
33365
33374
  for (const { re, type } of CSHARP_SANITIZER_RES) {
33366
33375
  if (type === sink.type && re.test(sinkLineText))
@@ -37234,6 +37243,8 @@ function isPublicMethod(method, language) {
37234
37243
  switch (language) {
37235
37244
  case "java":
37236
37245
  return method.modifiers.includes("public");
37246
+ case "csharp":
37247
+ return method.modifiers.includes("public");
37237
37248
  case "javascript":
37238
37249
  case "typescript":
37239
37250
  case "tsx":
@@ -37256,7 +37267,7 @@ class MissingPublicDocPass {
37256
37267
  if (UTIL_DIR_RE.test(graph.ir.meta.file)) {
37257
37268
  return { missingDocMethods: [], missingDocTypes: [] };
37258
37269
  }
37259
- if (!["java", "javascript", "typescript", "tsx", "python"].includes(language)) {
37270
+ if (!["java", "javascript", "typescript", "tsx", "python", "csharp"].includes(language)) {
37260
37271
  return { missingDocMethods: [], missingDocTypes: [] };
37261
37272
  }
37262
37273
  const lines = code.split(`
@@ -42231,6 +42242,30 @@ var WEAK_HASH_NAMES = new Set([
42231
42242
  "sha-1",
42232
42243
  "sha1"
42233
42244
  ]);
42245
+ var CSHARP_WEAK_HASH_CLASSES = new Set(["MD5", "SHA1"]);
42246
+ var CSHARP_HASH_FACTORY_RECEIVERS = new Set([
42247
+ "HashAlgorithm",
42248
+ "KeyedHashAlgorithm",
42249
+ "HMAC",
42250
+ "CryptoConfig"
42251
+ ]);
42252
+ var CSHARP_WEAK_HASH_CTORS = {
42253
+ MD5CryptoServiceProvider: "md5",
42254
+ MD5Cng: "md5",
42255
+ SHA1CryptoServiceProvider: "sha1",
42256
+ SHA1Managed: "sha1",
42257
+ SHA1Cng: "sha1",
42258
+ HMACMD5: "md5",
42259
+ HMACSHA1: "sha1"
42260
+ };
42261
+ function csharpWeakHashAlgo(cleaned) {
42262
+ if (!cleaned)
42263
+ return null;
42264
+ const base = (cleaned.split(".").pop() ?? cleaned).replace(/^hmac/, "");
42265
+ if (base === "sha")
42266
+ return "sha1";
42267
+ return WEAK_HASH_NAMES.has(base) ? base : null;
42268
+ }
42234
42269
  var COMMONS_DIGEST_METHODS = new Set([
42235
42270
  "md2",
42236
42271
  "md2Hex",
@@ -42401,6 +42436,20 @@ class WeakHashPass {
42401
42436
  }
42402
42437
  return null;
42403
42438
  }
42439
+ if (language === "csharp") {
42440
+ if ((method === "Create" || method === "HashData") && CSHARP_WEAK_HASH_CLASSES.has(receiver)) {
42441
+ return { algorithm: receiver.toLowerCase(), api: `${receiver}.${method}` };
42442
+ }
42443
+ if ((method === "Create" || method === "CreateFromName") && CSHARP_HASH_FACTORY_RECEIVERS.has(receiver)) {
42444
+ const algo = csharpWeakHashAlgo(literalAlgo(call, 0));
42445
+ if (algo)
42446
+ return { algorithm: algo, api: `${receiver}.${method}` };
42447
+ }
42448
+ if (call.is_constructor && CSHARP_WEAK_HASH_CTORS[method]) {
42449
+ return { algorithm: CSHARP_WEAK_HASH_CTORS[method], api: `new ${method}()` };
42450
+ }
42451
+ return null;
42452
+ }
42404
42453
  return null;
42405
42454
  }
42406
42455
  }
@@ -42457,6 +42506,30 @@ var WEAK_CIPHER_BASES = new Set([
42457
42506
  "seed",
42458
42507
  "cast5"
42459
42508
  ]);
42509
+ var CSHARP_WEAK_CIPHER_CLASSES = new Set(["DES", "TripleDES", "RC2", "RC4"]);
42510
+ var CSHARP_CIPHER_FACTORY_RECEIVERS = new Set(["SymmetricAlgorithm", "CryptoConfig"]);
42511
+ var CSHARP_WEAK_CIPHER_CTORS = {
42512
+ DESCryptoServiceProvider: "des",
42513
+ TripleDESCryptoServiceProvider: "3des",
42514
+ RC2CryptoServiceProvider: "rc2"
42515
+ };
42516
+ var CSHARP_RSA_FACTORY_CLASSES = new Set(["RSA", "DSA"]);
42517
+ var CSHARP_RSA_CTORS = new Set([
42518
+ "RSACryptoServiceProvider",
42519
+ "DSACryptoServiceProvider",
42520
+ "RSACng",
42521
+ "DSACng"
42522
+ ]);
42523
+ function csharpWeakCipher(cleaned) {
42524
+ if (!cleaned)
42525
+ return null;
42526
+ const base = (cleaned.split(".").pop() ?? cleaned).toLowerCase();
42527
+ if (base === "tripledes" || base === "desede")
42528
+ return "3des";
42529
+ if (base === "arc4")
42530
+ return "rc4";
42531
+ return WEAK_CIPHER_BASES.has(base) ? base : null;
42532
+ }
42460
42533
  function classifyJavaCipherSpec(spec) {
42461
42534
  const parts2 = spec.split("/").map((p) => p.trim().toLowerCase());
42462
42535
  const base = parts2[0] ?? "";
@@ -42880,6 +42953,35 @@ class WeakCryptoPass {
42880
42953
  }
42881
42954
  return out2;
42882
42955
  }
42956
+ if (language === "csharp") {
42957
+ if (method === "Create" && CSHARP_WEAK_CIPHER_CLASSES.has(receiver)) {
42958
+ const base = receiver === "TripleDES" ? "3des" : receiver.toLowerCase();
42959
+ out2.push({ issue: "weak-cipher", detail: base, api: `${receiver}.Create` });
42960
+ }
42961
+ if ((method === "Create" || method === "CreateFromName") && CSHARP_CIPHER_FACTORY_RECEIVERS.has(receiver)) {
42962
+ const base = csharpWeakCipher(literalAlgo2(call, 0));
42963
+ if (base)
42964
+ out2.push({ issue: "weak-cipher", detail: base, api: `${receiver}.${method}` });
42965
+ }
42966
+ if (call.is_constructor && CSHARP_WEAK_CIPHER_CTORS[method]) {
42967
+ out2.push({ issue: "weak-cipher", detail: CSHARP_WEAK_CIPHER_CTORS[method], api: `new ${method}()` });
42968
+ }
42969
+ const rsaFactory = method === "Create" && CSHARP_RSA_FACTORY_CLASSES.has(receiver);
42970
+ const rsaCtor = call.is_constructor && CSHARP_RSA_CTORS.has(method);
42971
+ if (rsaFactory || rsaCtor) {
42972
+ const sizeArg = call.arguments.find((a) => a.position === 0);
42973
+ const expr = (sizeArg?.literal ?? sizeArg?.expression ?? "").trim();
42974
+ const n = parseInt(expr, 10);
42975
+ if (Number.isFinite(n) && n > 0 && n < 2048) {
42976
+ out2.push({
42977
+ issue: "weak-rsa-key",
42978
+ detail: String(n),
42979
+ api: rsaCtor ? `new ${method}()` : `${receiver}.Create`
42980
+ });
42981
+ }
42982
+ }
42983
+ return out2;
42984
+ }
42883
42985
  return out2;
42884
42986
  }
42885
42987
  }
@@ -47900,7 +48002,7 @@ var colors = {
47900
48002
  };
47901
48003
 
47902
48004
  // src/version.ts
47903
- var version = "4.6.0";
48005
+ var version = "4.7.0";
47904
48006
 
47905
48007
  // src/formatters.ts
47906
48008
  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": "4.6.0",
3
+ "version": "4.7.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": "^4.6.0"
69
+ "circle-ir": "^4.7.0"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@types/node": "^25.5.0",