circle-ir 3.21.0 → 3.22.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.
@@ -4297,6 +4297,9 @@ function extractTypes(tree, cache, language) {
4297
4297
  const isJavaScript = effectiveLanguage === "javascript" || effectiveLanguage === "typescript";
4298
4298
  const isPython = effectiveLanguage === "python";
4299
4299
  const isRust = effectiveLanguage === "rust";
4300
+ if (effectiveLanguage === "go") {
4301
+ return extractGoTypes(tree, cache);
4302
+ }
4300
4303
  if (isRust) {
4301
4304
  return extractRustTypes(tree, cache);
4302
4305
  }
@@ -5432,6 +5435,143 @@ function extractRustDerives(node) {
5432
5435
  }
5433
5436
  return derives;
5434
5437
  }
5438
+ function extractGoTypes(tree, cache) {
5439
+ const types = [];
5440
+ const root = tree.rootNode;
5441
+ const typeDecls = getNodesFromCache(root, "type_declaration", cache);
5442
+ for (const decl of typeDecls) {
5443
+ for (let i2 = 0; i2 < decl.childCount; i2++) {
5444
+ const spec = decl.child(i2);
5445
+ if (!spec || spec.type !== "type_spec") continue;
5446
+ const nameNode = spec.childForFieldName("name");
5447
+ const typeNode = spec.childForFieldName("type");
5448
+ if (!nameNode || !typeNode) continue;
5449
+ const name2 = getNodeText(nameNode);
5450
+ const isInterface = typeNode.type === "interface_type";
5451
+ const isStruct = typeNode.type === "struct_type";
5452
+ if (!isStruct && !isInterface) continue;
5453
+ const fields = [];
5454
+ const methods = [];
5455
+ if (isStruct) {
5456
+ const fieldList = findChildByType(typeNode, "field_declaration_list");
5457
+ if (fieldList) {
5458
+ for (let j = 0; j < fieldList.childCount; j++) {
5459
+ const field = fieldList.child(j);
5460
+ if (!field || field.type !== "field_declaration") continue;
5461
+ const fieldName = field.childForFieldName("name");
5462
+ const fieldType = field.childForFieldName("type");
5463
+ if (fieldName) {
5464
+ fields.push({
5465
+ name: getNodeText(fieldName),
5466
+ type: fieldType ? getNodeText(fieldType) : null,
5467
+ modifiers: [],
5468
+ annotations: []
5469
+ });
5470
+ }
5471
+ }
5472
+ }
5473
+ }
5474
+ const methodDecls = getNodesFromCache(root, "method_declaration", cache);
5475
+ for (const md of methodDecls) {
5476
+ const receiver = md.childForFieldName("receiver");
5477
+ if (!receiver) continue;
5478
+ const receiverText = getNodeText(receiver);
5479
+ if (receiverText.includes(name2)) {
5480
+ const methodNameNode = md.childForFieldName("name");
5481
+ const params = md.childForFieldName("parameters");
5482
+ const result = md.childForFieldName("result");
5483
+ if (methodNameNode) {
5484
+ methods.push({
5485
+ name: getNodeText(methodNameNode),
5486
+ return_type: result ? getNodeText(result) : null,
5487
+ parameters: params ? extractGoParameters(params) : [],
5488
+ annotations: [],
5489
+ modifiers: [],
5490
+ start_line: md.startPosition.row + 1,
5491
+ end_line: md.endPosition.row + 1
5492
+ });
5493
+ }
5494
+ }
5495
+ }
5496
+ let pkg = null;
5497
+ const pkgClause = findChildByType(root, "package_clause");
5498
+ if (pkgClause) {
5499
+ for (let j = 0; j < pkgClause.childCount; j++) {
5500
+ const child = pkgClause.child(j);
5501
+ if (child && child.type === "package_identifier") {
5502
+ pkg = getNodeText(child);
5503
+ break;
5504
+ }
5505
+ }
5506
+ }
5507
+ types.push({
5508
+ name: name2,
5509
+ kind: isInterface ? "interface" : "class",
5510
+ package: pkg,
5511
+ extends: null,
5512
+ implements: [],
5513
+ annotations: [],
5514
+ methods,
5515
+ fields,
5516
+ start_line: decl.startPosition.row + 1,
5517
+ end_line: decl.endPosition.row + 1
5518
+ });
5519
+ }
5520
+ }
5521
+ const functions = getNodesFromCache(root, "function_declaration", cache);
5522
+ if (functions.length > 0) {
5523
+ const moduleFunctions = [];
5524
+ for (const func2 of functions) {
5525
+ const nameNode = func2.childForFieldName("name");
5526
+ const params = func2.childForFieldName("parameters");
5527
+ const result = func2.childForFieldName("result");
5528
+ if (nameNode) {
5529
+ moduleFunctions.push({
5530
+ name: getNodeText(nameNode),
5531
+ return_type: result ? getNodeText(result) : null,
5532
+ parameters: params ? extractGoParameters(params) : [],
5533
+ annotations: [],
5534
+ modifiers: [],
5535
+ start_line: func2.startPosition.row + 1,
5536
+ end_line: func2.endPosition.row + 1
5537
+ });
5538
+ }
5539
+ }
5540
+ if (moduleFunctions.length > 0) {
5541
+ types.push({
5542
+ name: "<module>",
5543
+ kind: "class",
5544
+ package: null,
5545
+ extends: null,
5546
+ implements: [],
5547
+ annotations: [],
5548
+ methods: moduleFunctions,
5549
+ fields: [],
5550
+ start_line: 1,
5551
+ end_line: root.endPosition.row + 1
5552
+ });
5553
+ }
5554
+ }
5555
+ return types;
5556
+ }
5557
+ function extractGoParameters(params) {
5558
+ const parameters = [];
5559
+ for (let i2 = 0; i2 < params.childCount; i2++) {
5560
+ const child = params.child(i2);
5561
+ if (!child || child.type !== "parameter_declaration") continue;
5562
+ const nameNode = child.childForFieldName("name");
5563
+ const typeNode = child.childForFieldName("type");
5564
+ if (nameNode) {
5565
+ parameters.push({
5566
+ name: getNodeText(nameNode),
5567
+ type: typeNode ? getNodeText(typeNode) : null,
5568
+ annotations: [],
5569
+ line: child.startPosition.row + 1
5570
+ });
5571
+ }
5572
+ }
5573
+ return parameters;
5574
+ }
5435
5575
  function findChildByType(node, type) {
5436
5576
  for (let i2 = 0; i2 < node.childCount; i2++) {
5437
5577
  const child = node.child(i2);
@@ -5479,6 +5619,9 @@ function extractCalls(tree, cache, language) {
5479
5619
  const isJavaScript = detectedLanguage === "javascript" || detectedLanguage === "typescript";
5480
5620
  const isPython = detectedLanguage === "python";
5481
5621
  const isRust = detectedLanguage === "rust";
5622
+ if (detectedLanguage === "go") {
5623
+ return extractGoCalls(tree, cache);
5624
+ }
5482
5625
  if (detectedLanguage === "bash") {
5483
5626
  return extractBashCalls(tree, cache);
5484
5627
  }
@@ -6761,6 +6904,104 @@ function resolveRustCall(methodName, receiver, context) {
6761
6904
  status: "external_method"
6762
6905
  };
6763
6906
  }
6907
+ function extractGoCalls(tree, cache) {
6908
+ const calls = [];
6909
+ const callExpressions = getNodesFromCache(tree.rootNode, "call_expression", cache);
6910
+ for (const call of callExpressions) {
6911
+ const callInfo = extractGoCallInfo(call);
6912
+ if (callInfo) {
6913
+ calls.push(callInfo);
6914
+ }
6915
+ }
6916
+ return calls;
6917
+ }
6918
+ function extractGoCallInfo(node) {
6919
+ const funcNode = node.childForFieldName("function");
6920
+ if (!funcNode) return null;
6921
+ let methodName;
6922
+ let receiver = null;
6923
+ if (funcNode.type === "selector_expression") {
6924
+ const operand = funcNode.childForFieldName("operand");
6925
+ const field = funcNode.childForFieldName("field");
6926
+ receiver = operand ? getNodeText(operand) : null;
6927
+ methodName = field ? getNodeText(field) : getNodeText(funcNode);
6928
+ } else if (funcNode.type === "identifier") {
6929
+ methodName = getNodeText(funcNode);
6930
+ } else {
6931
+ methodName = getNodeText(funcNode);
6932
+ }
6933
+ const argsNode = node.childForFieldName("arguments");
6934
+ const args2 = argsNode ? extractGoArguments(argsNode) : [];
6935
+ const inMethod = findGoEnclosingFunction(node);
6936
+ return {
6937
+ method_name: methodName,
6938
+ receiver,
6939
+ arguments: args2,
6940
+ location: {
6941
+ line: node.startPosition.row + 1,
6942
+ column: node.startPosition.column
6943
+ },
6944
+ in_method: inMethod,
6945
+ resolved: false,
6946
+ resolution: { status: "external_method" }
6947
+ };
6948
+ }
6949
+ function extractGoArguments(argsNode) {
6950
+ const args2 = [];
6951
+ let position = 0;
6952
+ for (let i2 = 0; i2 < argsNode.childCount; i2++) {
6953
+ const child = argsNode.child(i2);
6954
+ if (!child) continue;
6955
+ if (child.type === "(" || child.type === ")" || child.type === ",") continue;
6956
+ const expression = getNodeText(child);
6957
+ const variable = child.type === "identifier" ? expression : null;
6958
+ const literal = isGoLiteral(child) ? extractGoLiteralValue(child) : null;
6959
+ args2.push({
6960
+ position: position++,
6961
+ expression,
6962
+ variable,
6963
+ literal
6964
+ });
6965
+ }
6966
+ return args2;
6967
+ }
6968
+ function isGoLiteral(node) {
6969
+ const literalTypes = /* @__PURE__ */ new Set([
6970
+ "interpreted_string_literal",
6971
+ "raw_string_literal",
6972
+ "int_literal",
6973
+ "float_literal",
6974
+ "true",
6975
+ "false",
6976
+ "nil"
6977
+ ]);
6978
+ return literalTypes.has(node.type);
6979
+ }
6980
+ function extractGoLiteralValue(node) {
6981
+ const text = getNodeText(node);
6982
+ if (node.type === "interpreted_string_literal") {
6983
+ return text.slice(1, -1);
6984
+ }
6985
+ if (node.type === "raw_string_literal") {
6986
+ return text.slice(1, -1);
6987
+ }
6988
+ return text;
6989
+ }
6990
+ function findGoEnclosingFunction(node) {
6991
+ let current = node.parent;
6992
+ while (current) {
6993
+ if (current.type === "function_declaration") {
6994
+ const nameNode = current.childForFieldName("name");
6995
+ return nameNode ? getNodeText(nameNode) : null;
6996
+ }
6997
+ if (current.type === "method_declaration") {
6998
+ const nameNode = current.childForFieldName("name");
6999
+ return nameNode ? getNodeText(nameNode) : null;
7000
+ }
7001
+ current = current.parent;
7002
+ }
7003
+ return null;
7004
+ }
6764
7005
 
6765
7006
  // src/core/extractors/imports.ts
6766
7007
  function detectLanguage2(tree) {
@@ -6815,6 +7056,9 @@ function extractImports(tree, language) {
6815
7056
  const isJavaScript = effectiveLanguage === "javascript" || effectiveLanguage === "typescript";
6816
7057
  const isPython = effectiveLanguage === "python";
6817
7058
  const isRust = effectiveLanguage === "rust";
7059
+ if (effectiveLanguage === "go") {
7060
+ return extractGoImports(tree);
7061
+ }
6818
7062
  if (isRust) {
6819
7063
  return extractRustImports(tree);
6820
7064
  }
@@ -7362,6 +7606,61 @@ function extractRustScopedUseList(node, lineNumber) {
7362
7606
  }
7363
7607
  return imports;
7364
7608
  }
7609
+ function extractGoImports(tree) {
7610
+ const imports = [];
7611
+ const importDecls = findNodes(tree.rootNode, "import_declaration");
7612
+ for (const decl of importDecls) {
7613
+ const singleSpec = findGoChildByType(decl, "import_spec");
7614
+ if (singleSpec) {
7615
+ const parsed = parseGoImportSpec(singleSpec);
7616
+ if (parsed) imports.push(parsed);
7617
+ continue;
7618
+ }
7619
+ const specList = findGoChildByType(decl, "import_spec_list");
7620
+ if (specList) {
7621
+ for (let i2 = 0; i2 < specList.childCount; i2++) {
7622
+ const spec = specList.child(i2);
7623
+ if (!spec || spec.type !== "import_spec") continue;
7624
+ const parsed = parseGoImportSpec(spec);
7625
+ if (parsed) imports.push(parsed);
7626
+ }
7627
+ }
7628
+ }
7629
+ return imports;
7630
+ }
7631
+ function parseGoImportSpec(spec) {
7632
+ let alias = null;
7633
+ let path;
7634
+ for (let i2 = 0; i2 < spec.childCount; i2++) {
7635
+ const child = spec.child(i2);
7636
+ if (!child) continue;
7637
+ if (child.type === "package_identifier" || child.type === "blank_identifier" || child.type === "dot") {
7638
+ alias = getNodeText(child);
7639
+ }
7640
+ if (child.type === "interpreted_string_literal") {
7641
+ const text = getNodeText(child);
7642
+ path = text.slice(1, -1);
7643
+ }
7644
+ }
7645
+ if (!path) return null;
7646
+ const shortName = alias || path.split("/").pop() || path;
7647
+ return {
7648
+ imported_name: shortName,
7649
+ from_package: path,
7650
+ alias,
7651
+ is_wildcard: alias === ".",
7652
+ line_number: spec.startPosition.row + 1
7653
+ };
7654
+ }
7655
+ function findGoChildByType(node, type) {
7656
+ for (let i2 = 0; i2 < node.childCount; i2++) {
7657
+ const child = node.child(i2);
7658
+ if (child?.type === type) {
7659
+ return child;
7660
+ }
7661
+ }
7662
+ return null;
7663
+ }
7365
7664
 
7366
7665
  // src/core/extractors/exports.ts
7367
7666
  function extractExports(types) {
@@ -7453,6 +7752,9 @@ function buildCFG(tree, language) {
7453
7752
  if (effectiveLanguage === "bash") {
7454
7753
  return buildBashCFG(tree, blockIdCounter);
7455
7754
  }
7755
+ if (effectiveLanguage === "go") {
7756
+ return buildGoCFG(tree, blockIdCounter);
7757
+ }
7456
7758
  if (isJavaScript) {
7457
7759
  const functions = [
7458
7760
  ...findNodes(tree.rootNode, "function_declaration"),
@@ -7929,6 +8231,58 @@ function isStatement(node, isJavaScript) {
7929
8231
  ]);
7930
8232
  return isJavaScript ? jsStatementTypes.has(node.type) : javaStatementTypes.has(node.type);
7931
8233
  }
8234
+ function buildGoCFG(tree, blockIdCounter) {
8235
+ const allBlocks = [];
8236
+ const allEdges = [];
8237
+ const functions = [
8238
+ ...findNodes(tree.rootNode, "function_declaration"),
8239
+ ...findNodes(tree.rootNode, "method_declaration")
8240
+ ];
8241
+ for (const func2 of functions) {
8242
+ const body2 = func2.childForFieldName("body");
8243
+ if (!body2 || body2.type !== "block") continue;
8244
+ const { blocks, edges, nextId } = buildMethodCFG(body2, blockIdCounter, false);
8245
+ allBlocks.push(...blocks);
8246
+ allEdges.push(...edges);
8247
+ blockIdCounter = nextId;
8248
+ }
8249
+ const hasTopLevelDecls = tree.rootNode.children.some(
8250
+ (c) => c !== null && isGoStatement(c)
8251
+ );
8252
+ if (hasTopLevelDecls) {
8253
+ const block = {
8254
+ id: blockIdCounter++,
8255
+ type: "normal",
8256
+ start_line: 1,
8257
+ end_line: tree.rootNode.endPosition.row + 1
8258
+ };
8259
+ allBlocks.push(block);
8260
+ }
8261
+ return { blocks: allBlocks, edges: allEdges };
8262
+ }
8263
+ function isGoStatement(node) {
8264
+ const goStatementTypes = /* @__PURE__ */ new Set([
8265
+ "short_var_declaration",
8266
+ "var_declaration",
8267
+ "assignment_statement",
8268
+ "expression_statement",
8269
+ "if_statement",
8270
+ "for_statement",
8271
+ "switch_statement",
8272
+ "type_switch_statement",
8273
+ "select_statement",
8274
+ "return_statement",
8275
+ "go_statement",
8276
+ "defer_statement",
8277
+ "send_statement",
8278
+ "inc_statement",
8279
+ "dec_statement",
8280
+ "block",
8281
+ "type_declaration",
8282
+ "const_declaration"
8283
+ ]);
8284
+ return goStatementTypes.has(node.type);
8285
+ }
7932
8286
 
7933
8287
  // src/core/extractors/dfg.ts
7934
8288
  function detectLanguage4(tree) {
@@ -7976,6 +8330,9 @@ function buildDFG(tree, cache, language) {
7976
8330
  if (effectiveLanguage === "bash") {
7977
8331
  return buildBashDFG(tree);
7978
8332
  }
8333
+ if (effectiveLanguage === "go") {
8334
+ return buildGoDFG(tree);
8335
+ }
7979
8336
  return buildJavaDFG(tree, cache);
7980
8337
  }
7981
8338
  function buildJavaDFG(tree, cache) {
@@ -8959,68 +9316,321 @@ function isRustKeyword(name2) {
8959
9316
  ]);
8960
9317
  return keywords.has(name2);
8961
9318
  }
8962
-
8963
- // src/analysis/config-loader.ts
8964
- var DEFAULT_SOURCES = [
8965
- // HTTP Sources (Servlet API)
8966
- { method: "getParameter", class: "HttpServletRequest", type: "http_param", severity: "high", return_tainted: true },
8967
- { method: "getParameterValues", class: "HttpServletRequest", type: "http_param", severity: "high", return_tainted: true },
8968
- { method: "getParameterMap", class: "HttpServletRequest", type: "http_param", severity: "high", return_tainted: true },
8969
- { method: "getParameterNames", class: "HttpServletRequest", type: "http_param", severity: "high", return_tainted: true },
8970
- { method: "getHeader", class: "HttpServletRequest", type: "http_header", severity: "high", return_tainted: true },
8971
- { method: "getHeaders", class: "HttpServletRequest", type: "http_header", severity: "high", return_tainted: true },
8972
- { method: "getHeaderNames", class: "HttpServletRequest", type: "http_header", severity: "high", return_tainted: true },
8973
- { method: "getQueryString", class: "HttpServletRequest", type: "http_query", severity: "high", return_tainted: true },
8974
- { method: "getCookies", class: "HttpServletRequest", type: "http_cookie", severity: "high", return_tainted: true },
8975
- { method: "getInputStream", class: "HttpServletRequest", type: "http_body", severity: "high", return_tainted: true },
8976
- { method: "getReader", class: "HttpServletRequest", type: "http_body", severity: "high", return_tainted: true },
8977
- { method: "getPathInfo", class: "HttpServletRequest", type: "http_path", severity: "high", return_tainted: true },
8978
- { method: "getRequestURI", class: "HttpServletRequest", type: "http_path", severity: "high", return_tainted: true },
8979
- { method: "getRequestURL", class: "HttpServletRequest", type: "http_path", severity: "high", return_tainted: true },
8980
- { method: "getServletPath", class: "HttpServletRequest", type: "http_path", severity: "high", return_tainted: true },
8981
- { method: "getContextPath", class: "HttpServletRequest", type: "http_path", severity: "medium", return_tainted: true },
8982
- { method: "getRemoteHost", class: "HttpServletRequest", type: "http_header", severity: "medium", return_tainted: true },
8983
- { method: "getRemoteAddr", class: "HttpServletRequest", type: "http_header", severity: "medium", return_tainted: true },
8984
- // Additional HTTP request methods that can be attacker-controlled
8985
- { method: "getProtocol", class: "HttpServletRequest", type: "http_header", severity: "medium", return_tainted: true },
8986
- { method: "getScheme", class: "HttpServletRequest", type: "http_header", severity: "medium", return_tainted: true },
8987
- { method: "getAuthType", class: "HttpServletRequest", type: "http_header", severity: "medium", return_tainted: true },
8988
- { method: "getRemoteUser", class: "HttpServletRequest", type: "http_header", severity: "medium", return_tainted: true },
8989
- { method: "getMethod", class: "HttpServletRequest", type: "http_header", severity: "low", return_tainted: true },
8990
- { method: "getContentType", class: "HttpServletRequest", type: "http_header", severity: "medium", return_tainted: true },
8991
- { method: "getCharacterEncoding", class: "HttpServletRequest", type: "http_header", severity: "low", return_tainted: true },
8992
- // Enumeration/Iterator sources (from request.getHeaders(), etc.)
8993
- { method: "nextElement", class: "Enumeration", type: "http_header", severity: "high", return_tainted: true },
8994
- { method: "nextElement", type: "http_header", severity: "high", return_tainted: true },
8995
- // Cookie sources
8996
- { method: "getValue", class: "Cookie", type: "http_cookie", severity: "high", return_tainted: true },
8997
- { method: "getName", class: "Cookie", type: "http_cookie", severity: "high", return_tainted: true },
8998
- // I/O Sources (Scanner, BufferedReader, etc.)
8999
- { method: "readLine", class: "BufferedReader", type: "io_input", severity: "high", return_tainted: true },
9000
- { method: "readLine", type: "io_input", severity: "high", return_tainted: true },
9001
- { method: "nextLine", class: "Scanner", type: "io_input", severity: "high", return_tainted: true },
9002
- { method: "next", class: "Scanner", type: "io_input", severity: "high", return_tainted: true },
9003
- { method: "nextInt", class: "Scanner", type: "io_input", severity: "high", return_tainted: true },
9004
- // Database result sources
9005
- { method: "getString", class: "ResultSet", type: "db_input", severity: "medium", return_tainted: true },
9006
- { method: "getObject", class: "ResultSet", type: "db_input", severity: "medium", return_tainted: true },
9007
- { method: "getInt", class: "ResultSet", type: "db_input", severity: "medium", return_tainted: true },
9008
- // Spring annotations
9009
- { annotation: "RequestParam", type: "http_param", severity: "high", param_tainted: true },
9010
- { annotation: "RequestBody", type: "http_body", severity: "high", param_tainted: true },
9011
- { annotation: "PathVariable", type: "http_path", severity: "medium", param_tainted: true },
9012
- { annotation: "RequestHeader", type: "http_header", severity: "high", param_tainted: true },
9013
- { annotation: "CookieValue", type: "http_cookie", severity: "high", param_tainted: true },
9014
- // JAX-RS annotations
9015
- { annotation: "QueryParam", type: "http_param", severity: "high", param_tainted: true },
9016
- { annotation: "FormParam", type: "http_param", severity: "high", param_tainted: true },
9017
- { annotation: "PathParam", type: "http_path", severity: "medium", param_tainted: true },
9018
- { annotation: "HeaderParam", type: "http_header", severity: "high", param_tainted: true },
9019
- // Environment
9020
- { method: "getenv", class: "System", type: "env_input", severity: "medium", return_tainted: true },
9021
- { method: "getProperty", class: "System", type: "env_input", severity: "medium", return_tainted: true },
9022
- // Note: Properties.getProperty is NOT included by default as it causes many false positives
9023
- // in OWASP Benchmark. Include it via custom config if needed for specific analyses.
9319
+ var GO_KEYWORDS = /* @__PURE__ */ new Set([
9320
+ "break",
9321
+ "case",
9322
+ "chan",
9323
+ "const",
9324
+ "continue",
9325
+ "default",
9326
+ "defer",
9327
+ "else",
9328
+ "fallthrough",
9329
+ "for",
9330
+ "func",
9331
+ "go",
9332
+ "goto",
9333
+ "if",
9334
+ "import",
9335
+ "interface",
9336
+ "map",
9337
+ "package",
9338
+ "range",
9339
+ "return",
9340
+ "select",
9341
+ "struct",
9342
+ "switch",
9343
+ "type",
9344
+ "var",
9345
+ "true",
9346
+ "false",
9347
+ "nil",
9348
+ "iota",
9349
+ "append",
9350
+ "cap",
9351
+ "close",
9352
+ "complex",
9353
+ "copy",
9354
+ "delete",
9355
+ "imag",
9356
+ "len",
9357
+ "make",
9358
+ "new",
9359
+ "panic",
9360
+ "print",
9361
+ "println",
9362
+ "real",
9363
+ "recover",
9364
+ "string",
9365
+ "int",
9366
+ "int8",
9367
+ "int16",
9368
+ "int32",
9369
+ "int64",
9370
+ "uint",
9371
+ "uint8",
9372
+ "uint16",
9373
+ "uint32",
9374
+ "uint64",
9375
+ "float32",
9376
+ "float64",
9377
+ "complex64",
9378
+ "complex128",
9379
+ "byte",
9380
+ "rune",
9381
+ "bool",
9382
+ "error",
9383
+ "any"
9384
+ ]);
9385
+ function buildGoDFG(tree) {
9386
+ const defs = [];
9387
+ const uses = [];
9388
+ let defIdCounter = 1;
9389
+ let useIdCounter = 1;
9390
+ const scopeStack = [/* @__PURE__ */ new Map()];
9391
+ const functions = [
9392
+ ...findNodes(tree.rootNode, "function_declaration"),
9393
+ ...findNodes(tree.rootNode, "method_declaration")
9394
+ ];
9395
+ for (const func2 of functions) {
9396
+ scopeStack.push(/* @__PURE__ */ new Map());
9397
+ const params = func2.childForFieldName("parameters");
9398
+ if (params) {
9399
+ extractGoParamDefs(params, defs, defIdCounter, scopeStack);
9400
+ defIdCounter = defs.length + 1;
9401
+ }
9402
+ const receiver = func2.childForFieldName("receiver");
9403
+ if (receiver) {
9404
+ extractGoParamDefs(receiver, defs, defIdCounter, scopeStack);
9405
+ defIdCounter = defs.length + 1;
9406
+ }
9407
+ const body2 = func2.childForFieldName("body");
9408
+ if (body2) {
9409
+ processGoBlock(body2, defs, uses, scopeStack, { defId: defIdCounter, useId: useIdCounter });
9410
+ defIdCounter = defs.length + 1;
9411
+ useIdCounter = uses.length + 1;
9412
+ }
9413
+ scopeStack.pop();
9414
+ }
9415
+ for (let i2 = 0; i2 < tree.rootNode.childCount; i2++) {
9416
+ const child = tree.rootNode.child(i2);
9417
+ if (!child) continue;
9418
+ if (child.type === "var_declaration") {
9419
+ processGoVarDecl(child, defs, scopeStack, { defId: defIdCounter });
9420
+ defIdCounter = defs.length + 1;
9421
+ }
9422
+ }
9423
+ const chains = computeChains(defs, uses);
9424
+ return { defs, uses, chains };
9425
+ }
9426
+ function extractGoParamDefs(params, defs, _startId, scopeStack) {
9427
+ for (let i2 = 0; i2 < params.childCount; i2++) {
9428
+ const param = params.child(i2);
9429
+ if (!param || param.type !== "parameter_declaration") continue;
9430
+ const typeNode = param.childForFieldName("type");
9431
+ for (let j = 0; j < param.childCount; j++) {
9432
+ const nameNode = param.child(j);
9433
+ if (!nameNode || nameNode.type !== "identifier") continue;
9434
+ if (nameNode === typeNode) continue;
9435
+ const varName = getNodeText(nameNode);
9436
+ if (varName === "_") continue;
9437
+ const def = {
9438
+ id: defs.length + 1,
9439
+ variable: varName,
9440
+ kind: "param",
9441
+ line: param.startPosition.row + 1
9442
+ };
9443
+ defs.push(def);
9444
+ currentScope(scopeStack).set(varName, def.id);
9445
+ }
9446
+ }
9447
+ }
9448
+ function processGoBlock(node, defs, uses, scopeStack, counters) {
9449
+ walkTree(node, (child) => {
9450
+ if (child.type === "short_var_declaration") {
9451
+ const left = child.childForFieldName("left");
9452
+ const right = child.childForFieldName("right");
9453
+ if (right) {
9454
+ extractGoUses(right, uses, scopeStack);
9455
+ }
9456
+ if (left) {
9457
+ extractGoLhsDefs(left, defs, scopeStack, child.startPosition.row + 1);
9458
+ }
9459
+ } else if (child.type === "var_declaration") {
9460
+ processGoVarDecl(child, defs, scopeStack, counters);
9461
+ } else if (child.type === "assignment_statement") {
9462
+ const left = child.childForFieldName("left");
9463
+ const right = child.childForFieldName("right");
9464
+ if (right) {
9465
+ extractGoUses(right, uses, scopeStack);
9466
+ }
9467
+ if (left) {
9468
+ extractGoLhsDefs(left, defs, scopeStack, child.startPosition.row + 1);
9469
+ }
9470
+ } else if (child.type === "for_statement") {
9471
+ const rangeClause = findChildByTypeGo(child, "range_clause");
9472
+ if (rangeClause) {
9473
+ const left = rangeClause.childForFieldName("left");
9474
+ if (left) {
9475
+ extractGoLhsDefs(left, defs, scopeStack, child.startPosition.row + 1);
9476
+ }
9477
+ }
9478
+ } else if (child.type === "call_expression") {
9479
+ extractGoUses(child, uses, scopeStack);
9480
+ } else if (child.type === "return_statement") {
9481
+ for (let i2 = 0; i2 < child.childCount; i2++) {
9482
+ const expr = child.child(i2);
9483
+ if (expr && expr.type !== "return") {
9484
+ extractGoUses(expr, uses, scopeStack);
9485
+ }
9486
+ }
9487
+ }
9488
+ });
9489
+ }
9490
+ function processGoVarDecl(node, defs, scopeStack, _counters) {
9491
+ for (let i2 = 0; i2 < node.childCount; i2++) {
9492
+ const spec = node.child(i2);
9493
+ if (!spec || spec.type !== "var_spec") continue;
9494
+ for (let j = 0; j < spec.childCount; j++) {
9495
+ const nameNode = spec.child(j);
9496
+ if (!nameNode || nameNode.type !== "identifier") continue;
9497
+ const varName = getNodeText(nameNode);
9498
+ if (varName === "_") continue;
9499
+ const def = {
9500
+ id: defs.length + 1,
9501
+ variable: varName,
9502
+ kind: "local",
9503
+ line: spec.startPosition.row + 1
9504
+ };
9505
+ defs.push(def);
9506
+ currentScope(scopeStack).set(varName, def.id);
9507
+ }
9508
+ }
9509
+ }
9510
+ function extractGoLhsDefs(left, defs, scopeStack, line) {
9511
+ if (left.type === "identifier") {
9512
+ const varName = getNodeText(left);
9513
+ if (varName === "_") return;
9514
+ const def = {
9515
+ id: defs.length + 1,
9516
+ variable: varName,
9517
+ kind: "local",
9518
+ line
9519
+ };
9520
+ defs.push(def);
9521
+ currentScope(scopeStack).set(varName, def.id);
9522
+ } else if (left.type === "expression_list") {
9523
+ for (let i2 = 0; i2 < left.childCount; i2++) {
9524
+ const item = left.child(i2);
9525
+ if (item && item.type === "identifier") {
9526
+ const varName = getNodeText(item);
9527
+ if (varName === "_") continue;
9528
+ const def = {
9529
+ id: defs.length + 1,
9530
+ variable: varName,
9531
+ kind: "local",
9532
+ line
9533
+ };
9534
+ defs.push(def);
9535
+ currentScope(scopeStack).set(varName, def.id);
9536
+ }
9537
+ }
9538
+ }
9539
+ }
9540
+ function extractGoUses(node, uses, scopeStack) {
9541
+ walkTree(node, (child) => {
9542
+ if (child.type === "identifier") {
9543
+ const varName = getNodeText(child);
9544
+ if (varName === "_" || GO_KEYWORDS.has(varName)) return;
9545
+ const parent = child.parent;
9546
+ if (parent?.type === "selector_expression" && parent.childForFieldName("field") === child) {
9547
+ return;
9548
+ }
9549
+ if (parent?.type === "parameter_declaration" && parent.childForFieldName("type") === child) {
9550
+ return;
9551
+ }
9552
+ if (parent?.type === "type_identifier") {
9553
+ return;
9554
+ }
9555
+ const defId = findReachingDef(varName, scopeStack);
9556
+ uses.push({
9557
+ id: uses.length + 1,
9558
+ variable: varName,
9559
+ line: child.startPosition.row + 1,
9560
+ def_id: defId
9561
+ });
9562
+ }
9563
+ });
9564
+ }
9565
+ function findChildByTypeGo(node, type) {
9566
+ for (let i2 = 0; i2 < node.childCount; i2++) {
9567
+ const child = node.child(i2);
9568
+ if (child?.type === type) return child;
9569
+ }
9570
+ return null;
9571
+ }
9572
+
9573
+ // src/analysis/config-loader.ts
9574
+ var DEFAULT_SOURCES = [
9575
+ // HTTP Sources (Servlet API)
9576
+ { method: "getParameter", class: "HttpServletRequest", type: "http_param", severity: "high", return_tainted: true },
9577
+ { method: "getParameterValues", class: "HttpServletRequest", type: "http_param", severity: "high", return_tainted: true },
9578
+ { method: "getParameterMap", class: "HttpServletRequest", type: "http_param", severity: "high", return_tainted: true },
9579
+ { method: "getParameterNames", class: "HttpServletRequest", type: "http_param", severity: "high", return_tainted: true },
9580
+ { method: "getHeader", class: "HttpServletRequest", type: "http_header", severity: "high", return_tainted: true },
9581
+ { method: "getHeaders", class: "HttpServletRequest", type: "http_header", severity: "high", return_tainted: true },
9582
+ { method: "getHeaderNames", class: "HttpServletRequest", type: "http_header", severity: "high", return_tainted: true },
9583
+ { method: "getQueryString", class: "HttpServletRequest", type: "http_query", severity: "high", return_tainted: true },
9584
+ { method: "getCookies", class: "HttpServletRequest", type: "http_cookie", severity: "high", return_tainted: true },
9585
+ { method: "getInputStream", class: "HttpServletRequest", type: "http_body", severity: "high", return_tainted: true },
9586
+ { method: "getReader", class: "HttpServletRequest", type: "http_body", severity: "high", return_tainted: true },
9587
+ { method: "getPathInfo", class: "HttpServletRequest", type: "http_path", severity: "high", return_tainted: true },
9588
+ { method: "getRequestURI", class: "HttpServletRequest", type: "http_path", severity: "high", return_tainted: true },
9589
+ { method: "getRequestURL", class: "HttpServletRequest", type: "http_path", severity: "high", return_tainted: true },
9590
+ { method: "getServletPath", class: "HttpServletRequest", type: "http_path", severity: "high", return_tainted: true },
9591
+ { method: "getContextPath", class: "HttpServletRequest", type: "http_path", severity: "medium", return_tainted: true },
9592
+ { method: "getRemoteHost", class: "HttpServletRequest", type: "http_header", severity: "medium", return_tainted: true },
9593
+ { method: "getRemoteAddr", class: "HttpServletRequest", type: "http_header", severity: "medium", return_tainted: true },
9594
+ // Additional HTTP request methods that can be attacker-controlled
9595
+ { method: "getProtocol", class: "HttpServletRequest", type: "http_header", severity: "medium", return_tainted: true },
9596
+ { method: "getScheme", class: "HttpServletRequest", type: "http_header", severity: "medium", return_tainted: true },
9597
+ { method: "getAuthType", class: "HttpServletRequest", type: "http_header", severity: "medium", return_tainted: true },
9598
+ { method: "getRemoteUser", class: "HttpServletRequest", type: "http_header", severity: "medium", return_tainted: true },
9599
+ { method: "getMethod", class: "HttpServletRequest", type: "http_header", severity: "low", return_tainted: true },
9600
+ { method: "getContentType", class: "HttpServletRequest", type: "http_header", severity: "medium", return_tainted: true },
9601
+ { method: "getCharacterEncoding", class: "HttpServletRequest", type: "http_header", severity: "low", return_tainted: true },
9602
+ // Enumeration/Iterator sources (from request.getHeaders(), etc.)
9603
+ { method: "nextElement", class: "Enumeration", type: "http_header", severity: "high", return_tainted: true },
9604
+ { method: "nextElement", type: "http_header", severity: "high", return_tainted: true },
9605
+ // Cookie sources
9606
+ { method: "getValue", class: "Cookie", type: "http_cookie", severity: "high", return_tainted: true },
9607
+ { method: "getName", class: "Cookie", type: "http_cookie", severity: "high", return_tainted: true },
9608
+ // I/O Sources (Scanner, BufferedReader, etc.)
9609
+ { method: "readLine", class: "BufferedReader", type: "io_input", severity: "high", return_tainted: true },
9610
+ { method: "readLine", type: "io_input", severity: "high", return_tainted: true },
9611
+ { method: "nextLine", class: "Scanner", type: "io_input", severity: "high", return_tainted: true },
9612
+ { method: "next", class: "Scanner", type: "io_input", severity: "high", return_tainted: true },
9613
+ { method: "nextInt", class: "Scanner", type: "io_input", severity: "high", return_tainted: true },
9614
+ // Database result sources
9615
+ { method: "getString", class: "ResultSet", type: "db_input", severity: "medium", return_tainted: true },
9616
+ { method: "getObject", class: "ResultSet", type: "db_input", severity: "medium", return_tainted: true },
9617
+ { method: "getInt", class: "ResultSet", type: "db_input", severity: "medium", return_tainted: true },
9618
+ // Spring annotations
9619
+ { annotation: "RequestParam", type: "http_param", severity: "high", param_tainted: true },
9620
+ { annotation: "RequestBody", type: "http_body", severity: "high", param_tainted: true },
9621
+ { annotation: "PathVariable", type: "http_path", severity: "medium", param_tainted: true },
9622
+ { annotation: "RequestHeader", type: "http_header", severity: "high", param_tainted: true },
9623
+ { annotation: "CookieValue", type: "http_cookie", severity: "high", param_tainted: true },
9624
+ // JAX-RS annotations
9625
+ { annotation: "QueryParam", type: "http_param", severity: "high", param_tainted: true },
9626
+ { annotation: "FormParam", type: "http_param", severity: "high", param_tainted: true },
9627
+ { annotation: "PathParam", type: "http_path", severity: "medium", param_tainted: true },
9628
+ { annotation: "HeaderParam", type: "http_header", severity: "high", param_tainted: true },
9629
+ // Environment
9630
+ { method: "getenv", class: "System", type: "env_input", severity: "medium", return_tainted: true },
9631
+ { method: "getProperty", class: "System", type: "env_input", severity: "medium", return_tainted: true },
9632
+ // Note: Properties.getProperty is NOT included by default as it causes many false positives
9633
+ // in OWASP Benchmark. Include it via custom config if needed for specific analyses.
9024
9634
  // Servlet Configuration Parameters (can be attacker-influenced in some deployments)
9025
9635
  { method: "getInitParameter", class: "ServletConfig", type: "http_param", severity: "medium", return_tainted: true },
9026
9636
  { method: "getInitParameter", class: "ServletContext", type: "http_param", severity: "medium", return_tainted: true },
@@ -17886,211 +18496,784 @@ var BashPlugin = class extends BaseLanguagePlugin {
17886
18496
  argPositions: [1]
17887
18497
  },
17888
18498
  {
17889
- method: "zsh",
17890
- type: "command_injection",
17891
- cwe: "CWE-78",
17892
- severity: "critical",
17893
- argPositions: [1]
18499
+ method: "zsh",
18500
+ type: "command_injection",
18501
+ cwe: "CWE-78",
18502
+ severity: "critical",
18503
+ argPositions: [1]
18504
+ },
18505
+ {
18506
+ method: "ksh",
18507
+ type: "command_injection",
18508
+ cwe: "CWE-78",
18509
+ severity: "critical",
18510
+ argPositions: [1]
18511
+ },
18512
+ // SQL injection via DB CLI clients (first arg is query/expression)
18513
+ {
18514
+ method: "mysql",
18515
+ type: "sql_injection",
18516
+ cwe: "CWE-89",
18517
+ severity: "critical",
18518
+ argPositions: [1]
18519
+ },
18520
+ {
18521
+ method: "psql",
18522
+ type: "sql_injection",
18523
+ cwe: "CWE-89",
18524
+ severity: "critical",
18525
+ argPositions: [1]
18526
+ },
18527
+ {
18528
+ method: "sqlite3",
18529
+ type: "sql_injection",
18530
+ cwe: "CWE-89",
18531
+ severity: "critical",
18532
+ argPositions: [1]
18533
+ },
18534
+ // Path traversal via file operations (first arg is path)
18535
+ {
18536
+ method: "cat",
18537
+ type: "path_traversal",
18538
+ cwe: "CWE-22",
18539
+ severity: "high",
18540
+ argPositions: [0]
18541
+ },
18542
+ {
18543
+ method: "rm",
18544
+ type: "path_traversal",
18545
+ cwe: "CWE-22",
18546
+ severity: "high",
18547
+ argPositions: [0]
18548
+ },
18549
+ {
18550
+ method: "cp",
18551
+ type: "path_traversal",
18552
+ cwe: "CWE-22",
18553
+ severity: "high",
18554
+ argPositions: [0]
18555
+ },
18556
+ {
18557
+ method: "mv",
18558
+ type: "path_traversal",
18559
+ cwe: "CWE-22",
18560
+ severity: "high",
18561
+ argPositions: [0]
18562
+ },
18563
+ {
18564
+ method: "chmod",
18565
+ type: "path_traversal",
18566
+ cwe: "CWE-22",
18567
+ severity: "medium",
18568
+ argPositions: [1]
18569
+ },
18570
+ {
18571
+ method: "chown",
18572
+ type: "path_traversal",
18573
+ cwe: "CWE-22",
18574
+ severity: "medium",
18575
+ argPositions: [1]
18576
+ },
18577
+ // SSRF — curl/wget with externally-controlled URL
18578
+ {
18579
+ method: "curl",
18580
+ type: "ssrf",
18581
+ cwe: "CWE-918",
18582
+ severity: "high",
18583
+ argPositions: [0]
18584
+ },
18585
+ {
18586
+ method: "wget",
18587
+ type: "ssrf",
18588
+ cwe: "CWE-918",
18589
+ severity: "high",
18590
+ argPositions: [0]
18591
+ }
18592
+ ];
18593
+ }
18594
+ /**
18595
+ * Shell has no OOP receiver types.
18596
+ */
18597
+ getReceiverType(_node, _context) {
18598
+ return void 0;
18599
+ }
18600
+ /**
18601
+ * Bash string literals: quoted strings and raw ($'...') strings.
18602
+ */
18603
+ isStringLiteral(node) {
18604
+ return node.type === "string" || node.type === "raw_string" || node.type === "ansi_c_string";
18605
+ }
18606
+ /**
18607
+ * Extract string value from bash string literal, stripping quotes.
18608
+ */
18609
+ getStringValue(node) {
18610
+ if (!this.isStringLiteral(node)) return void 0;
18611
+ const text = node.text;
18612
+ if (node.type === "raw_string") {
18613
+ return text.slice(1, -1);
18614
+ }
18615
+ if (node.type === "ansi_c_string") {
18616
+ return text.slice(2, -1);
18617
+ }
18618
+ const match = text.match(/^"(.*)"$/s);
18619
+ if (match) return match[1];
18620
+ return text;
18621
+ }
18622
+ // Extraction methods — delegate to base extractors via generic walker
18623
+ extractTypes(_context) {
18624
+ return [];
18625
+ }
18626
+ extractCalls(_context) {
18627
+ return [];
18628
+ }
18629
+ extractImports(_context) {
18630
+ return [];
18631
+ }
18632
+ extractPackage(_context) {
18633
+ return void 0;
18634
+ }
18635
+ };
18636
+
18637
+ // src/languages/plugins/html.ts
18638
+ var HtmlPlugin = class extends BaseLanguagePlugin {
18639
+ id = "html";
18640
+ name = "HTML";
18641
+ extensions = [".html", ".htm", ".xhtml"];
18642
+ wasmPath = "tree-sitter-html.wasm";
18643
+ nodeTypes = {
18644
+ // HTML has no OOP constructs
18645
+ classDeclaration: [],
18646
+ interfaceDeclaration: [],
18647
+ enumDeclaration: [],
18648
+ functionDeclaration: [],
18649
+ methodDeclaration: [],
18650
+ // No expressions in HTML
18651
+ methodCall: [],
18652
+ functionCall: [],
18653
+ assignment: [],
18654
+ variableDeclaration: [],
18655
+ // No parameters
18656
+ parameter: [],
18657
+ argument: [],
18658
+ // No annotations
18659
+ annotation: [],
18660
+ decorator: [],
18661
+ // No imports
18662
+ importStatement: [],
18663
+ // No control flow
18664
+ ifStatement: [],
18665
+ forStatement: [],
18666
+ whileStatement: [],
18667
+ tryStatement: [],
18668
+ returnStatement: []
18669
+ };
18670
+ detectFramework(_context) {
18671
+ return void 0;
18672
+ }
18673
+ getBuiltinSources() {
18674
+ return [];
18675
+ }
18676
+ getBuiltinSinks() {
18677
+ return [];
18678
+ }
18679
+ getReceiverType(_node, _context) {
18680
+ return void 0;
18681
+ }
18682
+ isStringLiteral(node) {
18683
+ return node.type === "attribute_value" || node.type === "quoted_attribute_value";
18684
+ }
18685
+ getStringValue(node) {
18686
+ if (!this.isStringLiteral(node)) return void 0;
18687
+ const text = node.text;
18688
+ if (text.startsWith('"') && text.endsWith('"') || text.startsWith("'") && text.endsWith("'")) {
18689
+ return text.slice(1, -1);
18690
+ }
18691
+ return text;
18692
+ }
18693
+ extractTypes(_context) {
18694
+ return [];
18695
+ }
18696
+ extractCalls(_context) {
18697
+ return [];
18698
+ }
18699
+ extractImports(_context) {
18700
+ return [];
18701
+ }
18702
+ extractPackage(_context) {
18703
+ return void 0;
18704
+ }
18705
+ };
18706
+
18707
+ // src/languages/plugins/go.ts
18708
+ var GoPlugin = class extends BaseLanguagePlugin {
18709
+ id = "go";
18710
+ name = "Go";
18711
+ extensions = [".go"];
18712
+ wasmPath = "tree-sitter-go.wasm";
18713
+ nodeTypes = {
18714
+ // Type declarations
18715
+ classDeclaration: ["type_declaration"],
18716
+ interfaceDeclaration: ["type_declaration"],
18717
+ enumDeclaration: [],
18718
+ // Go has no enums (uses iota constants)
18719
+ functionDeclaration: ["function_declaration"],
18720
+ methodDeclaration: ["method_declaration"],
18721
+ // Expressions
18722
+ methodCall: ["call_expression"],
18723
+ functionCall: ["call_expression"],
18724
+ assignment: ["short_var_declaration", "assignment_statement", "var_declaration"],
18725
+ variableDeclaration: ["short_var_declaration", "var_declaration"],
18726
+ // Parameters and arguments
18727
+ parameter: ["parameter_declaration"],
18728
+ argument: ["argument_list"],
18729
+ // Annotations/decorators
18730
+ annotation: [],
18731
+ // Go has no annotations
18732
+ decorator: [],
18733
+ // Go has no decorators
18734
+ // Imports
18735
+ importStatement: ["import_declaration"],
18736
+ // Control flow
18737
+ ifStatement: ["if_statement"],
18738
+ forStatement: ["for_statement"],
18739
+ whileStatement: [],
18740
+ // Go uses for with condition
18741
+ tryStatement: [],
18742
+ // Go uses defer/recover
18743
+ returnStatement: ["return_statement"]
18744
+ };
18745
+ /**
18746
+ * Detect Go web frameworks from imports.
18747
+ */
18748
+ detectFramework(context) {
18749
+ const indicators = [];
18750
+ let framework;
18751
+ let confidence = 0;
18752
+ for (const imp of context.imports) {
18753
+ const path = imp.from_package || imp.imported_name;
18754
+ if (path.includes("gin-gonic/gin")) {
18755
+ framework = "gin";
18756
+ confidence = Math.max(confidence, 0.95);
18757
+ indicators.push(`import: ${path}`);
18758
+ }
18759
+ if (path.includes("labstack/echo")) {
18760
+ framework = "echo";
18761
+ confidence = Math.max(confidence, 0.95);
18762
+ indicators.push(`import: ${path}`);
18763
+ }
18764
+ if (path.includes("gofiber/fiber")) {
18765
+ framework = "fiber";
18766
+ confidence = Math.max(confidence, 0.95);
18767
+ indicators.push(`import: ${path}`);
18768
+ }
18769
+ if (path.includes("go-chi/chi")) {
18770
+ framework = "chi";
18771
+ confidence = Math.max(confidence, 0.9);
18772
+ indicators.push(`import: ${path}`);
18773
+ }
18774
+ if (path.includes("gorm.io/gorm")) {
18775
+ indicators.push(`import: ${path}`);
18776
+ }
18777
+ if (path === "net/http") {
18778
+ framework = framework || "net/http";
18779
+ confidence = Math.max(confidence, 0.8);
18780
+ indicators.push(`import: ${path}`);
18781
+ }
18782
+ }
18783
+ if (framework) {
18784
+ return { name: framework, confidence, indicators };
18785
+ }
18786
+ return void 0;
18787
+ }
18788
+ /**
18789
+ * Go taint source patterns.
18790
+ */
18791
+ getBuiltinSources() {
18792
+ return [
18793
+ // net/http request methods
18794
+ {
18795
+ method: "FormValue",
18796
+ class: "Request",
18797
+ type: "http_param",
18798
+ severity: "high",
18799
+ confidence: 0.95,
18800
+ returnTainted: true
18801
+ },
18802
+ {
18803
+ method: "PostFormValue",
18804
+ class: "Request",
18805
+ type: "http_param",
18806
+ severity: "high",
18807
+ confidence: 0.95,
18808
+ returnTainted: true
18809
+ },
18810
+ {
18811
+ method: "Query",
18812
+ class: "URL",
18813
+ type: "http_param",
18814
+ severity: "high",
18815
+ confidence: 0.95,
18816
+ returnTainted: true
18817
+ },
18818
+ {
18819
+ method: "Get",
18820
+ class: "Header",
18821
+ type: "http_header",
18822
+ severity: "high",
18823
+ confidence: 0.9,
18824
+ returnTainted: true
18825
+ },
18826
+ {
18827
+ method: "Cookie",
18828
+ class: "Request",
18829
+ type: "http_cookie",
18830
+ severity: "high",
18831
+ confidence: 0.9,
18832
+ returnTainted: true
18833
+ },
18834
+ // Gin framework
18835
+ {
18836
+ method: "Query",
18837
+ class: "Context",
18838
+ type: "http_param",
18839
+ severity: "high",
18840
+ confidence: 0.95,
18841
+ returnTainted: true
18842
+ },
18843
+ {
18844
+ method: "Param",
18845
+ class: "Context",
18846
+ type: "http_path",
18847
+ severity: "high",
18848
+ confidence: 0.95,
18849
+ returnTainted: true
18850
+ },
18851
+ {
18852
+ method: "PostForm",
18853
+ class: "Context",
18854
+ type: "http_param",
18855
+ severity: "high",
18856
+ confidence: 0.95,
18857
+ returnTainted: true
18858
+ },
18859
+ {
18860
+ method: "GetRawData",
18861
+ class: "Context",
18862
+ type: "http_body",
18863
+ severity: "high",
18864
+ confidence: 0.95,
18865
+ returnTainted: true
18866
+ },
18867
+ // Standard library I/O
18868
+ {
18869
+ method: "Getenv",
18870
+ class: "os",
18871
+ type: "env_var",
18872
+ severity: "medium",
18873
+ confidence: 0.85,
18874
+ returnTainted: true
18875
+ },
18876
+ {
18877
+ method: "ReadAll",
18878
+ class: "io",
18879
+ type: "io_input",
18880
+ severity: "medium",
18881
+ confidence: 0.8,
18882
+ returnTainted: true
18883
+ },
18884
+ {
18885
+ method: "ReadFile",
18886
+ class: "os",
18887
+ type: "file_input",
18888
+ severity: "medium",
18889
+ confidence: 0.8,
18890
+ returnTainted: true
17894
18891
  },
17895
18892
  {
17896
- method: "ksh",
17897
- type: "command_injection",
17898
- cwe: "CWE-78",
18893
+ method: "Text",
18894
+ class: "Scanner",
18895
+ type: "io_input",
18896
+ severity: "medium",
18897
+ confidence: 0.8,
18898
+ returnTainted: true
18899
+ }
18900
+ ];
18901
+ }
18902
+ /**
18903
+ * Go taint sink patterns.
18904
+ */
18905
+ getBuiltinSinks() {
18906
+ return [
18907
+ // SQL Injection
18908
+ {
18909
+ method: "Query",
18910
+ class: "DB",
18911
+ type: "sql_injection",
18912
+ cwe: "CWE-89",
17899
18913
  severity: "critical",
17900
- argPositions: [1]
18914
+ argPositions: [0]
17901
18915
  },
17902
- // SQL injection via DB CLI clients (first arg is query/expression)
17903
18916
  {
17904
- method: "mysql",
18917
+ method: "QueryRow",
18918
+ class: "DB",
17905
18919
  type: "sql_injection",
17906
18920
  cwe: "CWE-89",
17907
18921
  severity: "critical",
17908
- argPositions: [1]
18922
+ argPositions: [0]
17909
18923
  },
17910
18924
  {
17911
- method: "psql",
18925
+ method: "Exec",
18926
+ class: "DB",
17912
18927
  type: "sql_injection",
17913
18928
  cwe: "CWE-89",
17914
18929
  severity: "critical",
17915
- argPositions: [1]
18930
+ argPositions: [0]
17916
18931
  },
17917
18932
  {
17918
- method: "sqlite3",
18933
+ method: "Query",
18934
+ class: "Tx",
17919
18935
  type: "sql_injection",
17920
18936
  cwe: "CWE-89",
17921
18937
  severity: "critical",
17922
- argPositions: [1]
18938
+ argPositions: [0]
17923
18939
  },
17924
- // Path traversal via file operations (first arg is path)
18940
+ // Command Injection
17925
18941
  {
17926
- method: "cat",
17927
- type: "path_traversal",
17928
- cwe: "CWE-22",
17929
- severity: "high",
18942
+ method: "Command",
18943
+ class: "exec",
18944
+ type: "command_injection",
18945
+ cwe: "CWE-78",
18946
+ severity: "critical",
17930
18947
  argPositions: [0]
17931
18948
  },
17932
18949
  {
17933
- method: "rm",
18950
+ method: "CommandContext",
18951
+ class: "exec",
18952
+ type: "command_injection",
18953
+ cwe: "CWE-78",
18954
+ severity: "critical",
18955
+ argPositions: [1]
18956
+ },
18957
+ // Path Traversal
18958
+ {
18959
+ method: "Open",
18960
+ class: "os",
17934
18961
  type: "path_traversal",
17935
18962
  cwe: "CWE-22",
17936
18963
  severity: "high",
17937
18964
  argPositions: [0]
17938
18965
  },
17939
18966
  {
17940
- method: "cp",
18967
+ method: "ReadFile",
18968
+ class: "os",
17941
18969
  type: "path_traversal",
17942
18970
  cwe: "CWE-22",
17943
18971
  severity: "high",
17944
18972
  argPositions: [0]
17945
18973
  },
17946
18974
  {
17947
- method: "mv",
18975
+ method: "WriteFile",
18976
+ class: "os",
17948
18977
  type: "path_traversal",
17949
18978
  cwe: "CWE-22",
17950
18979
  severity: "high",
17951
18980
  argPositions: [0]
17952
18981
  },
18982
+ // XSS (writing to http.ResponseWriter without escaping)
17953
18983
  {
17954
- method: "chmod",
17955
- type: "path_traversal",
17956
- cwe: "CWE-22",
17957
- severity: "medium",
18984
+ method: "Fprintf",
18985
+ class: "fmt",
18986
+ type: "xss",
18987
+ cwe: "CWE-79",
18988
+ severity: "high",
17958
18989
  argPositions: [1]
17959
18990
  },
17960
18991
  {
17961
- method: "chown",
17962
- type: "path_traversal",
17963
- cwe: "CWE-22",
17964
- severity: "medium",
17965
- argPositions: [1]
18992
+ method: "Write",
18993
+ class: "ResponseWriter",
18994
+ type: "xss",
18995
+ cwe: "CWE-79",
18996
+ severity: "high",
18997
+ argPositions: [0]
17966
18998
  },
17967
- // SSRF — curl/wget with externally-controlled URL
18999
+ // SSRF
17968
19000
  {
17969
- method: "curl",
19001
+ method: "Get",
19002
+ class: "http",
17970
19003
  type: "ssrf",
17971
19004
  cwe: "CWE-918",
17972
19005
  severity: "high",
17973
19006
  argPositions: [0]
17974
19007
  },
17975
19008
  {
17976
- method: "wget",
19009
+ method: "Post",
19010
+ class: "http",
17977
19011
  type: "ssrf",
17978
19012
  cwe: "CWE-918",
17979
19013
  severity: "high",
19014
+ argPositions: [0, 2]
19015
+ },
19016
+ // Deserialization
19017
+ {
19018
+ method: "Unmarshal",
19019
+ class: "json",
19020
+ type: "deserialization",
19021
+ cwe: "CWE-502",
19022
+ severity: "medium",
19023
+ argPositions: [0]
19024
+ },
19025
+ {
19026
+ method: "Decode",
19027
+ class: "Decoder",
19028
+ type: "deserialization",
19029
+ cwe: "CWE-502",
19030
+ severity: "medium",
17980
19031
  argPositions: [0]
17981
19032
  }
17982
19033
  ];
17983
19034
  }
17984
19035
  /**
17985
- * Shell has no OOP receiver types.
19036
+ * Get receiver type from a Go call expression.
17986
19037
  */
17987
- getReceiverType(_node, _context) {
19038
+ getReceiverType(node, _context) {
19039
+ if (node.type !== "call_expression") return void 0;
19040
+ const func2 = node.childForFieldName("function");
19041
+ if (!func2) return void 0;
19042
+ if (func2.type === "selector_expression") {
19043
+ const operand = func2.childForFieldName("operand");
19044
+ if (operand) {
19045
+ return operand.text;
19046
+ }
19047
+ }
17988
19048
  return void 0;
17989
19049
  }
17990
19050
  /**
17991
- * Bash string literals: quoted strings and raw ($'...') strings.
19051
+ * Check if node is a Go string literal.
17992
19052
  */
17993
19053
  isStringLiteral(node) {
17994
- return node.type === "string" || node.type === "raw_string" || node.type === "ansi_c_string";
19054
+ return node.type === "interpreted_string_literal" || node.type === "raw_string_literal";
17995
19055
  }
17996
19056
  /**
17997
- * Extract string value from bash string literal, stripping quotes.
19057
+ * Get string value from Go string literal.
17998
19058
  */
17999
19059
  getStringValue(node) {
18000
19060
  if (!this.isStringLiteral(node)) return void 0;
18001
19061
  const text = node.text;
18002
- if (node.type === "raw_string") {
19062
+ if (text.startsWith("`") && text.endsWith("`")) {
18003
19063
  return text.slice(1, -1);
18004
19064
  }
18005
- if (node.type === "ansi_c_string") {
18006
- return text.slice(2, -1);
19065
+ if (text.startsWith('"') && text.endsWith('"')) {
19066
+ return text.slice(1, -1);
18007
19067
  }
18008
- const match = text.match(/^"(.*)"$/s);
18009
- if (match) return match[1];
18010
19068
  return text;
18011
19069
  }
18012
- // Extraction methods — delegate to base extractors via generic walker
18013
- extractTypes(_context) {
18014
- return [];
18015
- }
18016
- extractCalls(_context) {
18017
- return [];
18018
- }
18019
- extractImports(_context) {
18020
- return [];
18021
- }
18022
- extractPackage(_context) {
18023
- return void 0;
18024
- }
18025
- };
18026
-
18027
- // src/languages/plugins/html.ts
18028
- var HtmlPlugin = class extends BaseLanguagePlugin {
18029
- id = "html";
18030
- name = "HTML";
18031
- extensions = [".html", ".htm", ".xhtml"];
18032
- wasmPath = "tree-sitter-html.wasm";
18033
- nodeTypes = {
18034
- // HTML has no OOP constructs
18035
- classDeclaration: [],
18036
- interfaceDeclaration: [],
18037
- enumDeclaration: [],
18038
- functionDeclaration: [],
18039
- methodDeclaration: [],
18040
- // No expressions in HTML
18041
- methodCall: [],
18042
- functionCall: [],
18043
- assignment: [],
18044
- variableDeclaration: [],
18045
- // No parameters
18046
- parameter: [],
18047
- argument: [],
18048
- // No annotations
18049
- annotation: [],
18050
- decorator: [],
18051
- // No imports
18052
- importStatement: [],
18053
- // No control flow
18054
- ifStatement: [],
18055
- forStatement: [],
18056
- whileStatement: [],
18057
- tryStatement: [],
18058
- returnStatement: []
18059
- };
18060
- detectFramework(_context) {
18061
- return void 0;
19070
+ /**
19071
+ * Extract type information from Go source.
19072
+ */
19073
+ extractTypes(context) {
19074
+ const types = [];
19075
+ const root = context.tree.rootNode;
19076
+ const typeDecls = this.findNodes(root, "type_declaration");
19077
+ for (const decl of typeDecls) {
19078
+ for (let i2 = 0; i2 < decl.childCount; i2++) {
19079
+ const spec = decl.child(i2);
19080
+ if (!spec || spec.type !== "type_spec") continue;
19081
+ const nameNode = spec.childForFieldName("name");
19082
+ const typeNode = spec.childForFieldName("type");
19083
+ if (!nameNode || !typeNode) continue;
19084
+ const name2 = nameNode.text;
19085
+ const isInterface = typeNode.type === "interface_type";
19086
+ const isStruct = typeNode.type === "struct_type";
19087
+ if (isStruct || isInterface) {
19088
+ const fields = [];
19089
+ const methods = [];
19090
+ if (isStruct) {
19091
+ const fieldList = typeNode.childForFieldName("fields") ?? this.findChildByType(typeNode, "field_declaration_list");
19092
+ if (fieldList) {
19093
+ for (let j = 0; j < fieldList.childCount; j++) {
19094
+ const field = fieldList.child(j);
19095
+ if (!field || field.type !== "field_declaration") continue;
19096
+ const fieldName = field.childForFieldName("name");
19097
+ const fieldType = field.childForFieldName("type");
19098
+ if (fieldName) {
19099
+ fields.push({
19100
+ name: fieldName.text,
19101
+ type: fieldType?.text || null,
19102
+ modifiers: [],
19103
+ annotations: []
19104
+ });
19105
+ }
19106
+ }
19107
+ }
19108
+ }
19109
+ const methodDecls = this.findNodes(root, "method_declaration");
19110
+ for (const md of methodDecls) {
19111
+ const receiver = md.childForFieldName("receiver");
19112
+ if (!receiver) continue;
19113
+ const receiverText = receiver.text;
19114
+ if (receiverText.includes(name2)) {
19115
+ const methodName = md.childForFieldName("name");
19116
+ const params = md.childForFieldName("parameters");
19117
+ const result = md.childForFieldName("result");
19118
+ if (methodName) {
19119
+ methods.push({
19120
+ name: methodName.text,
19121
+ return_type: result?.text || null,
19122
+ parameters: params ? this.extractGoParams(params) : [],
19123
+ annotations: [],
19124
+ modifiers: [],
19125
+ start_line: md.startPosition.row + 1,
19126
+ end_line: md.endPosition.row + 1
19127
+ });
19128
+ }
19129
+ }
19130
+ }
19131
+ types.push({
19132
+ name: name2,
19133
+ kind: isInterface ? "interface" : "class",
19134
+ package: context.package || null,
19135
+ extends: null,
19136
+ implements: [],
19137
+ annotations: [],
19138
+ methods,
19139
+ fields,
19140
+ start_line: decl.startPosition.row + 1,
19141
+ end_line: decl.endPosition.row + 1
19142
+ });
19143
+ }
19144
+ }
19145
+ }
19146
+ return types;
18062
19147
  }
18063
- getBuiltinSources() {
18064
- return [];
19148
+ /**
19149
+ * Extract call information from Go source.
19150
+ */
19151
+ extractCalls(context) {
19152
+ const calls = [];
19153
+ const root = context.tree.rootNode;
19154
+ const callExprs = this.findNodes(root, "call_expression");
19155
+ for (const call of callExprs) {
19156
+ const func2 = call.childForFieldName("function");
19157
+ if (!func2) continue;
19158
+ let methodName;
19159
+ let receiver = null;
19160
+ if (func2.type === "selector_expression") {
19161
+ const operand = func2.childForFieldName("operand");
19162
+ const field = func2.childForFieldName("field");
19163
+ receiver = operand?.text || null;
19164
+ methodName = field?.text || func2.text;
19165
+ } else {
19166
+ methodName = func2.text;
19167
+ }
19168
+ const args2 = call.childForFieldName("arguments");
19169
+ const argInfos = [];
19170
+ let argPos = 0;
19171
+ if (args2) {
19172
+ for (let i2 = 0; i2 < args2.childCount; i2++) {
19173
+ const arg = args2.child(i2);
19174
+ if (arg && arg.type !== "(" && arg.type !== ")" && arg.type !== ",") {
19175
+ argInfos.push({
19176
+ position: argPos++,
19177
+ expression: arg.text,
19178
+ variable: arg.type === "identifier" ? arg.text : null,
19179
+ literal: arg.type === "interpreted_string_literal" || arg.type === "int_literal" ? arg.text : null
19180
+ });
19181
+ }
19182
+ }
19183
+ }
19184
+ calls.push({
19185
+ method_name: methodName,
19186
+ receiver,
19187
+ arguments: argInfos,
19188
+ location: {
19189
+ line: call.startPosition.row + 1,
19190
+ column: call.startPosition.column
19191
+ }
19192
+ });
19193
+ }
19194
+ return calls;
18065
19195
  }
18066
- getBuiltinSinks() {
18067
- return [];
19196
+ /**
19197
+ * Extract import information from Go source.
19198
+ */
19199
+ extractImports(context) {
19200
+ const imports = [];
19201
+ const root = context.tree.rootNode;
19202
+ const importDecls = this.findNodes(root, "import_declaration");
19203
+ for (const decl of importDecls) {
19204
+ const singleSpec = this.findChildByType(decl, "import_spec");
19205
+ if (singleSpec) {
19206
+ const parsed = this.parseImportSpec(singleSpec);
19207
+ if (parsed) imports.push(parsed);
19208
+ continue;
19209
+ }
19210
+ const specList = this.findChildByType(decl, "import_spec_list");
19211
+ if (specList) {
19212
+ for (let i2 = 0; i2 < specList.childCount; i2++) {
19213
+ const spec = specList.child(i2);
19214
+ if (!spec || spec.type !== "import_spec") continue;
19215
+ const parsed = this.parseImportSpec(spec);
19216
+ if (parsed) imports.push(parsed);
19217
+ }
19218
+ }
19219
+ }
19220
+ return imports;
18068
19221
  }
18069
- getReceiverType(_node, _context) {
19222
+ /**
19223
+ * Extract package name from Go source.
19224
+ */
19225
+ extractPackage(context) {
19226
+ const root = context.tree.rootNode;
19227
+ const pkgClause = this.findChildByType(root, "package_clause");
19228
+ if (!pkgClause) return void 0;
19229
+ for (let i2 = 0; i2 < pkgClause.childCount; i2++) {
19230
+ const child = pkgClause.child(i2);
19231
+ if (child && child.type === "package_identifier") {
19232
+ return child.text;
19233
+ }
19234
+ }
18070
19235
  return void 0;
18071
19236
  }
18072
- isStringLiteral(node) {
18073
- return node.type === "attribute_value" || node.type === "quoted_attribute_value";
18074
- }
18075
- getStringValue(node) {
18076
- if (!this.isStringLiteral(node)) return void 0;
18077
- const text = node.text;
18078
- if (text.startsWith('"') && text.endsWith('"') || text.startsWith("'") && text.endsWith("'")) {
18079
- return text.slice(1, -1);
19237
+ // ── Private helpers ─────────────────────────────────────────────────────
19238
+ parseImportSpec(spec) {
19239
+ let alias = null;
19240
+ let path;
19241
+ for (let i2 = 0; i2 < spec.childCount; i2++) {
19242
+ const child = spec.child(i2);
19243
+ if (!child) continue;
19244
+ if (child.type === "package_identifier" || child.type === "blank_identifier" || child.type === "dot") {
19245
+ alias = child.text;
19246
+ }
19247
+ if (child.type === "interpreted_string_literal") {
19248
+ path = child.text.slice(1, -1);
19249
+ }
18080
19250
  }
18081
- return text;
18082
- }
18083
- extractTypes(_context) {
18084
- return [];
18085
- }
18086
- extractCalls(_context) {
18087
- return [];
18088
- }
18089
- extractImports(_context) {
18090
- return [];
19251
+ if (!path) return null;
19252
+ const shortName = alias || path.split("/").pop() || path;
19253
+ return {
19254
+ imported_name: shortName,
19255
+ from_package: path,
19256
+ alias,
19257
+ is_wildcard: alias === ".",
19258
+ line_number: spec.startPosition.row + 1
19259
+ };
18091
19260
  }
18092
- extractPackage(_context) {
18093
- return void 0;
19261
+ extractGoParams(params) {
19262
+ const result = [];
19263
+ for (let i2 = 0; i2 < params.childCount; i2++) {
19264
+ const param = params.child(i2);
19265
+ if (!param || param.type !== "parameter_declaration") continue;
19266
+ const nameNode = param.childForFieldName("name");
19267
+ const typeNode = param.childForFieldName("type");
19268
+ if (nameNode) {
19269
+ result.push({
19270
+ name: nameNode.text,
19271
+ type: typeNode?.text || null,
19272
+ annotations: []
19273
+ });
19274
+ }
19275
+ }
19276
+ return result;
18094
19277
  }
18095
19278
  };
18096
19279
 
@@ -18102,6 +19285,7 @@ function registerBuiltinPlugins() {
18102
19285
  registerLanguage(new RustPlugin());
18103
19286
  registerLanguage(new BashPlugin());
18104
19287
  registerLanguage(new HtmlPlugin());
19288
+ registerLanguage(new GoPlugin());
18105
19289
  }
18106
19290
 
18107
19291
  // src/utils/logger.ts
@@ -24327,6 +25511,26 @@ function getNodeTypesForLanguage(language) {
24327
25511
  "self_closing_tag",
24328
25512
  "text"
24329
25513
  ]);
25514
+ case "go":
25515
+ return /* @__PURE__ */ new Set([
25516
+ "call_expression",
25517
+ "function_declaration",
25518
+ "method_declaration",
25519
+ "package_clause",
25520
+ "import_declaration",
25521
+ "import_spec",
25522
+ "var_declaration",
25523
+ "short_var_declaration",
25524
+ "assignment_statement",
25525
+ "type_declaration",
25526
+ "if_statement",
25527
+ "for_statement",
25528
+ "return_statement",
25529
+ "defer_statement",
25530
+ "go_statement",
25531
+ "selector_expression",
25532
+ "identifier"
25533
+ ]);
24330
25534
  default:
24331
25535
  return /* @__PURE__ */ new Set([
24332
25536
  "method_invocation",