cognium-dev 4.6.0 → 4.7.1

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 +205 -20
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -9350,13 +9350,15 @@ function computeChains(defs, uses) {
9350
9350
  existing.push(use);
9351
9351
  usesByLine.set(use.line, existing);
9352
9352
  }
9353
+ const seenChains = new Set;
9353
9354
  for (const def of defs) {
9354
9355
  if (def.kind === "local") {
9355
9356
  const usesOnLine = usesByLine.get(def.line) ?? [];
9356
9357
  for (const use of usesOnLine) {
9357
9358
  if (use.def_id !== null && use.def_id !== def.id) {
9358
- const exists = chains.some((c) => c.from_def === use.def_id && c.to_def === def.id && c.via === use.variable);
9359
- if (!exists) {
9359
+ const key = `${use.def_id}\x00${def.id}\x00${use.variable}`;
9360
+ if (!seenChains.has(key)) {
9361
+ seenChains.add(key);
9360
9362
  chains.push({
9361
9363
  from_def: use.def_id,
9362
9364
  to_def: def.id,
@@ -11531,7 +11533,7 @@ var DEFAULT_SINKS = [
11531
11533
  { method: "validate", type: "xss", cwe: "CWE-79", severity: "medium", arg_positions: [0] },
11532
11534
  { method: "startElement", class: "ContentHandler", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0, 1, 2] },
11533
11535
  { method: "characters", class: "ContentHandler", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0] },
11534
- { method: "output", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0] },
11536
+ { method: "output", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0], exclude_languages: ["rust"] },
11535
11537
  { method: "setOutput", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0] },
11536
11538
  { method: "writeAttribute", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0, 1] },
11537
11539
  { method: "startElement", class: "MagicSAXFilter", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0, 1, 2] },
@@ -12332,7 +12334,7 @@ var DEFAULT_SINKS = [
12332
12334
  { method: "ExecuteScalarAsync", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12333
12335
  { method: "ExecuteReaderAsync", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["csharp"] },
12334
12336
  { 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"] },
12337
+ { method: "Start", class: "Process", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1], languages: ["csharp"] },
12336
12338
  { method: "ProcessStartInfo", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0, 1], languages: ["csharp"] },
12337
12339
  { method: "ReadAllText", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
12338
12340
  { method: "ReadAllBytes", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0], languages: ["csharp"] },
@@ -12366,6 +12368,11 @@ var DEFAULT_SINKS = [
12366
12368
  { method: "HtmlString", type: "xss", cwe: "CWE-79", severity: "high", arg_positions: [0], languages: ["csharp"] },
12367
12369
  { method: "DirectorySearcher", type: "ldap_injection", cwe: "CWE-90", severity: "high", arg_positions: [0], languages: ["csharp"] },
12368
12370
  { method: "DirectoryEntry", type: "ldap_injection", cwe: "CWE-90", severity: "high", arg_positions: [0], languages: ["csharp"] },
12371
+ { method: "Redirect", type: "open_redirect", cwe: "CWE-601", severity: "medium", arg_positions: [0], languages: ["csharp"] },
12372
+ { method: "RedirectPermanent", type: "open_redirect", cwe: "CWE-601", severity: "medium", arg_positions: [0], languages: ["csharp"] },
12373
+ { method: "AddHeader", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["csharp"] },
12374
+ { method: "AppendHeader", type: "crlf", cwe: "CWE-113", severity: "medium", arg_positions: [1], languages: ["csharp"] },
12375
+ { method: "Parse", class: "BsonDocument", type: "nosql_injection", cwe: "CWE-943", severity: "high", arg_positions: [0], languages: ["csharp"] },
12369
12376
  { method: "SelectSingleNode", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
12370
12377
  { method: "SelectNodes", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
12371
12378
  { method: "Compile", class: "XPathExpression", type: "xpath_injection", cwe: "CWE-643", severity: "high", arg_positions: [0], languages: ["csharp"] },
@@ -25027,6 +25034,7 @@ class LanguageSourcesPass {
25027
25034
  additionalSources.push(...findSetterChainSources(types, code, language));
25028
25035
  additionalSources.push(...findJavaScriptAssignmentSources(code, language));
25029
25036
  additionalSources.push(...findCSharpRequestSources(code, language));
25037
+ additionalSources.push(...findGoArgvSources(code, language));
25030
25038
  const jsDOMSinks = findJavaScriptDOMSinks(code, language);
25031
25039
  for (const s of jsDOMSinks) {
25032
25040
  const alreadyExists = additionalSinks.some((x) => x.line === s.line && x.cwe === s.cwe);
@@ -25629,6 +25637,35 @@ function findSetterChainSources(types, sourceCode, language) {
25629
25637
  }
25630
25638
  return sources;
25631
25639
  }
25640
+ function findGoArgvSources(sourceCode, language) {
25641
+ if (language !== "go")
25642
+ return [];
25643
+ const sources = [];
25644
+ const lines = sourceCode.split(`
25645
+ `);
25646
+ const rangeRe = /\bfor\b[^;{]*?,\s*([A-Za-z_]\w*)\s*:?=\s*range\s+os\.Args\b/;
25647
+ const assignRe = /\b([A-Za-z_]\w*)\s*:?=\s*os\.Args\b/;
25648
+ for (let i2 = 0;i2 < lines.length; i2++) {
25649
+ const line = lines[i2];
25650
+ const rm = rangeRe.exec(line);
25651
+ const m = rm ?? assignRe.exec(line);
25652
+ if (!m)
25653
+ continue;
25654
+ const varName = m[1];
25655
+ const lineNumber = i2 + 1;
25656
+ if (sources.some((s) => s.line === lineNumber && s.variable === varName))
25657
+ continue;
25658
+ sources.push({
25659
+ type: "io_input",
25660
+ location: `${varName} = os.Args`,
25661
+ severity: "high",
25662
+ line: lineNumber,
25663
+ confidence: 1,
25664
+ variable: varName
25665
+ });
25666
+ }
25667
+ return sources;
25668
+ }
25632
25669
  function findCSharpRequestSources(sourceCode, language) {
25633
25670
  if (language !== "csharp")
25634
25671
  return [];
@@ -25638,12 +25675,13 @@ function findCSharpRequestSources(sourceCode, language) {
25638
25675
  const assignRe = /^\s*(?:var\s+|[A-Za-z_][\w.<>\[\]]*\s+)?([A-Za-z_]\w*)\s*=\s*(.+?);?\s*$/;
25639
25676
  const requestReadRe = /\bRequest\s*\.\s*(?:Query|Form|Headers|Cookies|QueryString|RouteValues|Body|Files|Params)\b/;
25640
25677
  const consoleReadRe = /\bConsole\s*\.\s*ReadLine\s*\(/;
25678
+ const envReadRe = /\bEnvironment\s*\.\s*GetEnvironmentVariables?\s*(?:\(|\[)/;
25641
25679
  for (let i2 = 0;i2 < lines.length; i2++) {
25642
25680
  const m = assignRe.exec(lines[i2]);
25643
25681
  if (!m)
25644
25682
  continue;
25645
25683
  const [, varName, rhs] = m;
25646
- const type = requestReadRe.test(rhs) ? "http_param" : consoleReadRe.test(rhs) ? "io_input" : null;
25684
+ const type = requestReadRe.test(rhs) ? "http_param" : consoleReadRe.test(rhs) ? "io_input" : envReadRe.test(rhs) ? "env_input" : null;
25647
25685
  if (!type)
25648
25686
  continue;
25649
25687
  const lineNumber = i2 + 1;
@@ -26591,7 +26629,7 @@ function findBashTaintSources(sourceCode, dfg) {
26591
26629
  });
26592
26630
  }
26593
26631
  }
26594
- const envRe = /\$([A-Z][A-Z0-9_]{2,})|\$\{([A-Z][A-Z0-9_]{2,})\}/g;
26632
+ const envRe = /\$([A-Z][A-Z0-9_]{2,})|\$\{([A-Z][A-Z0-9_]{2,})(?:[:#%/^,@!*+?=-][^}]*)?\}/g;
26595
26633
  let em;
26596
26634
  while ((em = envRe.exec(line)) !== null) {
26597
26635
  const envVar = em[1] ?? em[2];
@@ -33360,7 +33398,10 @@ class SinkFilterPass {
33360
33398
  const sourceLines = ctx.code.split(`
33361
33399
  `);
33362
33400
  const sanitizedByType = csharpSanitizedVarsByType(ctx.code);
33401
+ const xxeHardened = /\bXmlResolver\s*=\s*null\b/.test(ctx.code) || /\bDtdProcessing\s*=\s*(?:DtdProcessing\s*\.\s*)?(?:Prohibit|Ignore)\b/.test(ctx.code);
33363
33402
  filtered = filtered.filter((sink) => {
33403
+ if (sink.type === "xxe" && xxeHardened)
33404
+ return false;
33364
33405
  const sinkLineText = sourceLines[sink.line - 1] ?? "";
33365
33406
  for (const { re, type } of CSHARP_SANITIZER_RES) {
33366
33407
  if (type === sink.type && re.test(sinkLineText))
@@ -36410,6 +36451,26 @@ function analyzeInterprocedural2(graphOrTypes, callsOrSources, dfgOrSinks, sourc
36410
36451
  "Command",
36411
36452
  "CommandContext"
36412
36453
  ]);
36454
+ const ormQueryBuilderMethods = new Set([
36455
+ "findMany",
36456
+ "findFirst",
36457
+ "findUnique",
36458
+ "findUniqueOrThrow",
36459
+ "findFirstOrThrow",
36460
+ "findOne",
36461
+ "findAll",
36462
+ "findByPk",
36463
+ "findAndCountAll",
36464
+ "findBy",
36465
+ "findOneBy",
36466
+ "where",
36467
+ "andWhere",
36468
+ "orWhere",
36469
+ "whereIn",
36470
+ "whereNot",
36471
+ "first",
36472
+ "bind"
36473
+ ]);
36413
36474
  const sanitizerMethods = new Set;
36414
36475
  for (const san of sanitizers) {
36415
36476
  sanitizerMethods.add(san.method);
@@ -36434,7 +36495,7 @@ function analyzeInterprocedural2(graphOrTypes, callsOrSources, dfgOrSinks, sourc
36434
36495
  }
36435
36496
  const targetMethod = getMethodNode(methodNodes, call.method_name);
36436
36497
  if (!targetMethod) {
36437
- if (taintedArgPositions.length > 0 && !collectionMethods.has(call.method_name) && !sanitizerMethods.has(call.method_name) && !safeUtilityMethods.has(call.method_name)) {
36498
+ if (taintedArgPositions.length > 0 && !collectionMethods.has(call.method_name) && !sanitizerMethods.has(call.method_name) && !safeUtilityMethods.has(call.method_name) && !ormQueryBuilderMethods.has(call.method_name)) {
36438
36499
  const isBash = graph.ir.meta.language === "bash";
36439
36500
  const bashSafeBuiltins = new Set([
36440
36501
  "echo",
@@ -37234,6 +37295,8 @@ function isPublicMethod(method, language) {
37234
37295
  switch (language) {
37235
37296
  case "java":
37236
37297
  return method.modifiers.includes("public");
37298
+ case "csharp":
37299
+ return method.modifiers.includes("public");
37237
37300
  case "javascript":
37238
37301
  case "typescript":
37239
37302
  case "tsx":
@@ -37256,7 +37319,7 @@ class MissingPublicDocPass {
37256
37319
  if (UTIL_DIR_RE.test(graph.ir.meta.file)) {
37257
37320
  return { missingDocMethods: [], missingDocTypes: [] };
37258
37321
  }
37259
- if (!["java", "javascript", "typescript", "tsx", "python"].includes(language)) {
37322
+ if (!["java", "javascript", "typescript", "tsx", "python", "csharp"].includes(language)) {
37260
37323
  return { missingDocMethods: [], missingDocTypes: [] };
37261
37324
  }
37262
37325
  const lines = code.split(`
@@ -38222,6 +38285,7 @@ var SKIP_NAMES3 = new Set([
38222
38285
  "unknown",
38223
38286
  "bigint"
38224
38287
  ]);
38288
+ var EMPTY_LINES = [];
38225
38289
 
38226
38290
  class UnusedVariablePass {
38227
38291
  name = "unused-variable";
@@ -38236,6 +38300,35 @@ class UnusedVariablePass {
38236
38300
  `);
38237
38301
  const unusedVars = [];
38238
38302
  const reported = new Set;
38303
+ const defsByVar = new Map;
38304
+ for (const d of graph.ir.dfg.defs) {
38305
+ const arr = defsByVar.get(d.variable);
38306
+ if (arr)
38307
+ arr.push(d);
38308
+ else
38309
+ defsByVar.set(d.variable, [d]);
38310
+ }
38311
+ const nameLines = new Map;
38312
+ const idRe = /[A-Za-z_][A-Za-z0-9_]*/g;
38313
+ for (let i2 = 0;i2 < codeLines.length; i2++) {
38314
+ const line = codeLines[i2];
38315
+ idRe.lastIndex = 0;
38316
+ let seen = null;
38317
+ let m;
38318
+ while ((m = idRe.exec(line)) !== null) {
38319
+ const w = m[0];
38320
+ if (seen === null)
38321
+ seen = new Set;
38322
+ if (seen.has(w))
38323
+ continue;
38324
+ seen.add(w);
38325
+ const arr = nameLines.get(w);
38326
+ if (arr)
38327
+ arr.push(i2 + 1);
38328
+ else
38329
+ nameLines.set(w, [i2 + 1]);
38330
+ }
38331
+ }
38239
38332
  for (const def of graph.ir.dfg.defs) {
38240
38333
  if (def.kind !== "local")
38241
38334
  continue;
@@ -38252,19 +38345,20 @@ class UnusedVariablePass {
38252
38345
  const uses = graph.usesOfDef(def.id);
38253
38346
  if (uses.length > 0)
38254
38347
  continue;
38255
- const otherDefs = graph.ir.dfg.defs.filter((d) => d.variable === variable && d.id !== def.id);
38348
+ const otherDefs = (defsByVar.get(variable) ?? []).filter((d) => d.id !== def.id);
38256
38349
  const otherDefLines = new Set(otherDefs.map((d) => d.line));
38257
- const escapedName = variable.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
38258
- const namePattern = new RegExp(`\\b${escapedName}\\b`);
38350
+ const plainName = /^[A-Za-z_][A-Za-z0-9_]*$/.test(variable);
38351
+ const idxLines = plainName ? nameLines.get(variable) ?? EMPTY_LINES : null;
38352
+ const namePattern = plainName ? null : new RegExp(`\\b${variable.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`);
38259
38353
  if (otherDefLines.size === 0) {
38260
- const usedElsewhere = codeLines.some((line, idx) => idx !== def.line - 1 && namePattern.test(line));
38354
+ const usedElsewhere = idxLines !== null ? idxLines.some((ln) => ln !== def.line) : codeLines.some((line, idx) => idx !== def.line - 1 && namePattern.test(line));
38261
38355
  if (usedElsewhere)
38262
38356
  continue;
38263
38357
  } else {
38264
38358
  const lineText2 = codeLines[def.line - 1] ?? "";
38265
38359
  const isTrueDeclaration = /\b(?:let|const|var)\s+[\w{[]/.test(lineText2) || /\b(?:int|long|float|double|boolean|byte|char|short|var|final)\b/.test(lineText2) || /\b[A-Z]\w*(?:<[^>]*>)?\s+\w/.test(lineText2) || /\blet\s+(?:mut\s+)?\w/.test(lineText2);
38266
38360
  if (isTrueDeclaration) {
38267
- const usedBeforeNextDef = codeLines.some((line, idx) => {
38361
+ const usedBeforeNextDef = idxLines !== null ? idxLines.some((ln) => ln !== def.line && !otherDefLines.has(ln) && !otherDefs.some((d) => d.line > def.line && d.line < ln)) : codeLines.some((line, idx) => {
38268
38362
  const lineNum = idx + 1;
38269
38363
  if (lineNum === def.line || otherDefLines.has(lineNum))
38270
38364
  return false;
@@ -38275,7 +38369,7 @@ class UnusedVariablePass {
38275
38369
  if (usedBeforeNextDef)
38276
38370
  continue;
38277
38371
  } else {
38278
- const usedOnNonDefLine = codeLines.some((line, idx) => {
38372
+ const usedOnNonDefLine = idxLines !== null ? idxLines.some((ln) => ln !== def.line && !otherDefLines.has(ln)) : codeLines.some((line, idx) => {
38279
38373
  const lineNum = idx + 1;
38280
38374
  return lineNum !== def.line && !otherDefLines.has(lineNum) && namePattern.test(line);
38281
38375
  });
@@ -42231,6 +42325,30 @@ var WEAK_HASH_NAMES = new Set([
42231
42325
  "sha-1",
42232
42326
  "sha1"
42233
42327
  ]);
42328
+ var CSHARP_WEAK_HASH_CLASSES = new Set(["MD5", "SHA1"]);
42329
+ var CSHARP_HASH_FACTORY_RECEIVERS = new Set([
42330
+ "HashAlgorithm",
42331
+ "KeyedHashAlgorithm",
42332
+ "HMAC",
42333
+ "CryptoConfig"
42334
+ ]);
42335
+ var CSHARP_WEAK_HASH_CTORS = {
42336
+ MD5CryptoServiceProvider: "md5",
42337
+ MD5Cng: "md5",
42338
+ SHA1CryptoServiceProvider: "sha1",
42339
+ SHA1Managed: "sha1",
42340
+ SHA1Cng: "sha1",
42341
+ HMACMD5: "md5",
42342
+ HMACSHA1: "sha1"
42343
+ };
42344
+ function csharpWeakHashAlgo(cleaned) {
42345
+ if (!cleaned)
42346
+ return null;
42347
+ const base = (cleaned.split(".").pop() ?? cleaned).replace(/^hmac/, "");
42348
+ if (base === "sha")
42349
+ return "sha1";
42350
+ return WEAK_HASH_NAMES.has(base) ? base : null;
42351
+ }
42234
42352
  var COMMONS_DIGEST_METHODS = new Set([
42235
42353
  "md2",
42236
42354
  "md2Hex",
@@ -42401,6 +42519,20 @@ class WeakHashPass {
42401
42519
  }
42402
42520
  return null;
42403
42521
  }
42522
+ if (language === "csharp") {
42523
+ if ((method === "Create" || method === "HashData") && CSHARP_WEAK_HASH_CLASSES.has(receiver)) {
42524
+ return { algorithm: receiver.toLowerCase(), api: `${receiver}.${method}` };
42525
+ }
42526
+ if ((method === "Create" || method === "CreateFromName") && CSHARP_HASH_FACTORY_RECEIVERS.has(receiver)) {
42527
+ const algo = csharpWeakHashAlgo(literalAlgo(call, 0));
42528
+ if (algo)
42529
+ return { algorithm: algo, api: `${receiver}.${method}` };
42530
+ }
42531
+ if (call.is_constructor && CSHARP_WEAK_HASH_CTORS[method]) {
42532
+ return { algorithm: CSHARP_WEAK_HASH_CTORS[method], api: `new ${method}()` };
42533
+ }
42534
+ return null;
42535
+ }
42404
42536
  return null;
42405
42537
  }
42406
42538
  }
@@ -42457,6 +42589,30 @@ var WEAK_CIPHER_BASES = new Set([
42457
42589
  "seed",
42458
42590
  "cast5"
42459
42591
  ]);
42592
+ var CSHARP_WEAK_CIPHER_CLASSES = new Set(["DES", "TripleDES", "RC2", "RC4"]);
42593
+ var CSHARP_CIPHER_FACTORY_RECEIVERS = new Set(["SymmetricAlgorithm", "CryptoConfig"]);
42594
+ var CSHARP_WEAK_CIPHER_CTORS = {
42595
+ DESCryptoServiceProvider: "des",
42596
+ TripleDESCryptoServiceProvider: "3des",
42597
+ RC2CryptoServiceProvider: "rc2"
42598
+ };
42599
+ var CSHARP_RSA_FACTORY_CLASSES = new Set(["RSA", "DSA"]);
42600
+ var CSHARP_RSA_CTORS = new Set([
42601
+ "RSACryptoServiceProvider",
42602
+ "DSACryptoServiceProvider",
42603
+ "RSACng",
42604
+ "DSACng"
42605
+ ]);
42606
+ function csharpWeakCipher(cleaned) {
42607
+ if (!cleaned)
42608
+ return null;
42609
+ const base = (cleaned.split(".").pop() ?? cleaned).toLowerCase();
42610
+ if (base === "tripledes" || base === "desede")
42611
+ return "3des";
42612
+ if (base === "arc4")
42613
+ return "rc4";
42614
+ return WEAK_CIPHER_BASES.has(base) ? base : null;
42615
+ }
42460
42616
  function classifyJavaCipherSpec(spec) {
42461
42617
  const parts2 = spec.split("/").map((p) => p.trim().toLowerCase());
42462
42618
  const base = parts2[0] ?? "";
@@ -42880,6 +43036,35 @@ class WeakCryptoPass {
42880
43036
  }
42881
43037
  return out2;
42882
43038
  }
43039
+ if (language === "csharp") {
43040
+ if (method === "Create" && CSHARP_WEAK_CIPHER_CLASSES.has(receiver)) {
43041
+ const base = receiver === "TripleDES" ? "3des" : receiver.toLowerCase();
43042
+ out2.push({ issue: "weak-cipher", detail: base, api: `${receiver}.Create` });
43043
+ }
43044
+ if ((method === "Create" || method === "CreateFromName") && CSHARP_CIPHER_FACTORY_RECEIVERS.has(receiver)) {
43045
+ const base = csharpWeakCipher(literalAlgo2(call, 0));
43046
+ if (base)
43047
+ out2.push({ issue: "weak-cipher", detail: base, api: `${receiver}.${method}` });
43048
+ }
43049
+ if (call.is_constructor && CSHARP_WEAK_CIPHER_CTORS[method]) {
43050
+ out2.push({ issue: "weak-cipher", detail: CSHARP_WEAK_CIPHER_CTORS[method], api: `new ${method}()` });
43051
+ }
43052
+ const rsaFactory = method === "Create" && CSHARP_RSA_FACTORY_CLASSES.has(receiver);
43053
+ const rsaCtor = call.is_constructor && CSHARP_RSA_CTORS.has(method);
43054
+ if (rsaFactory || rsaCtor) {
43055
+ const sizeArg = call.arguments.find((a) => a.position === 0);
43056
+ const expr = (sizeArg?.literal ?? sizeArg?.expression ?? "").trim();
43057
+ const n = parseInt(expr, 10);
43058
+ if (Number.isFinite(n) && n > 0 && n < 2048) {
43059
+ out2.push({
43060
+ issue: "weak-rsa-key",
43061
+ detail: String(n),
43062
+ api: rsaCtor ? `new ${method}()` : `${receiver}.Create`
43063
+ });
43064
+ }
43065
+ }
43066
+ return out2;
43067
+ }
42883
43068
  return out2;
42884
43069
  }
42885
43070
  }
@@ -43610,9 +43795,7 @@ class InfoDisclosureStacktracePass {
43610
43795
  // ../circle-ir/dist/analysis/passes/unrestricted-file-upload-pass.js
43611
43796
  var UPLOAD_NAME_RE = /(?:getOriginalFilename|getSubmittedFileName|originalname|originalName|\.filename|\.Filename|FileHeader\.Filename|UploadFile)/;
43612
43797
  var FILE_SAFE_CALL_RE = /(?:secure_filename|FilenameUtils\.getExtension|\.lastIndexOf\(['"]\.['"]\)|ALLOWED_EXT|ALLOWED_EXTENSIONS|allowedExtensions|\bfileFilter\b|filepath\.Ext|path\.extname)/;
43613
- function lineWindow(code, startLine, endLine) {
43614
- const lines = code.split(`
43615
- `);
43798
+ function lineWindow(lines, startLine, endLine) {
43616
43799
  const s = Math.max(0, startLine - 1);
43617
43800
  const e = Math.min(lines.length, endLine);
43618
43801
  return lines.slice(s, e).join(`
@@ -43636,10 +43819,12 @@ class UnrestrictedFileUploadPass {
43636
43819
  const { graph, language, code } = ctx;
43637
43820
  const file = graph.ir.meta.file;
43638
43821
  const findings = [];
43822
+ const codeLines = code.split(`
43823
+ `);
43639
43824
  const safeFunctionRanges = [];
43640
43825
  for (const t of graph.ir.types) {
43641
43826
  for (const m of t.methods) {
43642
- const body2 = lineWindow(code, m.start_line, m.end_line);
43827
+ const body2 = lineWindow(codeLines, m.start_line, m.end_line);
43643
43828
  if (FILE_SAFE_CALL_RE.test(body2)) {
43644
43829
  safeFunctionRanges.push({ start: m.start_line, end: m.end_line });
43645
43830
  }
@@ -43650,7 +43835,7 @@ class UnrestrictedFileUploadPass {
43650
43835
  if (line >= r.start && line <= r.end)
43651
43836
  return true;
43652
43837
  }
43653
- const win = lineWindow(code, Math.max(1, line - 20), line + 5);
43838
+ const win = lineWindow(codeLines, Math.max(1, line - 20), line + 5);
43654
43839
  return FILE_SAFE_CALL_RE.test(win);
43655
43840
  };
43656
43841
  if (language === "java") {
@@ -47900,7 +48085,7 @@ var colors = {
47900
48085
  };
47901
48086
 
47902
48087
  // src/version.ts
47903
- var version = "4.6.0";
48088
+ var version = "4.7.1";
47904
48089
 
47905
48090
  // src/formatters.ts
47906
48091
  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.1",
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.1"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@types/node": "^25.5.0",