cognium-dev 3.125.0 → 3.128.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 +245 -1
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -22607,6 +22607,7 @@ class LanguageSourcesPass {
22607
22607
  additionalSanitizers.push(...findPythonRegexAllowlistWrapperSanitizers(code));
22608
22608
  additionalSanitizers.push(...findPythonSetMembershipXssGuardSanitizers(code));
22609
22609
  additionalSanitizers.push(...findPythonDefusedXmlSanitizers(code));
22610
+ additionalSanitizers.push(...findPythonJinjaAutoescapeSanitizers(code));
22610
22611
  const pyMisconfigFindings = findPythonPatternFindings(code, graph.ir.meta.file);
22611
22612
  for (const finding of pyMisconfigFindings) {
22612
22613
  ctx.addFinding(finding);
@@ -22615,6 +22616,7 @@ class LanguageSourcesPass {
22615
22616
  if (language === "rust") {
22616
22617
  additionalSanitizers.push(...findRustSetAllowlistGuardSanitizers(code));
22617
22618
  additionalSanitizers.push(...findRustCanonicalizeGuardSanitizers(code));
22619
+ additionalSanitizers.push(...findRustArgvCommandSanitizers(code));
22618
22620
  const rustMisconfigFindings = findRustPatternFindings(code, graph.ir.meta.file);
22619
22621
  for (const finding of rustMisconfigFindings) {
22620
22622
  ctx.addFinding(finding);
@@ -22625,9 +22627,13 @@ class LanguageSourcesPass {
22625
22627
  additionalSanitizers.push(...findJsCryptoHashSanitizers(code));
22626
22628
  additionalSanitizers.push(...findJsCsvFormulaPrefixSanitizers(code));
22627
22629
  additionalSanitizers.push(...findJsWrapperFunctionSanitizers(code));
22630
+ additionalSanitizers.push(...findJsSsrfAllowlistGuardSanitizers(code));
22628
22631
  }
22629
22632
  if (language === "java") {
22630
22633
  additionalSanitizers.push(...findJavaSafeJsonParseSanitizers(code));
22634
+ additionalSanitizers.push(...findJavaPathNormalizeStartsWithGuardSanitizers(code));
22635
+ additionalSanitizers.push(...findJavaInlineCrlfStripLogSanitizers(code));
22636
+ additionalSanitizers.push(...findJavaArgvFormExecSanitizers(code));
22631
22637
  }
22632
22638
  if (language === "python" || language === "javascript" || language === "typescript" || language === "go") {
22633
22639
  const exfilFindings = findExternalSecretExfiltrationFindings(code, graph.ir.meta.file, language);
@@ -24487,6 +24493,244 @@ function findJsWrapperFunctionSanitizers(code) {
24487
24493
  }
24488
24494
  return sanitizers;
24489
24495
  }
24496
+ function findJsSsrfAllowlistGuardSanitizers(code) {
24497
+ const sanitizers = [];
24498
+ const lines = code.split(`
24499
+ `);
24500
+ const urlAliasToHostAlias = new Map;
24501
+ const urlAliasDecl = /\b(?:const|let|var)\s+([A-Za-z_]\w*)\s*=\s*new\s+URL\s*\(\s*([A-Za-z_][\w.[\]'"`]*)\s*\)/;
24502
+ const hostAliasDecl = /\b(?:const|let|var)\s+([A-Za-z_]\w*)\s*=\s*([A-Za-z_]\w*)\.(?:hostname|host)\b/;
24503
+ const hostFromUrl = new Map;
24504
+ for (const line of lines) {
24505
+ const ua = urlAliasDecl.exec(line);
24506
+ if (ua)
24507
+ urlAliasToHostAlias.set(ua[1], ua[2]);
24508
+ const ha = hostAliasDecl.exec(line);
24509
+ if (ha)
24510
+ hostFromUrl.set(ha[1], ha[2]);
24511
+ }
24512
+ const allowlistName = /^(?:[A-Z][A-Z0-9_]+|.*?(allowed|accepted|whitelist|permitted|valid|approved).*)$/i;
24513
+ const guardHas = /if\s*\(\s*!\s*([A-Za-z_]\w*)\s*\.\s*(?:has|includes)\s*\(\s*([A-Za-z_]\w*)(?:\s*\.\s*(?:hostname|host))?\s*\)\s*\)/;
24514
+ const guardIndexOf = /if\s*\(\s*([A-Za-z_]\w*)\s*\.\s*indexOf\s*\(\s*([A-Za-z_]\w*)(?:\s*\.\s*(?:hostname|host))?\s*\)\s*<\s*0\s*\)/;
24515
+ const terminator = /\b(return|throw|res\s*\.\s*status\s*\([^)]*\)\s*\.\s*(?:send|end|json)\s*\()/;
24516
+ for (let i2 = 0;i2 < lines.length; i2++) {
24517
+ const line = lines[i2];
24518
+ let m = guardHas.exec(line);
24519
+ let allow = null;
24520
+ let guardedVar = null;
24521
+ if (m) {
24522
+ allow = m[1];
24523
+ guardedVar = m[2];
24524
+ } else {
24525
+ m = guardIndexOf.exec(line);
24526
+ if (m) {
24527
+ allow = m[1];
24528
+ guardedVar = m[2];
24529
+ }
24530
+ }
24531
+ if (!allow || !guardedVar)
24532
+ continue;
24533
+ if (!allowlistName.test(allow))
24534
+ continue;
24535
+ let bodyHasTerminator = false;
24536
+ let blockEnd = -1;
24537
+ const maxScan = Math.min(lines.length, i2 + 26);
24538
+ let braceDepth = 0;
24539
+ let started = false;
24540
+ for (let j = i2;j < maxScan; j++) {
24541
+ const ln = lines[j];
24542
+ for (const ch of ln) {
24543
+ if (ch === "{") {
24544
+ braceDepth++;
24545
+ started = true;
24546
+ } else if (ch === "}") {
24547
+ braceDepth--;
24548
+ if (started && braceDepth === 0) {
24549
+ blockEnd = j;
24550
+ break;
24551
+ }
24552
+ }
24553
+ }
24554
+ if (started && j > i2 && terminator.test(ln))
24555
+ bodyHasTerminator = true;
24556
+ if (blockEnd !== -1)
24557
+ break;
24558
+ }
24559
+ if (!started)
24560
+ continue;
24561
+ if (blockEnd === -1)
24562
+ continue;
24563
+ if (!bodyHasTerminator)
24564
+ continue;
24565
+ const safeNames = new Set([guardedVar]);
24566
+ if (hostFromUrl.has(guardedVar)) {
24567
+ safeNames.add(hostFromUrl.get(guardedVar));
24568
+ }
24569
+ for (const [hostName, urlName] of hostFromUrl) {
24570
+ if (urlName === guardedVar)
24571
+ safeNames.add(hostName);
24572
+ }
24573
+ const refRes = [...safeNames].map((n) => new RegExp(`\\b${n}\\b`));
24574
+ for (let l = blockEnd + 2;l <= lines.length; l++) {
24575
+ const lineText = lines[l - 1];
24576
+ if (!refRes.some((re) => re.test(lineText)))
24577
+ continue;
24578
+ sanitizers.push({
24579
+ type: "js_ssrf_allowlist_guard",
24580
+ method: "if",
24581
+ line: l,
24582
+ sanitizes: ["ssrf", "external_taint_escape"]
24583
+ });
24584
+ }
24585
+ }
24586
+ return sanitizers;
24587
+ }
24588
+ function findJavaPathNormalizeStartsWithGuardSanitizers(code) {
24589
+ const sanitizers = [];
24590
+ const lines = code.split(`
24591
+ `);
24592
+ const resolveNormalizeRe = /\b([A-Za-z_]\w*)\s*=\s*([A-Za-z_]\w*)\s*\.\s*resolve\s*\([^)]*\)\s*\.\s*normalize\s*\(\s*\)/;
24593
+ const startsWithGuardRe = (varName, rootName) => new RegExp(`if\\s*\\(\\s*!\\s*${varName}\\s*\\.\\s*startsWith\\s*\\(\\s*${rootName}\\s*\\)\\s*\\)`);
24594
+ const terminatorRe = /\b(throw|return)\b/;
24595
+ const candidates = [];
24596
+ for (let i2 = 0;i2 < lines.length; i2++) {
24597
+ const m = resolveNormalizeRe.exec(lines[i2]);
24598
+ if (!m)
24599
+ continue;
24600
+ candidates.push({ line: i2 + 1, fullVar: m[1], rootVar: m[2] });
24601
+ }
24602
+ if (candidates.length === 0)
24603
+ return sanitizers;
24604
+ for (const c of candidates) {
24605
+ const guardRe = startsWithGuardRe(c.fullVar, c.rootVar);
24606
+ let guardLine = -1;
24607
+ for (let l = c.line;l < Math.min(lines.length, c.line + 6); l++) {
24608
+ if (!guardRe.test(lines[l]))
24609
+ continue;
24610
+ if (terminatorRe.test(lines[l]) || l + 1 < lines.length && terminatorRe.test(lines[l + 1])) {
24611
+ guardLine = l + 1;
24612
+ break;
24613
+ }
24614
+ }
24615
+ if (guardLine < 0)
24616
+ continue;
24617
+ const varRefRe = new RegExp(`\\b${c.fullVar}\\b`);
24618
+ sanitizers.push({
24619
+ type: "java_path_normalize_startswith_guard",
24620
+ method: "normalize",
24621
+ line: c.line,
24622
+ sanitizes: ["path_traversal", "external_taint_escape"]
24623
+ });
24624
+ for (let l = c.line;l < lines.length; l++) {
24625
+ if (!varRefRe.test(lines[l]))
24626
+ continue;
24627
+ sanitizers.push({
24628
+ type: "java_path_normalize_startswith_guard",
24629
+ method: "normalize",
24630
+ line: l + 1,
24631
+ sanitizes: ["path_traversal", "external_taint_escape"]
24632
+ });
24633
+ }
24634
+ }
24635
+ return sanitizers;
24636
+ }
24637
+ function findJavaInlineCrlfStripLogSanitizers(code) {
24638
+ const sanitizers = [];
24639
+ const lines = code.split(`
24640
+ `);
24641
+ const logCallStart = /\b(?:log|logger|LOG|LOGGER|slog|LOGGER_)\s*\.\s*(?:info|warn|error|debug|trace|fatal|severe|warning|fine|finer|finest|config)\s*\(/;
24642
+ const crlfReplaceAll = /\.\s*replaceAll\s*\(\s*"\[[^"]*\\\\?[rnt][^"]*\]"/;
24643
+ const crlfReplaceChar = /\.\s*replace\s*\(\s*'(?:\\\\?[rnt])'\s*,/;
24644
+ for (let i2 = 0;i2 < lines.length; i2++) {
24645
+ const text = lines[i2];
24646
+ if (!logCallStart.test(text))
24647
+ continue;
24648
+ if (!crlfReplaceAll.test(text) && !crlfReplaceChar.test(text))
24649
+ continue;
24650
+ sanitizers.push({
24651
+ type: "java_inline_crlf_strip_log",
24652
+ method: "replaceAll",
24653
+ line: i2 + 1,
24654
+ sanitizes: ["log_injection", "external_taint_escape"]
24655
+ });
24656
+ }
24657
+ return sanitizers;
24658
+ }
24659
+ function findJavaArgvFormExecSanitizers(code) {
24660
+ const sanitizers = [];
24661
+ const lines = code.split(`
24662
+ `);
24663
+ const argvExecRe = /\.\s*exec\s*\(\s*new\s+String\s*\[\s*\]\s*\{/;
24664
+ const argvPbRe = /\bnew\s+ProcessBuilder\s*\(\s*new\s+String\s*\[\s*\]\s*\{/;
24665
+ for (let i2 = 0;i2 < lines.length; i2++) {
24666
+ const text = lines[i2];
24667
+ if (!argvExecRe.test(text) && !argvPbRe.test(text))
24668
+ continue;
24669
+ sanitizers.push({
24670
+ type: "java_argv_form_exec",
24671
+ method: "exec",
24672
+ line: i2 + 1,
24673
+ sanitizes: ["command_injection", "external_taint_escape"]
24674
+ });
24675
+ }
24676
+ return sanitizers;
24677
+ }
24678
+ function findRustArgvCommandSanitizers(code) {
24679
+ const sanitizers = [];
24680
+ const lines = code.split(`
24681
+ `);
24682
+ const argvCommandRe = /\bCommand\s*::\s*new\s*\(\s*"[^"]*"\s*\)\s*\.\s*arg\s*\(/;
24683
+ const shellArgvRe = /\bCommand\s*::\s*new\s*\(\s*"(?:sh|bash|zsh|ksh|dash|cmd(?:\.exe)?|powershell|pwsh)"\s*\)\s*\.\s*arg\s*\(\s*"-c"/;
24684
+ for (let i2 = 0;i2 < lines.length; i2++) {
24685
+ const text = lines[i2];
24686
+ if (!argvCommandRe.test(text))
24687
+ continue;
24688
+ if (shellArgvRe.test(text))
24689
+ continue;
24690
+ sanitizers.push({
24691
+ type: "rust_argv_command",
24692
+ method: "arg",
24693
+ line: i2 + 1,
24694
+ sanitizes: ["command_injection", "external_taint_escape"]
24695
+ });
24696
+ }
24697
+ return sanitizers;
24698
+ }
24699
+ function findPythonJinjaAutoescapeSanitizers(code) {
24700
+ const sanitizers = [];
24701
+ const lines = code.split(`
24702
+ `);
24703
+ const envAssignRe = /\b([A-Za-z_]\w*)\s*=\s*Environment\s*\(/;
24704
+ const autoescapeOnRe = /\bautoescape\s*=/;
24705
+ const autoescapeOffRe = /\bautoescape\s*=\s*(?:False|None|0)\b/;
24706
+ const envVars = new Set;
24707
+ for (let i2 = 0;i2 < lines.length; i2++) {
24708
+ const m = envAssignRe.exec(lines[i2]);
24709
+ if (!m)
24710
+ continue;
24711
+ if (!autoescapeOnRe.test(lines[i2]))
24712
+ continue;
24713
+ if (autoescapeOffRe.test(lines[i2]))
24714
+ continue;
24715
+ envVars.add(m[1]);
24716
+ }
24717
+ if (envVars.size === 0)
24718
+ return sanitizers;
24719
+ for (const envVar of envVars) {
24720
+ const renderChainRe = new RegExp(`\\b${envVar}\\s*\\.\\s*get_template\\s*\\([^)]*\\)\\s*\\.\\s*render\\s*\\(`);
24721
+ for (let i2 = 0;i2 < lines.length; i2++) {
24722
+ if (!renderChainRe.test(lines[i2]))
24723
+ continue;
24724
+ sanitizers.push({
24725
+ type: "python_jinja_autoescape",
24726
+ method: "render",
24727
+ line: i2 + 1,
24728
+ sanitizes: ["xss", "external_taint_escape"]
24729
+ });
24730
+ }
24731
+ }
24732
+ return sanitizers;
24733
+ }
24490
24734
  function collectEnvSecretVars(lines, language) {
24491
24735
  const out2 = new Map;
24492
24736
  for (let i2 = 0;i2 < lines.length; i2++) {
@@ -38028,7 +38272,7 @@ var colors = {
38028
38272
  };
38029
38273
 
38030
38274
  // src/version.ts
38031
- var version = "3.125.0";
38275
+ var version = "3.128.0";
38032
38276
 
38033
38277
  // src/formatters.ts
38034
38278
  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": "3.125.0",
3
+ "version": "3.128.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": "^3.125.0"
69
+ "circle-ir": "^3.128.0"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@types/node": "^25.5.0",