8 min read

API Security
Advanced
API8

gRPC Pentesting

gRPC uses Protocol Buffers (Protobuf) for serialization and HTTP/2 for transport. Testing requires tools that can understand the binary format and interact with the service definitions.

Authorization Required

Only test gRPC services you own or have explicit written authorization to test. Confirm the scope covers the individual services behind the gateway, not just the HTTP host in front of them — reflection enumeration and metadata injection reach the upstream service, and that traffic is indistinguishable from an attack.

Service Discovery & Reflection

gRPC Reflection lets a client ask the server which services and methods it exposes, plus their message schemas. That removes the need for a .proto file and is the first thing to check.

Using grpcurl

A single list call answers both questions — if it returns, reflection is enabled and that is the service inventory:

grpcurl — list services
# Succeeds → reflection is enabled; the output is the service list
grpcurl -plaintext localhost:50051 list

Then pull the method and message definitions for one of the services it named:

grpcurl — describe a service
grpcurl -plaintext localhost:50051 describe com.example.UserService

Describing a method gives you the full request/response schema, which is what you need to build the JSON bodies used later on this page:

grpcurl — describe a method
grpcurl -plaintext localhost:50051 describe com.example.UserService.GetUser

Without Reflection

If reflection is disabled, you need to find the .proto files. Look in mobile app packages, web assets, or public repositories. You can also try to reconstruct them from binary traffic using protoc --decode_raw.

Interacting with gRPC

Invoking Methods

Call methods using grpcurl or Postman.

grpcurl — call a method
grpcurl -plaintext -d '{"id": 1}' localhost:50051 com.example.UserService/GetUser

Intercepting Traffic

Burp Suite proxies HTTP/2 but does not decode gRPC bodies: each frame is a 5-byte header followed by length-delimited Protobuf, which Burp shows as opaque bytes. You need an extension that turns those bytes into editable fields.

Burp extensions for Protobuf

blackboxprotobuf is the extension most often used for this: it decodes a body without a .proto file and re-encodes your edits. It is a Jython extension, so see the note on Jython's status in the field-tampering section below before you build a workflow around it.

gRPC-UI

A web-based UI for interacting with gRPC services, similar to Swagger UI. It reflects the schema and gives you a form per method, which is faster than hand-writing JSON for large messages.

grpcui — browser client
grpcui -plaintext localhost:50051

Protobuf Field Tampering

Protobuf fields are identified by field numbers, not names. If you can identify the encoding, you can inject fields the client would not normally send (undocumented fields, admin flags).

Decoding captured protobuf
# Decode raw protobuf bytes to inspect field numbers
protoc --decode_raw < captured.bin

# Decode using .proto definition
protoc --decode=com.example.UserRequest user.proto < captured.bin

# Replay a modified request as JSON. grpcurl's -d @ reads JSON from
# stdin and has no raw-bytes mode, so this only reaches fields the
# loaded schema declares.
echo '{"userId": 1, "isAdmin": true}' | grpcurl -plaintext \
  -d @ localhost:50051 com.example.UserService/GetUser

Note that limit: -d takes a JSON body, and protojson rejects fields that are absent from the loaded schema. To add a field number the schema does not declare, edit the wire bytes instead: decode the capture with protoc --decode_raw, append the tag for the field you want ( field_number << 3 | wire_type) plus its value, and replay the modified frame through Burp Repeater with a Protobuf-decoding extension installed. grpcui has the same JSON-only constraint.

Intercepting gRPC in Burp

The blackboxprotobuf Burp extension decodes and re-encodes Protobuf bodies inline, which is what makes hand-editing field numbers practical. It is written for Jython: Burp's Jython Extender API is legacy and no longer actively maintained, so the extension can break on newer Burp releases — check its repo before relying on it, and prefer a Montoya-API extension where one does the same job. Set Burp to intercept HTTP/2 and install its CA in the target app. For command-line interception, mitmproxy sees the same HTTP/2 traffic and its addon API can decode and rewrite gRPC frames, though you are still editing bytes by hand.

Enum Value & Boundary Fuzzing

Protobuf enums travel as integers and the schema only documents the values the developer intended. Many servers reject an unknown value or coerce it to the default, but some let it fall through to an internal branch. Treat "an undefined enum reaches privileged logic" as a hypothesis to test, not a guaranteed finding: send the out-of-range values, record whether the response actually changes, and report only what you observed.

Enum and page-size probing
# Normal request with role=USER (enum value 0)
grpcurl -plaintext -d '{"user_id": 1, "role": 0}' localhost:50051 UserService/GetProfile

# Try enum value 1 (ADMIN), 2 (SUPERADMIN), 99 (undefined)
grpcurl -plaintext -d '{"user_id": 1, "role": 1}' localhost:50051 UserService/GetProfile
grpcurl -plaintext -d '{"user_id": 1, "role": 99}' localhost:50051 UserService/GetProfile

# Server-side streaming — test for resource exhaustion
grpcurl -plaintext -d '{"query": "", "page_size": 99999}' \
  localhost:50051 DataService/StreamAll

Authentication & mTLS Testing

gRPC services often use mTLS or JWT metadata for authentication. Test for missing or weak enforcement.

JWT in gRPC Metadata

gRPC uses metadata headers (similar to HTTP headers) for auth tokens. Test if the service validates them.

JWT in gRPC metadata
# Call with valid JWT in metadata
grpcurl -plaintext \
  -H "Authorization: Bearer eyJhbGciOi..." \
  -d '{"user_id": 1}' localhost:50051 UserService/GetProfile

# Call WITHOUT auth — does it still work?
grpcurl -plaintext -d '{"user_id": 1}' localhost:50051 UserService/GetProfile

# Tampered JWT (change role claim)
grpcurl -plaintext \
  -H "Authorization: Bearer TAMPERED_TOKEN" \
  -d '{"user_id": 1}' localhost:50051 UserService/GetProfile

mTLS Certificate Testing

If mTLS is required, test whether the server validates the client certificate properly.

mTLS client certificates
# Connect with client certificate
grpcurl -cert client.crt -key client.key -cacert ca.crt \
  target:443 list

# Test with self-signed cert (should be rejected)
openssl req -x509 -newkey rsa:2048 -keyout fake.key -out fake.crt -days 1 -nodes -subj "/CN=attacker"
grpcurl -cert fake.crt -key fake.key -cacert ca.crt \
  target:443 list

# Test without any cert (should fail if mTLS enforced)
grpcurl -cacert ca.crt target:443 list

Metadata Injection

gRPC metadata headers can be target vectors for injection if the server processes them as database queries or commands.

Injection through metadata
# Inject SQL via metadata  
grpcurl -plaintext \
  -H "X-User-Id: 1' OR 1=1--" \
  -d '{}' localhost:50051 UserService/ListUsers

# Inject via gRPC deadline metadata (unusual vector)
grpcurl -plaintext \
  -H "grpc-timeout: 999999999n" \
  -d '{"query": "*"}' localhost:50051 DataService/Search

Service Mesh Considerations

In Kubernetes environments, gRPC services are often behind service meshes like Istio or Linkerd. Test whether sidecar proxies properly enforce authorization policies.

Calling services past the mesh
# If you have pod access, try calling services directly (bypassing mesh)
# Find service IPs
kubectl get svc -A | grep grpc

# Direct call bypassing Istio sidecar
grpcurl -plaintext SERVICE_IP:50051 list

# Check if AuthorizationPolicy is enforced
# Try accessing admin services from non-admin namespace pods

Evidence Collection

For a gRPC finding, capture:

Discovery output: The grpcurl list and describe output, or the reconstructed proto file, with the endpoint and whether reflection was enabled in production.

Message and status: The request payload in protobuf JSON form, the response, and the gRPC status code with its message from the trailers — a gRPC failure is not an HTTP body.

Certificate identity: For mTLS: which client certificate was presented, whether a self-signed or foreign-service certificate was accepted, and whether a certificate was required at all.

False Positive Identification

  • Reflection inside a trusted network: A reflection-enabled service unreachable from an untrusted network is a hardening note, not an exposure. Establish where you are on the network before recording it.
  • A field that "disappeared": Protobuf omits fields at their default value, so an absent field in the response is not proof a write was dropped. Set a non-default value, then read it back.

Testing Checklist

Surface

  • ☐ Enumerate services and methods by reflection, then confirm which are reachable from your network position and whether the gateway enforces auth the upstream service also enforces.

Messages and transport

  • ☐ Tamper every field: out-of-range integers, unknown enum values, wrong wire types, oversized strings and omitted required fields.
  • ☐ Test the handshake with no certificate, a self-signed one, an expired one and one issued for another service.
  • ☐ Inject into metadata headers (identity, tenant, role) and check the mesh policy from a non-privileged workload.

Remediation & Defense

gRPC has no browser to lean on: every control has to be enforced by the service or the mesh in front of it.

Expose less

  • • Disable gRPC reflection in production, and keep admin and internal services off the same host and certificate as customer-facing ones.

Enforce at the transport and message layers

  • • TLS everywhere, mTLS or a JWT for every service-to-service call, and validation of every protobuf field — including enum values, rejecting undefined numbers rather than falling through to the default branch.
  • • Strip or sanitize gRPC metadata before it reaches backend logic, and enforce mesh authorization policies (Istio AuthorizationPolicy, Linkerd ServerAuthorization) as defence in depth rather than as the only check.

gRPC Security Practice

There is no public gRPC lab we can vouch for here — the repository this page used to link was removed upstream. Run a throwaway reflection-enabled gRPC service locally and work through the Protobuf Field Tampering and Authentication sections above against it.

HackTheBox — gRPC Challenges Hack The Box hard
Proto file reconstructionAuth bypassmTLS testing