// grpc-sql benchmark case // Demonstrates SQL injection sink reachable via gRPC handler package main import ( "context" "database/sql" "fmt" "log" "net" _ "github.com/mattn/go-sqlite3" "google.golang.org/grpc" ) // User represents a user record type User struct { ID string Name string Email string } // userServer implements the gRPC UserService type userServer struct { db *sql.DB } // GetUser - VULNERABLE: SQL injection sink // User ID is concatenated directly into SQL query func (s *userServer) GetUser(ctx context.Context, userID string) (*User, error) { // SINK: database/sql.Query with string concatenation query := fmt.Sprintf("SELECT id, name, email FROM users WHERE id = '%s'", userID) row := s.db.QueryRow(query) var user User if err := row.Scan(&user.ID, &user.Name, &user.Email); err != nil { return nil, fmt.Errorf("user not found: %w", err) } return &user, nil } // GetUserSafe - SAFE: uses parameterized query func (s *userServer) GetUserSafe(ctx context.Context, userID string) (*User, error) { query := "SELECT id, name, email FROM users WHERE id = ?" row := s.db.QueryRow(query, userID) var user User if err := row.Scan(&user.ID, &user.Name, &user.Email); err != nil { return nil, fmt.Errorf("user not found: %w", err) } return &user, nil } func main() { db, err := sql.Open("sqlite3", ":memory:") if err != nil { log.Fatalf("failed to open database: %v", err) } defer db.Close() // Initialize schema _, err = db.Exec(` CREATE TABLE users ( id TEXT PRIMARY KEY, name TEXT, email TEXT ) `) if err != nil { log.Fatalf("failed to create table: %v", err) } lis, err := net.Listen("tcp", ":50051") if err != nil { log.Fatalf("failed to listen: %v", err) } s := grpc.NewServer() // Register service here (simplified for benchmark) log.Printf("gRPC server listening on %v", lis.Addr()) if err := s.Serve(lis); err != nil { log.Fatalf("failed to serve: %v", err) } }