NEWBravos is availableCreate your account
The Knowledge Base
8 min read

gRPC Reflection API Abuse: Service Enumeration and Data Exposure

Network Service ExploitsBy BugB Security Team

Detect gRPC services with reflection API enabled that expose internal service definitions, methods, and message schemas to unauthenticated clients.

Executive Summary

The gRPC Server Reflection API is a powerful development tool that allows clients to discover service definitions, methods, and message types at runtime — without requiring .proto files. When left enabled in production, it becomes a free reconnaissance interface: attackers can enumerate every service your application exposes, understand its internal architecture, and craft targeted attacks against specific endpoints.

The result? Full API surface mapping without authentication. An attacker with network access to a gRPC port can list all registered services, identify sensitive internal endpoints (admin, billing, auth), and use tools like grpcurl to interact with them directly.

Key Insight: Detecting this exposure requires establishing an actual gRPC connection, sending a reflection ListServices RPC, and semantically analyzing the response — none of which is achievable with YAML pattern matching or simple banner grabs. CERT-X-GEN's Go template handles the full gRPC wire protocol natively.

Quick Stats

MetricValue
CVSS Score5.3 (Medium) — enumeration only; escalates with exposed sensitive services
CWECWE-200 (Information Exposure), CWE-538 (Insertion of Sensitive Information)
Common Ports9090, 50051, 8080, 443 (gRPC)
Detection ComplexityMedium (requires gRPC protocol handling)
Exploitation DifficultyLow (grpcurl one-liner once port is reachable)

Run this check with CERT-X-GEN — the polyglot security scanner that executes templates in real programming languages. Get the templates | Install CERT-X-GEN

Template source: grpc-reflection-abuse.go

Understanding the Vulnerability

What is gRPC Reflection?

gRPC Reflection is a standard gRPC service (grpc.reflection.v1alpha.ServerReflection) that servers can register alongside their business services. Once registered, any client can query it to discover:

  • All registered service names
  • Method signatures for each service
  • Full protobuf message schemas (field names, types, nesting)
  • Streaming vs. unary method types

This is invaluable during development — tools like grpcurl and grpcui rely on it. In production, it is an information disclosure vulnerability.

The Attack Surface

Exposure LevelWhat Attacker LearnsSeverity
Reflection enabled, few servicesService names, basic API structureMedium
Reflection enabled, many servicesFull microservice architecture mapHigh
Sensitive service names exposedInternal services (admin, auth, payment, billing)High
No authentication on reflectionEverything above, zero credentials neededHigh

How the Attack Works

┌─────────────────────────────────────────────────────────────────┐
│            gRPC REFLECTION ABUSE ATTACK FLOW                     │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  1. Attacker discovers open gRPC port (50051, 9090, etc.)       │
│                         ↓                                        │
│  2. Attacker sends ListServices reflection RPC                   │
│                         ↓                                        │
│  3. Server returns all registered service names                  │
│     e.g., myapp.AdminService, myapp.PaymentService              │
│                         ↓                                        │
│  4. Attacker queries FileContainingSymbol for each service       │
│                         ↓                                        │
│  5. Server returns full .proto definitions:                      │
│     methods, message types, field names, enums                   │
│                         ↓                                        │
│  6. Attacker now has complete API blueprint                      │
│     Can craft targeted calls to any method                       │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

Why This Happens

  1. Copy-paste from tutorials: Most gRPC quickstarts include reflection.Register(grpcServer) — developers copy it and never remove it
  2. No runtime cost: Unlike debug endpoints, reflection has negligible overhead, so there is no performance incentive to disable it
  3. Invisible exposure: There is no HTTP path or banner to scan — you only find it by speaking gRPC
  4. Framework defaults: Some frameworks (e.g., grpc-go health check examples) register reflection alongside health services

Why Traditional Scanners Fall Short

CapabilityYAML ScannerCERT-X-GEN (Go)
gRPC wire protocol❌ Cannot speak HTTP/2 + gRPC✅ Native google.golang.org/grpc
Reflection RPC call❌ No protobuf serialization✅ Full ServerReflectionInfo stream
Service enumeration❌ Cannot parse reflection responses✅ Iterates and classifies services
Sensitive name detection❌ No semantic analysis✅ Keyword matching against service names
Severity classification❌ Static severity✅ Dynamic: info → medium → high based on findings

The CERT-X-GEN Approach

The template implements a multi-stage detection strategy:

Stage 1 — Connection: Establishes a gRPC connection to the target with configurable timeout. Uses insecure credentials (plaintext) since exposed reflection services rarely use mTLS.

Stage 2 — Reflection Query: Creates a ServerReflectionClient and opens a bidirectional stream. Sends a ListServices request to enumerate all registered services.

Stage 3 — Service Analysis: Filters out the reflection service itself, then classifies each service name against a sensitive keyword list (admin, internal, payment, credential, auth, secret, etc.).

Stage 4 — Severity Assignment: Dynamically assigns severity based on what was found:

ConditionSeverity
Reflection not availableInfo
Reflection enabled, no servicesLow
≤2 services, no sensitive namesMedium
Multiple services exposedHigh
Sensitive service names foundHigh

Key Template Code: Service Enumeration

go
// Connect and query reflection
client := grpc_reflection_v1alpha.NewServerReflectionClient(conn)
stream, err := client.ServerReflectionInfo(ctx)

// Request all services
stream.Send(&grpc_reflection_v1alpha.ServerReflectionRequest{
    MessageRequest: &grpc_reflection_v1alpha.ServerReflectionRequest_ListServices{
        ListServices: "*",
    },
})

// Parse response
resp, _ := stream.Recv()
for _, service := range resp.GetListServicesResponse().Service {
    if isSensitiveServiceName(service.Name) {
        result.HasSensitiveNames = true
        result.SensitiveServices = append(result.SensitiveServices, service.Name)
    }
}

Key Template Code: Sensitive Name Detection

go
func isSensitiveServiceName(serviceName string) bool {
    sensitiveKeywords := []string{
        "admin", "internal", "private", "debug", "test",
        "management", "auth", "user", "account", "payment",
        "billing", "credential", "secret", "token", "key",
    }
    lowerName := strings.ToLower(serviceName)
    for _, keyword := range sensitiveKeywords {
        if strings.Contains(lowerName, keyword) {
            return true
        }
    }
    return false
}

Usage Guide

Running the Template

bash
# Basic scan
cxg scan --scope target.com:50051 --templates grpc-reflection-abuse.go

# Multiple ports
cxg scan --scope target.com:9090 --templates grpc-reflection-abuse.go
cxg scan --scope target.com:50051 --templates grpc-reflection-abuse.go

# With extended timeout for slow networks
cxg scan --scope target.com:50051 --templates grpc-reflection-abuse.go --timeout 30s

# JSON output for pipeline integration
cxg scan --scope target.com:50051 --templates grpc-reflection-abuse.go --json

Manual Verification with grpcurl

bash
# Quick check — if this returns service names, reflection is exposed
grpcurl -plaintext target.com:50051 list

# Describe a specific service
grpcurl -plaintext target.com:50051 describe myapp.AdminService

# Should return error if properly secured
grpcurl -plaintext target.com:50051 list 2>&1 | grep -i "unimplemented\|unknown service"

Expected Output

Vulnerable system (sensitive services exposed):

json
{
  "findings": [
    {
      "target": "target.com:50051",
      "template_id": "grpc-reflection-abuse",
      "severity": "high",
      "confidence": 95,
      "title": "gRPC Reflection Exposes Sensitive Services",
      "description": "Reflection API enabled and exposes 8 service(s), including 3 with sensitive names.",
      "evidence": {
        "reflection_enabled": true,
        "service_count": 8,
        "services": [
          "myapp.UserService",
          "myapp.AdminService",
          "myapp.PaymentService",
          "myapp.OrderService",
          "myapp.InternalMetrics",
          "myapp.HealthCheck",
          "myapp.ProductCatalog",
          "myapp.NotificationService"
        ],
        "has_sensitive_names": true,
        "sensitive_services": [
          "myapp.AdminService",
          "myapp.PaymentService",
          "myapp.InternalMetrics"
        ]
      }
    }
  ]
}

Secure system (reflection disabled):

json
{
  "findings": [
    {
      "target": "target.com:50051",
      "template_id": "grpc-reflection-abuse",
      "severity": "info",
      "confidence": 50,
      "title": "gRPC Reflection Not Available",
      "description": "gRPC reflection service not accessible: connection failed or reflection unimplemented"
    }
  ]
}

Defense & Remediation

Immediate Fix

go
// Remove or conditionally register reflection
// BEFORE (vulnerable):
reflection.Register(grpcServer)

// AFTER (environment-gated):
if os.Getenv("ENABLE_GRPC_REFLECTION") == "true" {
    reflection.Register(grpcServer)
}

Comprehensive Hardening

ActionPriorityEffort
Remove reflection.Register() from production buildsCriticalLow
Use build tags to exclude reflection in release buildsHighLow
Implement mTLS for all gRPC servicesHighMedium
Add NetworkPolicy to restrict gRPC port accessHighLow
Deploy gRPC-aware firewall/proxy (Envoy, Istio)MediumMedium
Implement per-method authorization interceptorsMediumMedium
Monitor for reflection queries in production logsLowLow

Language-Specific Disabling

Go:

go
// Use build tags
//go:build dev
reflection.Register(grpcServer)

Python:

python
# Only in development
if settings.DEBUG:
    from grpc_reflection.v1alpha import reflection
    reflection.enable_server_reflection(SERVICE_NAMES, server)

Java:

java
// Conditional registration
if (System.getenv("ENABLE_REFLECTION") != null) {
    ProtoReflectionService.newInstance();
}

Verification

bash
# After remediation — should fail with "unimplemented" or connection refused
grpcurl -plaintext your-server.com:50051 list 2>&1 | grep -i "unimplemented\|unknown service\|refused"

Extending the Template

Testing Multiple Ports

go
func scanMultiplePorts(host string) []Finding {
    ports := []int{9090, 50051, 8080, 443}
    allFindings := []Finding{}
    for _, port := range ports {
        findings := testVulnerability(host, port, 10)
        allFindings = append(allFindings, findings...)
    }
    return allFindings
}

Custom Sensitive Keywords

go
func loadSensitiveKeywords() []string {
    keywords := []string{
        "admin", "internal", "private",
        // Add organization-specific terms
        "mycompany", "confidential", "restricted",
    }
    if data, err := os.ReadFile("keywords.txt"); err == nil {
        lines := strings.Split(string(data), "\n")
        keywords = append(keywords, lines...)
    }
    return keywords
}

References

gRPC Reflection Protocol:

Tools:

  • grpcurl — Command-line gRPC client with reflection support
  • grpcui — Web UI for gRPC with reflection

Security Research:

  • CWE-200: Exposure of Sensitive Information
  • CWE-538: Insertion of Sensitive Information into Externally-Accessible File
  • OWASP API Security Top 10

For questions or contributions, see: cert-x-gen-templates

Need help hardening your environment?

Talk to the Bugb security team directly.

Book a session