cognium-dev 3.157.0 → 3.159.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 +146 -3
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -18898,6 +18898,42 @@ function shouldGateInterproceduralParam(sourceType, enclosingMethod, enclosingTy
18898
18898
  // ../circle-ir/dist/analysis/require-entry-path.js
18899
18899
  var RULE_ID_REQUIRE_ENTRY_PATH = "require-entry-path";
18900
18900
  var MAX_VISITED_METHODS = 2000;
18901
+ var TAINT_FLOW_RULE_IDS = new Set([
18902
+ "sql_injection",
18903
+ "nosql_injection",
18904
+ "command_injection",
18905
+ "path_traversal",
18906
+ "xss",
18907
+ "xxe",
18908
+ "deserialization",
18909
+ "insecure_deserialization",
18910
+ "ldap_injection",
18911
+ "xpath_injection",
18912
+ "ssrf",
18913
+ "open_redirect",
18914
+ "code_injection",
18915
+ "log_injection",
18916
+ "redos",
18917
+ "format_string",
18918
+ "crlf",
18919
+ "mass_assignment",
18920
+ "mybatis_mapper_call",
18921
+ "external_taint_escape",
18922
+ "template_injection",
18923
+ "sql-injection",
18924
+ "nosql-injection",
18925
+ "command-injection",
18926
+ "path-traversal",
18927
+ "ldap-injection",
18928
+ "xpath-injection",
18929
+ "open-redirect",
18930
+ "code-injection",
18931
+ "log-injection",
18932
+ "format-string",
18933
+ "mass-assignment",
18934
+ "template-injection",
18935
+ "insecure-deserialization"
18936
+ ]);
18901
18937
  function applyRequireEntryPath(fileAnalyses, options = {}) {
18902
18938
  const disabledSet = normalizeDisabled(options.disabledPasses);
18903
18939
  if (disabledSet.has(RULE_ID_REQUIRE_ENTRY_PATH))
@@ -19033,6 +19069,8 @@ function collectEntryPointKeys(graph) {
19033
19069
  function classifyFinding(finding, ir, graph, entryPointKeys, profile) {
19034
19070
  if (finding.category !== "security")
19035
19071
  return { action: "keep" };
19072
+ if (!TAINT_FLOW_RULE_IDS.has(finding.rule_id))
19073
+ return { action: "keep" };
19036
19074
  const isHighOrCritical = finding.severity === "high" || finding.severity === "critical";
19037
19075
  const language = (ir.meta.language ?? "").toLowerCase();
19038
19076
  if (language !== "java")
@@ -22478,14 +22516,40 @@ class CrossFilePass {
22478
22516
  });
22479
22517
  }
22480
22518
  }
22519
+ const filteredTaintPaths = taintPaths.filter((tp) => {
22520
+ const sinkIR = projectGraph.getIR(tp.sink.file);
22521
+ if (!sinkIR)
22522
+ return true;
22523
+ const sinkTypeStr = tp.sink.type;
22524
+ if (tp.source.file === tp.sink.file) {
22525
+ const lo = Math.min(tp.source.line, tp.sink.line);
22526
+ const hi = Math.max(tp.source.line, tp.sink.line);
22527
+ for (const san of sinkIR.taint.sanitizers ?? []) {
22528
+ if (san.line < lo || san.line > hi)
22529
+ continue;
22530
+ if (san.sanitizes.includes(sinkTypeStr)) {
22531
+ return false;
22532
+ }
22533
+ }
22534
+ return true;
22535
+ }
22536
+ for (const san of sinkIR.taint.sanitizers ?? []) {
22537
+ if (san.line !== tp.sink.line)
22538
+ continue;
22539
+ if (san.sanitizes.includes(sinkTypeStr)) {
22540
+ return false;
22541
+ }
22542
+ }
22543
+ return true;
22544
+ });
22481
22545
  const typeHierarchy = projectGraph.typeHierarchy.toTypeHierarchyData();
22482
22546
  logger.info("cross-file: complete", {
22483
22547
  totalMs: Date.now() - startMs,
22484
- paths: taintPaths.length,
22548
+ paths: filteredTaintPaths.length,
22485
22549
  crossFileCalls: crossFileCalls.length,
22486
22550
  budgetExceeded: exceeded
22487
22551
  });
22488
- const result = { crossFileCalls, taintPaths, typeHierarchy };
22552
+ const result = { crossFileCalls, taintPaths: filteredTaintPaths, typeHierarchy };
22489
22553
  if (exceeded)
22490
22554
  result.budgetExceeded = true;
22491
22555
  return result;
@@ -23631,6 +23695,7 @@ class LanguageSourcesPass {
23631
23695
  if (language === "java") {
23632
23696
  additionalSanitizers.push(...findJavaSafeJsonParseSanitizers(code));
23633
23697
  additionalSanitizers.push(...findJavaPathNormalizeStartsWithGuardSanitizers(code));
23698
+ additionalSanitizers.push(...findJavaPathGetFileNameSanitizers(code));
23634
23699
  additionalSanitizers.push(...findJavaInlineCrlfStripLogSanitizers(code));
23635
23700
  additionalSanitizers.push(...findJavaArgvFormExecSanitizers(code));
23636
23701
  for (const finding of findJavaPatternFindings(code, graph.ir.meta.file)) {
@@ -25899,6 +25964,48 @@ function findJavaPathNormalizeStartsWithGuardSanitizers(code) {
25899
25964
  }
25900
25965
  return sanitizers;
25901
25966
  }
25967
+ function findJavaPathGetFileNameSanitizers(code) {
25968
+ const sanitizers = [];
25969
+ const lines = code.split(`
25970
+ `);
25971
+ const assignmentRe = /^\s*(?:(?:final\s+)?[A-Za-z_][\w.<>?,\s\[\]]*?\s+)?([A-Za-z_]\w*)\s*=\s*(.+?);\s*$/;
25972
+ const rhsHasGetFileNameRe = /\.\s*getFileName\s*\(\s*\)/;
25973
+ const rhsHasPathsChainRe = /\b(?:Paths\s*\.\s*get|Path\s*\.\s*of)\s*\(/;
25974
+ const candidates = [];
25975
+ for (let i2 = 0;i2 < lines.length; i2++) {
25976
+ const m = assignmentRe.exec(lines[i2]);
25977
+ if (!m)
25978
+ continue;
25979
+ const rhs = m[2];
25980
+ if (!rhsHasGetFileNameRe.test(rhs))
25981
+ continue;
25982
+ if (!rhsHasPathsChainRe.test(rhs))
25983
+ continue;
25984
+ candidates.push({ line: i2 + 1, boundVar: m[1] });
25985
+ }
25986
+ if (candidates.length === 0)
25987
+ return sanitizers;
25988
+ for (const c of candidates) {
25989
+ sanitizers.push({
25990
+ type: "java_path_get_filename",
25991
+ method: "getFileName",
25992
+ line: c.line,
25993
+ sanitizes: ["path_traversal", "external_taint_escape"]
25994
+ });
25995
+ const varRefRe = new RegExp(`\\b${c.boundVar}\\b`);
25996
+ for (let l = c.line;l < lines.length; l++) {
25997
+ if (!varRefRe.test(lines[l]))
25998
+ continue;
25999
+ sanitizers.push({
26000
+ type: "java_path_get_filename",
26001
+ method: "getFileName",
26002
+ line: l + 1,
26003
+ sanitizes: ["path_traversal", "external_taint_escape"]
26004
+ });
26005
+ }
26006
+ }
26007
+ return sanitizers;
26008
+ }
25902
26009
  function findJavaInlineCrlfStripLogSanitizers(code) {
25903
26010
  const sanitizers = [];
25904
26011
  const lines = code.split(`
@@ -30415,6 +30522,30 @@ class SinkFilterPass {
30415
30522
  }
30416
30523
  if (language === "java") {
30417
30524
  const sourceLines = ctx.code.split(`
30525
+ `);
30526
+ filtered = filtered.filter((sink) => {
30527
+ if (sink.type !== "xss")
30528
+ return true;
30529
+ const sinkLineText = sourceLines[sink.line - 1] ?? "";
30530
+ const receiverMatch = sinkLineText.match(/\b(\w+)\s*\.\s*(\w+)\s*\(/);
30531
+ const receiver = receiverMatch?.[1];
30532
+ const method = sink.method ?? receiverMatch?.[2];
30533
+ if ((method === "render" || method === "process" || method === "merge" || method === "renderTo" || method === "apply") && receiver) {
30534
+ const recvType = resolveJavaReceiverType(receiver, sink.line, sourceLines);
30535
+ if (recvType && COMPILED_TEMPLATE_TYPES.has(recvType))
30536
+ return false;
30537
+ if (recvType && TEMPLATE_ENGINE_LITERAL_TARGETS.has(recvType)) {
30538
+ const args2 = extractJavaCallArgs(method, sinkLineText);
30539
+ if (args2 !== null && args2.length >= 1 && isJavaLiteralOrAnnotationAccessor(args2[0])) {
30540
+ return false;
30541
+ }
30542
+ }
30543
+ }
30544
+ return true;
30545
+ });
30546
+ }
30547
+ if (language === "java") {
30548
+ const sourceLines = ctx.code.split(`
30418
30549
  `);
30419
30550
  filtered = filtered.filter((sink) => {
30420
30551
  if (sink.type !== "command_injection")
@@ -38674,10 +38805,22 @@ var TEST_PATH_PATTERNS = [
38674
38805
  /\.spec\.(?:tsx?|jsx?|mjs|cjs)$/i,
38675
38806
  /\.test\.(?:java|kt)$/i
38676
38807
  ];
38808
+ var JVM_TEST_FILE_PATTERNS = [
38809
+ /(?:^|\/)[A-Za-z_]\w*(?:Test|Tests|Spec|IT|ITCase|TestCase)\.(?:java|kt|scala|groovy)$/,
38810
+ /(?:^|\/)[A-Za-z_]\w*\.(?:test|spec)\.(?:java|kt|scala|groovy)$/i
38811
+ ];
38812
+ var JVM_SOURCE_FILE_RE = /\.(?:java|kt|scala|groovy)$/i;
38677
38813
  function isTestPath(filepath) {
38678
38814
  if (!filepath)
38679
38815
  return false;
38680
38816
  const normalized = filepath.replace(/\\/g, "/");
38817
+ if (JVM_SOURCE_FILE_RE.test(normalized)) {
38818
+ for (const pattern of JVM_TEST_FILE_PATTERNS) {
38819
+ if (pattern.test(normalized))
38820
+ return true;
38821
+ }
38822
+ return false;
38823
+ }
38681
38824
  for (const pattern of TEST_PATH_PATTERNS) {
38682
38825
  if (pattern.test(normalized))
38683
38826
  return true;
@@ -43608,7 +43751,7 @@ var colors = {
43608
43751
  };
43609
43752
 
43610
43753
  // src/version.ts
43611
- var version = "3.157.0";
43754
+ var version = "3.159.0";
43612
43755
 
43613
43756
  // src/formatters.ts
43614
43757
  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.157.0",
3
+ "version": "3.159.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.157.0"
69
+ "circle-ir": "^3.159.0"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@types/node": "^25.5.0",