cognium-dev 3.168.0 → 3.174.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 +276 -98
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -6861,33 +6861,33 @@ function detectLanguage2(tree) {
6861
6861
  return "python";
6862
6862
  return jsScore > javaScore ? "javascript" : "java";
6863
6863
  }
6864
- function extractImports(tree, language) {
6864
+ function extractImports(tree, language, cache) {
6865
6865
  const effectiveLanguage = language ?? detectLanguage2(tree);
6866
6866
  const isJavaScript = effectiveLanguage === "javascript" || effectiveLanguage === "typescript" || effectiveLanguage === "tsx";
6867
6867
  const isPython = effectiveLanguage === "python";
6868
6868
  const isRust = effectiveLanguage === "rust";
6869
6869
  if (effectiveLanguage === "go") {
6870
- return extractGoImports(tree);
6870
+ return extractGoImports(tree, cache);
6871
6871
  }
6872
6872
  if (isRust) {
6873
- return extractRustImports(tree);
6873
+ return extractRustImports(tree, cache);
6874
6874
  }
6875
6875
  if (isPython) {
6876
- return extractPythonImports(tree);
6876
+ return extractPythonImports(tree, cache);
6877
6877
  }
6878
6878
  if (isJavaScript) {
6879
- return extractJavaScriptImports(tree);
6879
+ return extractJavaScriptImports(tree, cache);
6880
6880
  }
6881
- return extractJavaImports(tree);
6881
+ return extractJavaImports(tree, cache);
6882
6882
  }
6883
- function extractJavaScriptImports(tree) {
6883
+ function extractJavaScriptImports(tree, cache) {
6884
6884
  const imports = [];
6885
- const importStatements = findNodes(tree.rootNode, "import_statement");
6885
+ const importStatements = getNodesFromCache(tree.rootNode, "import_statement", cache);
6886
6886
  for (const importStmt of importStatements) {
6887
6887
  const importInfos = extractJSImportInfo(importStmt);
6888
6888
  imports.push(...importInfos);
6889
6889
  }
6890
- const exportStatements = findNodes(tree.rootNode, "export_statement");
6890
+ const exportStatements = getNodesFromCache(tree.rootNode, "export_statement", cache);
6891
6891
  for (const exportStmt of exportStatements) {
6892
6892
  const sourceNode = exportStmt.childForFieldName("source");
6893
6893
  if (!sourceNode)
@@ -6903,13 +6903,13 @@ function extractJavaScriptImports(tree) {
6903
6903
  line_number: exportStmt.startPosition.row + 1
6904
6904
  });
6905
6905
  }
6906
- const requireCalls = findRequireCalls(tree);
6906
+ const requireCalls = findRequireCalls(tree, cache);
6907
6907
  imports.push(...requireCalls);
6908
6908
  return imports;
6909
6909
  }
6910
- function extractJavaImports(tree) {
6910
+ function extractJavaImports(tree, cache) {
6911
6911
  const imports = [];
6912
- const importDecls = findNodes(tree.rootNode, "import_declaration");
6912
+ const importDecls = getNodesFromCache(tree.rootNode, "import_declaration", cache);
6913
6913
  for (const importDecl of importDecls) {
6914
6914
  const importInfo = extractJavaImportInfo(importDecl);
6915
6915
  if (importInfo) {
@@ -7061,9 +7061,9 @@ function extractJSImportInfo(node) {
7061
7061
  }
7062
7062
  return imports;
7063
7063
  }
7064
- function findRequireCalls(tree) {
7064
+ function findRequireCalls(tree, cache) {
7065
7065
  const imports = [];
7066
- const callExpressions = findNodes(tree.rootNode, "call_expression");
7066
+ const callExpressions = getNodesFromCache(tree.rootNode, "call_expression", cache);
7067
7067
  for (const call of callExpressions) {
7068
7068
  const funcNode = call.childForFieldName("function");
7069
7069
  if (!funcNode || getNodeText(funcNode) !== "require")
@@ -7182,14 +7182,14 @@ function parseImportPath(fullPath, isWildcard) {
7182
7182
  fromPackage: fullPath.substring(0, lastDot)
7183
7183
  };
7184
7184
  }
7185
- function extractPythonImports(tree) {
7185
+ function extractPythonImports(tree, cache) {
7186
7186
  const imports = [];
7187
- const importStatements = findNodes(tree.rootNode, "import_statement");
7187
+ const importStatements = getNodesFromCache(tree.rootNode, "import_statement", cache);
7188
7188
  for (const stmt of importStatements) {
7189
7189
  const importInfos = extractPythonImportStatement(stmt);
7190
7190
  imports.push(...importInfos);
7191
7191
  }
7192
- const importFromStatements = findNodes(tree.rootNode, "import_from_statement");
7192
+ const importFromStatements = getNodesFromCache(tree.rootNode, "import_from_statement", cache);
7193
7193
  for (const stmt of importFromStatements) {
7194
7194
  const importInfos = extractPythonFromImportStatement(stmt);
7195
7195
  imports.push(...importInfos);
@@ -7285,9 +7285,9 @@ function extractPythonFromImportStatement(node) {
7285
7285
  }
7286
7286
  return imports;
7287
7287
  }
7288
- function extractRustImports(tree) {
7288
+ function extractRustImports(tree, cache) {
7289
7289
  const imports = [];
7290
- const useDecls = findNodes(tree.rootNode, "use_declaration");
7290
+ const useDecls = getNodesFromCache(tree.rootNode, "use_declaration", cache);
7291
7291
  for (const useDecl of useDecls) {
7292
7292
  const useImports = extractRustUseDecl(useDecl);
7293
7293
  imports.push(...useImports);
@@ -7433,9 +7433,9 @@ function extractRustScopedUseList(node, lineNumber) {
7433
7433
  }
7434
7434
  return imports;
7435
7435
  }
7436
- function extractGoImports(tree) {
7436
+ function extractGoImports(tree, cache) {
7437
7437
  const imports = [];
7438
- const importDecls = findNodes(tree.rootNode, "import_declaration");
7438
+ const importDecls = getNodesFromCache(tree.rootNode, "import_declaration", cache);
7439
7439
  for (const decl of importDecls) {
7440
7440
  const singleSpec = findGoChildByType(decl, "import_spec");
7441
7441
  if (singleSpec) {
@@ -7576,7 +7576,7 @@ function detectLanguage3(tree) {
7576
7576
  }
7577
7577
  return jsScore > javaScore ? "javascript" : "java";
7578
7578
  }
7579
- function buildCFG(tree, language) {
7579
+ function buildCFG(tree, language, cache) {
7580
7580
  const effectiveLanguage = language ?? detectLanguage3(tree);
7581
7581
  const isJavaScript = effectiveLanguage === "javascript" || effectiveLanguage === "typescript" || effectiveLanguage === "tsx";
7582
7582
  const allBlocks = [];
@@ -7590,11 +7590,11 @@ function buildCFG(tree, language) {
7590
7590
  }
7591
7591
  if (isJavaScript) {
7592
7592
  const functions = [
7593
- ...findNodes(tree.rootNode, "function_declaration"),
7594
- ...findNodes(tree.rootNode, "arrow_function"),
7595
- ...findNodes(tree.rootNode, "method_definition"),
7596
- ...findNodes(tree.rootNode, "function"),
7597
- ...findNodes(tree.rootNode, "function_expression")
7593
+ ...getNodesFromCache(tree.rootNode, "function_declaration", cache),
7594
+ ...getNodesFromCache(tree.rootNode, "arrow_function", cache),
7595
+ ...getNodesFromCache(tree.rootNode, "method_definition", cache),
7596
+ ...getNodesFromCache(tree.rootNode, "function", cache),
7597
+ ...getNodesFromCache(tree.rootNode, "function_expression", cache)
7598
7598
  ];
7599
7599
  for (const func2 of functions) {
7600
7600
  const body2 = func2.childForFieldName("body");
@@ -7617,8 +7617,8 @@ function buildCFG(tree, language) {
7617
7617
  }
7618
7618
  } else {
7619
7619
  const methods = [
7620
- ...findNodes(tree.rootNode, "method_declaration"),
7621
- ...findNodes(tree.rootNode, "constructor_declaration")
7620
+ ...getNodesFromCache(tree.rootNode, "method_declaration", cache),
7621
+ ...getNodesFromCache(tree.rootNode, "constructor_declaration", cache)
7622
7622
  ];
7623
7623
  for (const method of methods) {
7624
7624
  const body2 = method.childForFieldName("body");
@@ -10507,7 +10507,51 @@ var DEFAULT_SOURCES = [
10507
10507
  { method: "recv", class: "TcpStream", type: "network_input", severity: "high", return_tainted: true },
10508
10508
  { method: "read", class: "TcpStream", type: "network_input", severity: "high", return_tainted: true },
10509
10509
  { method: "read_to_end", class: "TcpStream", type: "network_input", severity: "high", return_tainted: true },
10510
- { method: "read_to_string", class: "TcpStream", type: "network_input", severity: "high", return_tainted: true }
10510
+ { method: "read_to_string", class: "TcpStream", type: "network_input", severity: "high", return_tainted: true },
10511
+ { method_annotation: "Query", type: "http_body", severity: "high", languages: ["javascript", "typescript"] },
10512
+ { method_annotation: "Mutation", type: "http_body", severity: "high", languages: ["javascript", "typescript"] },
10513
+ { method_annotation: "Subscription", type: "http_body", severity: "high", languages: ["javascript", "typescript"] },
10514
+ { method_annotation: "FieldResolver", type: "http_body", severity: "high", languages: ["javascript", "typescript"] },
10515
+ { method_annotation: "ResolveField", type: "http_body", severity: "high", languages: ["javascript", "typescript"] },
10516
+ { annotation: "Arg", type: "http_param", severity: "high", param_tainted: true, languages: ["javascript", "typescript"] },
10517
+ { annotation: "Args", type: "http_param", severity: "high", param_tainted: true, languages: ["javascript", "typescript"] },
10518
+ { method_annotation: "strawberry.field", type: "http_body", severity: "high", languages: ["python"] },
10519
+ { method_annotation: "strawberry.mutation", type: "http_body", severity: "high", languages: ["python"] },
10520
+ { method_annotation: "strawberry.subscription", type: "http_body", severity: "high", languages: ["python"] },
10521
+ { method_annotation: "DgsQuery", type: "http_body", severity: "high", languages: ["java"] },
10522
+ { method_annotation: "DgsMutation", type: "http_body", severity: "high", languages: ["java"] },
10523
+ { method_annotation: "DgsSubscription", type: "http_body", severity: "high", languages: ["java"] },
10524
+ { method_annotation: "DgsData", type: "http_body", severity: "high", languages: ["java"] },
10525
+ { method_annotation: "GraphQLQuery", type: "http_body", severity: "high", languages: ["java"] },
10526
+ { method_annotation: "GraphQLMutation", type: "http_body", severity: "high", languages: ["java"] },
10527
+ { annotation: "InputArgument", type: "http_param", severity: "high", param_tainted: true, languages: ["java"] },
10528
+ { annotation: "GraphQLArgument", type: "http_param", severity: "high", param_tainted: true, languages: ["java"] },
10529
+ { method: "invocation_metadata", type: "http_header", severity: "high", return_tainted: true, languages: ["python"] },
10530
+ { method: "get", class: "Metadata", type: "http_header", severity: "high", return_tainted: true, languages: ["javascript", "typescript"] },
10531
+ { method: "getMap", class: "Metadata", type: "http_header", severity: "high", return_tainted: true, languages: ["javascript", "typescript"] },
10532
+ { method: "FromIncomingContext", class: "metadata", type: "http_header", severity: "high", return_tainted: true, languages: ["go"] },
10533
+ { method: "get", class: "Metadata", type: "http_header", severity: "high", return_tainted: true, languages: ["java"] },
10534
+ { method: "get", class: "Redis", type: "db_input", severity: "medium", return_tainted: true, languages: ["python"] },
10535
+ { method: "hget", class: "Redis", type: "db_input", severity: "medium", return_tainted: true, languages: ["python"] },
10536
+ { method: "mget", class: "Redis", type: "db_input", severity: "medium", return_tainted: true, languages: ["python"] },
10537
+ { method: "lrange", class: "Redis", type: "db_input", severity: "medium", return_tainted: true, languages: ["python"] },
10538
+ { method: "get", class: "cache", type: "db_input", severity: "medium", return_tainted: true, languages: ["python"] },
10539
+ { method: "get_many", class: "cache", type: "db_input", severity: "medium", return_tainted: true, languages: ["python"] },
10540
+ { method: "get", class: "Redis", type: "db_input", severity: "medium", return_tainted: true, languages: ["javascript", "typescript"] },
10541
+ { method: "hget", class: "Redis", type: "db_input", severity: "medium", return_tainted: true, languages: ["javascript", "typescript"] },
10542
+ { method: "mget", class: "Redis", type: "db_input", severity: "medium", return_tainted: true, languages: ["javascript", "typescript"] },
10543
+ { method: "get", class: "Jedis", type: "db_input", severity: "medium", return_tainted: true, languages: ["java"] },
10544
+ { method: "hget", class: "Jedis", type: "db_input", severity: "medium", return_tainted: true, languages: ["java"] },
10545
+ { method: "mget", class: "Jedis", type: "db_input", severity: "medium", return_tainted: true, languages: ["java"] },
10546
+ { method: "decode", class: "jwt", type: "http_header", severity: "high", return_tainted: true, languages: ["python"] },
10547
+ { method: "get_unverified_claims", class: "jwt", type: "http_header", severity: "high", return_tainted: true, languages: ["python"] },
10548
+ { method: "get_unverified_header", class: "jwt", type: "http_header", severity: "high", return_tainted: true, languages: ["python"] },
10549
+ { method: "decode", class: "jwt", type: "http_header", severity: "high", return_tainted: true, languages: ["javascript", "typescript"] },
10550
+ { method: "decode", class: "jsonwebtoken", type: "http_header", severity: "high", return_tainted: true, languages: ["javascript", "typescript"] },
10551
+ { method: "decodeJwt", class: "jose", type: "http_header", severity: "high", return_tainted: true, languages: ["javascript", "typescript"] },
10552
+ { method: "decodeProtectedHeader", class: "jose", type: "http_header", severity: "high", return_tainted: true, languages: ["javascript", "typescript"] },
10553
+ { method: "decode", class: "JWT", type: "http_header", severity: "high", return_tainted: true, languages: ["java"] },
10554
+ { method: "ParseUnverified", class: "jwt", type: "http_header", severity: "high", return_tainted: true, languages: ["go"] }
10511
10555
  ];
10512
10556
  var DEFAULT_SINKS = [
10513
10557
  { method: "executeQuery", class: "Statement", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0] },
@@ -11538,7 +11582,49 @@ var DEFAULT_SINKS = [
11538
11582
  { method: "fetchval", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["python"] },
11539
11583
  { method: "Redirect", class: "http", type: "open_redirect", cwe: "CWE-601", severity: "medium", arg_positions: [2], languages: ["go"] },
11540
11584
  { method: "Do", class: "Client", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["go"] },
11541
- { method: "DoTimeout", class: "Client", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["go"] }
11585
+ { method: "DoTimeout", class: "Client", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [0], languages: ["go"] },
11586
+ { method: "create", class: "Completions", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["python"] },
11587
+ { method: "create", class: "Responses", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["python"] },
11588
+ { method: "create", class: "ChatCompletion", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["python"] },
11589
+ { method: "create", class: "Completion", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["python"] },
11590
+ { method: "create", class: "Messages", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["python"] },
11591
+ { method: "stream", class: "Messages", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["python"] },
11592
+ { method: "completion", class: "litellm", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["python"] },
11593
+ { method: "acompletion", class: "litellm", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["python"] },
11594
+ { method: "invoke", class: "ChatOpenAI", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["python"] },
11595
+ { method: "predict", class: "ChatOpenAI", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["python"] },
11596
+ { method: "stream", class: "ChatOpenAI", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["python"] },
11597
+ { method: "generate", class: "ChatOpenAI", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["python"] },
11598
+ { method: "invoke", class: "ChatAnthropic", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["python"] },
11599
+ { method: "invoke", class: "ChatGoogleGenerativeAI", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["python"] },
11600
+ { method: "run", class: "LLMChain", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["python"] },
11601
+ { method: "invoke", class: "LLMChain", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["python"] },
11602
+ { method: "create", class: "Completions", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["javascript", "typescript"] },
11603
+ { method: "create", class: "Responses", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["javascript", "typescript"] },
11604
+ { method: "create", class: "Messages", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["javascript", "typescript"] },
11605
+ { method: "stream", class: "Messages", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["javascript", "typescript"] },
11606
+ { method: "generateText", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0], languages: ["javascript", "typescript"] },
11607
+ { method: "streamText", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0], languages: ["javascript", "typescript"] },
11608
+ { method: "generateObject", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0], languages: ["javascript", "typescript"] },
11609
+ { method: "streamObject", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0], languages: ["javascript", "typescript"] },
11610
+ { method: "invoke", class: "ChatOpenAI", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["javascript", "typescript"] },
11611
+ { method: "invoke", class: "ChatAnthropic", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["javascript", "typescript"] },
11612
+ { method: "stream", class: "ChatOpenAI", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["javascript", "typescript"] },
11613
+ { method: "generate", class: "ChatLanguageModel", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["java"] },
11614
+ { method: "chat", class: "ChatLanguageModel", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["java"] },
11615
+ { method: "generate", class: "StreamingChatLanguageModel", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["java"] },
11616
+ { method: "chat", class: "StreamingChatLanguageModel", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["java"] },
11617
+ { method: "prompt", class: "ChatClient", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["java"] },
11618
+ { method: "call", class: "ChatClient", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["java"] },
11619
+ { method: "call", class: "ChatModel", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["java"] },
11620
+ { method: "createChatCompletion", class: "OpenAiService", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["java"] },
11621
+ { method: "createCompletion", class: "OpenAiService", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["java"] },
11622
+ { method: "CreateChatCompletion", class: "Client", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["go"] },
11623
+ { method: "CreateCompletion", class: "Client", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["go"] },
11624
+ { method: "CreateChatCompletionStream", class: "Client", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["go"] },
11625
+ { method: "Call", class: "LLM", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["go"] },
11626
+ { method: "Generate", class: "LLM", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["go"] },
11627
+ { method: "GenerateContent", class: "Model", type: "prompt_injection", cwe: "CWE-1427", severity: "high", arg_positions: [0, 1, 2, 3], languages: ["go"] }
11542
11628
  ];
11543
11629
  var DEFAULT_SANITIZERS = [
11544
11630
  { method: "setString", class: "PreparedStatement", removes: ["sql_injection"] },
@@ -11995,6 +12081,9 @@ function findSources(calls, types, patterns, sourceLines, language) {
11995
12081
  for (const param of method.parameters) {
11996
12082
  for (const pattern of patterns) {
11997
12083
  if (pattern.annotation && pattern.param_tainted) {
12084
+ if (pattern.languages && pattern.languages.length > 0 && language !== undefined && !pattern.languages.includes(language)) {
12085
+ continue;
12086
+ }
11998
12087
  if (matchesAnnotation(param.annotations, pattern.annotation)) {
11999
12088
  const paramLine = param.line ?? method.start_line;
12000
12089
  sources.push({
@@ -12016,6 +12105,9 @@ function findSources(calls, types, patterns, sourceLines, language) {
12016
12105
  for (const pattern of patterns) {
12017
12106
  if (!pattern.method_annotation)
12018
12107
  continue;
12108
+ if (pattern.languages && pattern.languages.length > 0 && language !== undefined && !pattern.languages.includes(language)) {
12109
+ continue;
12110
+ }
12019
12111
  if (!matchesAnnotation(method.annotations, pattern.method_annotation))
12020
12112
  continue;
12021
12113
  for (const param of method.parameters) {
@@ -12269,7 +12361,7 @@ function isParameterizedQueryCall(call, pattern) {
12269
12361
  const secondArg = call.arguments.find((a) => a.position === 1);
12270
12362
  if (secondArg?.expression) {
12271
12363
  const expr = secondArg.expression.trim();
12272
- if (expr.startsWith("[")) {
12364
+ if (expr.startsWith("[") && !/^\[\s*\]$/.test(expr)) {
12273
12365
  return true;
12274
12366
  }
12275
12367
  }
@@ -12757,52 +12849,75 @@ function matchesSourcePattern(call, pattern) {
12757
12849
  }
12758
12850
  return false;
12759
12851
  }
12852
+ var JS_SOURCE_PATTERN_CACHE = new WeakMap;
12853
+ var JS_FALLBACK_COMPILED = (() => {
12854
+ const bases = [
12855
+ { base: "req\\.params", sourceType: "http_param" },
12856
+ { base: "req\\.query", sourceType: "http_param" },
12857
+ { base: "req\\.body", sourceType: "http_body" },
12858
+ { base: "req\\.headers", sourceType: "http_header" },
12859
+ { base: "req\\.cookies", sourceType: "http_cookie" },
12860
+ { base: "req\\.url", sourceType: "http_path" },
12861
+ { base: "req\\.path", sourceType: "http_path" },
12862
+ { base: "req\\.originalUrl", sourceType: "http_path" },
12863
+ { base: "req\\.file", sourceType: "file_input" },
12864
+ { base: "req\\.files", sourceType: "file_input" },
12865
+ { base: "request\\.params", sourceType: "http_param" },
12866
+ { base: "request\\.query", sourceType: "http_param" },
12867
+ { base: "request\\.body", sourceType: "http_body" },
12868
+ { base: "request\\.headers", sourceType: "http_header" },
12869
+ { base: "process\\.env", sourceType: "env_input" },
12870
+ { base: "process\\.argv", sourceType: "io_input" },
12871
+ { base: "ctx\\.query", sourceType: "http_param" },
12872
+ { base: "ctx\\.params", sourceType: "http_param" },
12873
+ { base: "ctx\\.request", sourceType: "http_body" }
12874
+ ];
12875
+ const exact = [];
12876
+ const contained = [];
12877
+ for (const { base, sourceType } of bases) {
12878
+ exact.push({ pattern: new RegExp(`^${base}\\b`), sourceType });
12879
+ contained.push({ pattern: new RegExp(`\\b${base}\\b`), sourceType });
12880
+ }
12881
+ return { exact, contained };
12882
+ })();
12883
+ function compileJsSourcePatterns(sourcePatterns) {
12884
+ const cached = JS_SOURCE_PATTERN_CACHE.get(sourcePatterns);
12885
+ if (cached)
12886
+ return cached;
12887
+ const exact = [];
12888
+ const contained = [];
12889
+ for (const sp of sourcePatterns) {
12890
+ if (sp.property && sp.object && sp.property_tainted) {
12891
+ exact.push({
12892
+ pattern: new RegExp(`^${sp.object}\\.${sp.property}\\b`),
12893
+ sourceType: sp.type
12894
+ });
12895
+ contained.push({
12896
+ pattern: new RegExp(`\\b${sp.object}\\.${sp.property}\\b`),
12897
+ sourceType: sp.type
12898
+ });
12899
+ }
12900
+ }
12901
+ const compiled = { exact, contained };
12902
+ JS_SOURCE_PATTERN_CACHE.set(sourcePatterns, compiled);
12903
+ return compiled;
12904
+ }
12760
12905
  function isJavaScriptTaintedArgument(argExpression, sourcePatterns) {
12761
- const exactPatterns = [];
12762
- const containedPatterns = [];
12763
- if (sourcePatterns) {
12764
- for (const sp of sourcePatterns) {
12765
- if (sp.property && sp.object && sp.property_tainted) {
12766
- const exactRegex = new RegExp(`^${sp.object}\\.${sp.property}\\b`);
12767
- exactPatterns.push({ pattern: exactRegex, sourceType: sp.type });
12768
- const containedRegex = new RegExp(`\\b${sp.object}\\.${sp.property}\\b`);
12769
- containedPatterns.push({ pattern: containedRegex, sourceType: sp.type });
12770
- }
12771
- }
12772
- }
12773
- if (exactPatterns.length === 0) {
12774
- const basePatterns = [
12775
- { base: "req\\.params", sourceType: "http_param" },
12776
- { base: "req\\.query", sourceType: "http_param" },
12777
- { base: "req\\.body", sourceType: "http_body" },
12778
- { base: "req\\.headers", sourceType: "http_header" },
12779
- { base: "req\\.cookies", sourceType: "http_cookie" },
12780
- { base: "req\\.url", sourceType: "http_path" },
12781
- { base: "req\\.path", sourceType: "http_path" },
12782
- { base: "req\\.originalUrl", sourceType: "http_path" },
12783
- { base: "req\\.file", sourceType: "file_input" },
12784
- { base: "req\\.files", sourceType: "file_input" },
12785
- { base: "request\\.params", sourceType: "http_param" },
12786
- { base: "request\\.query", sourceType: "http_param" },
12787
- { base: "request\\.body", sourceType: "http_body" },
12788
- { base: "request\\.headers", sourceType: "http_header" },
12789
- { base: "process\\.env", sourceType: "env_input" },
12790
- { base: "process\\.argv", sourceType: "io_input" },
12791
- { base: "ctx\\.query", sourceType: "http_param" },
12792
- { base: "ctx\\.params", sourceType: "http_param" },
12793
- { base: "ctx\\.request", sourceType: "http_body" }
12794
- ];
12795
- for (const { base, sourceType } of basePatterns) {
12796
- exactPatterns.push({ pattern: new RegExp(`^${base}\\b`), sourceType });
12797
- containedPatterns.push({ pattern: new RegExp(`\\b${base}\\b`), sourceType });
12906
+ let compiled;
12907
+ if (sourcePatterns && sourcePatterns.length > 0) {
12908
+ compiled = compileJsSourcePatterns(sourcePatterns);
12909
+ if (compiled.exact.length === 0) {
12910
+ compiled = JS_FALLBACK_COMPILED;
12798
12911
  }
12912
+ } else {
12913
+ compiled = JS_FALLBACK_COMPILED;
12799
12914
  }
12800
- for (const { pattern, sourceType } of exactPatterns) {
12915
+ for (const { pattern, sourceType } of compiled.exact) {
12801
12916
  if (pattern.test(argExpression)) {
12802
12917
  return { isTainted: true, sourceType };
12803
12918
  }
12804
12919
  }
12805
- for (const { pattern, sourceType } of containedPatterns) {
12920
+ for (const { pattern, sourceType } of compiled.contained) {
12806
12921
  if (pattern.test(argExpression)) {
12807
12922
  return { isTainted: true, sourceType };
12808
12923
  }
@@ -15934,6 +16049,20 @@ function walkBackwardDefs(startDefId, chainsByToDef, defById, options = {}) {
15934
16049
  return { visited, lines, hopCapReached };
15935
16050
  }
15936
16051
 
16052
+ // ../circle-ir/dist/analysis/sanitizer-index.js
16053
+ var SANITIZER_SET_CACHE = new WeakMap;
16054
+ function getSanitizesSet(san) {
16055
+ let s = SANITIZER_SET_CACHE.get(san);
16056
+ if (!s) {
16057
+ s = new Set(san.sanitizes);
16058
+ SANITIZER_SET_CACHE.set(san, s);
16059
+ }
16060
+ return s;
16061
+ }
16062
+ function sanitizerCoversSink(san, sinkType) {
16063
+ return getSanitizesSet(san).has(sinkType);
16064
+ }
16065
+
15937
16066
  // ../circle-ir/dist/analysis/taint-propagation.js
15938
16067
  function buildSanitizersByLine(sanitizers) {
15939
16068
  const out2 = new Map;
@@ -16155,7 +16284,7 @@ function checkSanitized(fromLine, toLine, sinkType, sanitizersByLine, ctx) {
16155
16284
  if (sanitizersAtTarget && sanitizersAtTarget.length > 0) {
16156
16285
  for (const san of sanitizersAtTarget) {
16157
16286
  if (isKnownSinkType) {
16158
- if (san.sanitizes.includes(sinkType)) {
16287
+ if (sanitizerCoversSink(san, sinkType)) {
16159
16288
  return { sanitized: true, sanitizer: san };
16160
16289
  }
16161
16290
  } else if (san.sanitizes.length > 0) {
@@ -16175,7 +16304,7 @@ function checkSanitized(fromLine, toLine, sinkType, sanitizersByLine, ctx) {
16175
16304
  continue;
16176
16305
  for (const san of sansAtLine) {
16177
16306
  if (isKnownSinkType) {
16178
- if (san.sanitizes.includes(sinkType)) {
16307
+ if (sanitizerCoversSink(san, sinkType)) {
16179
16308
  return { sanitized: true, sanitizer: san };
16180
16309
  }
16181
16310
  } else if (san.sanitizes.length > 0) {
@@ -23193,7 +23322,7 @@ class CrossFilePass {
23193
23322
  for (const san of sinkIR.taint.sanitizers ?? []) {
23194
23323
  if (san.line < lo || san.line > hi)
23195
23324
  continue;
23196
- if (san.sanitizes.includes(sinkTypeStr)) {
23325
+ if (sanitizerCoversSink(san, sinkTypeStr)) {
23197
23326
  return false;
23198
23327
  }
23199
23328
  }
@@ -23202,7 +23331,7 @@ class CrossFilePass {
23202
23331
  for (const san of sinkIR.taint.sanitizers ?? []) {
23203
23332
  if (san.line !== tp.sink.line)
23204
23333
  continue;
23205
- if (san.sanitizes.includes(sinkTypeStr)) {
23334
+ if (sanitizerCoversSink(san, sinkTypeStr)) {
23206
23335
  return false;
23207
23336
  }
23208
23337
  }
@@ -32083,7 +32212,7 @@ function filterSanitizedSinks(sinks, sanitizers, calls) {
32083
32212
  if (!lineSanitizers || lineSanitizers.length === 0)
32084
32213
  return true;
32085
32214
  for (const san of lineSanitizers) {
32086
- if (san.sanitizes.includes(sink.type)) {
32215
+ if (sanitizerCoversSink(san, sink.type)) {
32087
32216
  const lineCalls = callsByLine.get(sink.line) ?? [];
32088
32217
  for (const call of lineCalls) {
32089
32218
  for (const arg of call.arguments) {
@@ -32573,15 +32702,25 @@ class TaintPropagationPass {
32573
32702
  confidence: flow.confidence,
32574
32703
  sanitized: flow.sanitized
32575
32704
  }));
32705
+ const flowKey = (x) => `${x.source_line}|${x.sink_line}|${x.sink_type}`;
32706
+ const flowKeys = new Set;
32707
+ for (const x of flows)
32708
+ flowKeys.add(flowKey(x));
32709
+ const pushIfNew = (f) => {
32710
+ const k = flowKey(f);
32711
+ if (flowKeys.has(k))
32712
+ return false;
32713
+ flowKeys.add(k);
32714
+ flows.push(f);
32715
+ return true;
32716
+ };
32576
32717
  const arrayFlows = detectArrayElementFlows(calls, sources, sinks, constProp.taintedArrayElements, constProp.unreachableLines, types) ?? [];
32577
32718
  for (const f of arrayFlows) {
32578
- if (!flows.some((x) => x.source_line === f.source_line && x.sink_line === f.sink_line && x.sink_type === f.sink_type)) {
32579
- flows.push(f);
32580
- }
32719
+ pushIfNew(f);
32581
32720
  }
32582
32721
  const collectionFlows = detectCollectionFlows(calls, sources, sinks, constProp.tainted, constProp.unreachableLines, ctx.code, types) ?? [];
32583
32722
  for (const f of collectionFlows) {
32584
- if (flows.some((x) => x.source_line === f.source_line && x.sink_line === f.sink_line && x.sink_type === f.sink_type))
32723
+ if (flowKeys.has(flowKey(f)))
32585
32724
  continue;
32586
32725
  const flowForCheck = {
32587
32726
  source: { line: f.source_line },
@@ -32599,17 +32738,15 @@ class TaintPropagationPass {
32599
32738
  }
32600
32739
  if (isFP)
32601
32740
  continue;
32602
- flows.push(f);
32741
+ pushIfNew(f);
32603
32742
  }
32604
32743
  const paramFlows = detectParameterSinkFlows(types, calls, sources, sinks, constProp.unreachableLines, constProp.tainted, ctx.code) ?? [];
32605
32744
  for (const f of paramFlows) {
32606
- if (!flows.some((x) => x.source_line === f.source_line && x.sink_line === f.sink_line && x.sink_type === f.sink_type)) {
32607
- flows.push(f);
32608
- }
32745
+ pushIfNew(f);
32609
32746
  }
32610
32747
  const exprScanFlows = detectExpressionScanFlows(calls, sources, sinks, sanitizers, constProp.unreachableLines, constProp.tainted, ctx.code, ctx.language) ?? [];
32611
32748
  for (const f of exprScanFlows) {
32612
- if (flows.some((x) => x.source_line === f.source_line && x.sink_line === f.sink_line && x.sink_type === f.sink_type))
32749
+ if (flowKeys.has(flowKey(f)))
32613
32750
  continue;
32614
32751
  const flowForCheck = {
32615
32752
  source: { line: f.source_line },
@@ -32627,7 +32764,7 @@ class TaintPropagationPass {
32627
32764
  }
32628
32765
  if (isFP)
32629
32766
  continue;
32630
- flows.push(f);
32767
+ pushIfNew(f);
32631
32768
  }
32632
32769
  const sanitizedNames = constProp.sanitizedVars;
32633
32770
  let finalFlows = sanitizedNames.size === 0 ? flows : flows.filter((f) => {
@@ -32660,7 +32797,7 @@ class TaintPropagationPass {
32660
32797
  if (!sansAtLine)
32661
32798
  continue;
32662
32799
  for (const san of sansAtLine) {
32663
- if (san.sanitizes.includes(f.sink_type)) {
32800
+ if (sanitizerCoversSink(san, f.sink_type)) {
32664
32801
  return false;
32665
32802
  }
32666
32803
  }
@@ -32670,7 +32807,7 @@ class TaintPropagationPass {
32670
32807
  const sansAtSink = sanitizersByLine.get(f.sink_line);
32671
32808
  if (sansAtSink && sansAtSink.length > 0) {
32672
32809
  for (const san of sansAtSink) {
32673
- if (san.sanitizes.includes(f.sink_type)) {
32810
+ if (sanitizerCoversSink(san, f.sink_type)) {
32674
32811
  return false;
32675
32812
  }
32676
32813
  }
@@ -32696,7 +32833,7 @@ class TaintPropagationPass {
32696
32833
  if (!sansAtLine || sansAtLine.length === 0)
32697
32834
  continue;
32698
32835
  for (const san of sansAtLine) {
32699
- if (san.sanitizes.includes(f.sink_type)) {
32836
+ if (sanitizerCoversSink(san, f.sink_type)) {
32700
32837
  return false;
32701
32838
  }
32702
32839
  }
@@ -34239,7 +34376,7 @@ class InterproceduralPass {
34239
34376
  if (!sansAtLine)
34240
34377
  continue;
34241
34378
  for (const san of sansAtLine) {
34242
- if (san.sanitizes.includes(f.sink_type)) {
34379
+ if (sanitizerCoversSink(san, f.sink_type)) {
34243
34380
  sanitizedSinkKeys.add(`${f.sink_line}:${f.sink_type}`);
34244
34381
  return false;
34245
34382
  }
@@ -34251,7 +34388,7 @@ class InterproceduralPass {
34251
34388
  if (!sansAtSink || sansAtSink.length === 0)
34252
34389
  return true;
34253
34390
  for (const san of sansAtSink) {
34254
- if (san.sanitizes.includes(f.sink_type)) {
34391
+ if (sanitizerCoversSink(san, f.sink_type)) {
34255
34392
  return false;
34256
34393
  }
34257
34394
  }
@@ -43489,7 +43626,9 @@ function getNodeTypesForLanguage(language) {
43489
43626
  "jsx_self_closing_element",
43490
43627
  "jsx_opening_element",
43491
43628
  "jsx_attribute",
43492
- "jsx_expression"
43629
+ "jsx_expression",
43630
+ "function",
43631
+ "function_expression"
43493
43632
  ]);
43494
43633
  case "bash":
43495
43634
  return new Set([
@@ -43543,7 +43682,9 @@ function getNodeTypesForLanguage(language) {
43543
43682
  "field_declaration",
43544
43683
  "import_declaration",
43545
43684
  "interface_declaration",
43546
- "enum_declaration"
43685
+ "enum_declaration",
43686
+ "package_declaration",
43687
+ "local_variable_declaration"
43547
43688
  ]);
43548
43689
  }
43549
43690
  }
@@ -43601,10 +43742,21 @@ async function analyze(code, filePath, language, options = {}) {
43601
43742
  }
43602
43743
  }
43603
43744
  logger.debug("Analyzing file", { filePath, language, parseGrammar, codeLength: code.length });
43745
+ const phaseTimingEnabled = globalThis.__circleIrPassTiming === true;
43746
+ const phaseStart = () => phaseTimingEnabled ? Date.now() : 0;
43747
+ const phaseEnd = (label, t0) => {
43748
+ if (!phaseTimingEnabled)
43749
+ return;
43750
+ console.error(`[phase-timing] ${label} ${Date.now() - t0}ms file=${filePath}`);
43751
+ };
43752
+ const tParse = phaseStart();
43604
43753
  const tree = await parse(code, parseGrammar);
43754
+ phaseEnd("parse", tParse);
43605
43755
  try {
43606
43756
  logger.trace("Parsed AST", { rootNodeType: tree.rootNode.type });
43757
+ const tParseStatus = phaseStart();
43607
43758
  const parseStatus = extractParseStatus(tree);
43759
+ phaseEnd("extractParseStatus", tParseStatus);
43608
43760
  if (parseStatus.has_errors) {
43609
43761
  logger.warn("Partial parse — IR may be incomplete", {
43610
43762
  filePath,
@@ -43613,18 +43765,37 @@ async function analyze(code, filePath, language, options = {}) {
43613
43765
  firstErrorLine: parseStatus.error_locations[0]?.line
43614
43766
  });
43615
43767
  }
43768
+ const tCollect = phaseStart();
43616
43769
  const nodeCache = collectAllNodes(tree.rootNode, getNodeTypesForLanguage(language));
43770
+ phaseEnd("collectAllNodes", tCollect);
43771
+ const tMeta = phaseStart();
43617
43772
  const meta = extractMeta(code, tree, filePath, language);
43618
43773
  if (options.projectProfile !== undefined) {
43619
43774
  meta.projectProfile = makeProfileResolver2(options.projectProfile)(filePath);
43620
43775
  }
43776
+ phaseEnd("extractMeta", tMeta);
43777
+ const tTypes = phaseStart();
43621
43778
  const types = extractTypes(tree, nodeCache, language);
43779
+ phaseEnd("extractTypes", tTypes);
43780
+ const tCalls = phaseStart();
43622
43781
  const calls = extractCalls(tree, nodeCache, language);
43623
- const imports = extractImports(tree, language);
43782
+ phaseEnd("extractCalls", tCalls);
43783
+ const tImports = phaseStart();
43784
+ const imports = extractImports(tree, language, nodeCache);
43785
+ phaseEnd("extractImports", tImports);
43786
+ const tExports = phaseStart();
43624
43787
  const exports = extractExports(types);
43625
- const cfg = buildCFG(tree, language);
43788
+ phaseEnd("extractExports", tExports);
43789
+ const tCFG = phaseStart();
43790
+ const cfg = buildCFG(tree, language, nodeCache);
43791
+ phaseEnd("buildCFG", tCFG);
43792
+ const tDFG = phaseStart();
43626
43793
  const dfg = buildDFG(tree, nodeCache, language);
43794
+ phaseEnd("buildDFG", tDFG);
43795
+ const tRuntime = phaseStart();
43627
43796
  const runtimeRegistrations = extractRuntimeRegistrations(tree, nodeCache, language, imports);
43797
+ phaseEnd("extractRuntimeRegistrations", tRuntime);
43798
+ const tGraph = phaseStart();
43628
43799
  const graph = new CodeGraph({
43629
43800
  meta,
43630
43801
  types,
@@ -43637,6 +43808,7 @@ async function analyze(code, filePath, language, options = {}) {
43637
43808
  unresolved: [],
43638
43809
  enriched: {}
43639
43810
  });
43811
+ phaseEnd("buildCodeGraph", tGraph);
43640
43812
  const config = options.taintConfig ?? getDefaultConfig();
43641
43813
  const disabledPasses = new Set(options.disabledPasses ?? []);
43642
43814
  const passOpts = options.passOptions ?? {};
@@ -44595,7 +44767,7 @@ var colors = {
44595
44767
  };
44596
44768
 
44597
44769
  // src/version.ts
44598
- var version = "3.168.0";
44770
+ var version = "3.174.0";
44599
44771
 
44600
44772
  // src/formatters.ts
44601
44773
  var LIBRARY_API_SURFACE_TAG2 = "library-api-surface:caller-responsibility";
@@ -44630,7 +44802,8 @@ var SINK_SEVERITY = {
44630
44802
  redos: "medium",
44631
44803
  format_string: "high",
44632
44804
  crlf: "medium",
44633
- mass_assignment: "high"
44805
+ mass_assignment: "high",
44806
+ prompt_injection: "high"
44634
44807
  };
44635
44808
  var SINK_CWE = {
44636
44809
  sql_injection: "CWE-89",
@@ -44656,7 +44829,8 @@ var SINK_CWE = {
44656
44829
  redos: "CWE-1333",
44657
44830
  format_string: "CWE-134",
44658
44831
  crlf: "CWE-113",
44659
- mass_assignment: "CWE-915"
44832
+ mass_assignment: "CWE-915",
44833
+ prompt_injection: "CWE-1427"
44660
44834
  };
44661
44835
  var VULNERABILITY_HELP = {
44662
44836
  sql_injection: {
@@ -44739,6 +44913,10 @@ var VULNERABILITY_HELP = {
44739
44913
  description: "Tainted argument passed to a MyBatis mapper interface method — actual SQL lives in the mapper XML/annotation binding, so exploitability depends on whether ${...} string interpolation is used",
44740
44914
  fix: "Audit the mapper XML/annotations: use #{...} parameter binding (PreparedStatement-backed) for any user-controlled value. Reject from SQL-injection reports unless ${...} interpolation is confirmed"
44741
44915
  },
44916
+ prompt_injection: {
44917
+ description: "User input flows into a generative-model prompt-construction call — attacker text can override system instructions or induce unintended tool/agent actions downstream",
44918
+ fix: "Keep untrusted text confined to user-role message content; do not concatenate it into system-role or template-controlled sections. Prefer schema-validated tool arguments (JSON-mode / structured outputs). Validate model output before it drives tool execution or code eval."
44919
+ },
44742
44920
  "dead-code": {
44743
44921
  description: "Unreachable code block has no execution path from any entry point",
44744
44922
  fix: "Remove the unreachable block or fix the control flow that precedes it"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cognium-dev",
3
- "version": "3.168.0",
3
+ "version": "3.174.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.168.0"
69
+ "circle-ir": "^3.174.0"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@types/node": "^25.5.0",