Webupdated Oct 1, 2026

gRPC-Web Pentest

Map and test gRPC-Web services: decode binary frames, enumerate methods, and probe per-method auth and metadata handling.

toolbox:grpcurlgrpcuiburp suitejq

A runbook for testing gRPC-Web services in an authorized scope. Goal: enumerate methods, decode the length-prefixed framing, and verify authorization is enforced per RPC rather than only in the UI.

1. Fingerprint the gateway

Look for application/grpc-web+proto content types and paths shaped like /package.Service/Method. Check whether reflection is exposed and whether a REST gateway maps the same methods.

curl -s -D - -o /dev/null https://target/ \
  -H 'Content-Type: application/grpc-web+proto'
grpcurl -plaintext target:50051 list

2. Triage reflection and descriptors

If reflection is on, list and describe services directly instead of reverse-engineering JS.

grpcurl -plaintext target:50051 list
grpcurl -plaintext target:50051 describe pkg.Service
grpcurl -plaintext target:50051 describe pkg.Service.Method > method.json

Without reflection, harvest method names from client bundles or a Burp capture.

curl -s https://target/static/app.js | grep -oE '/[A-Za-z0-9_.]+\.[A-Za-z0-9_]+/[A-Za-z0-9_]+' | sort -u

3. Decode the gRPC-Web framing

Each body is one or more frames: a flag byte, a 4-byte big-endian length, then the protobuf payload. The trailer frame sets the high bit.

[0x00][len:4][protobuf data]
[0x80][len:4][grpc-status + metadata trailers]

Decode a base64 body saved from Burp:

echo "<base64-body>" | base64 -d | xxd | head
python3 -c "import sys;d=sys.stdin.buffer.read();i=0
while i<len(d):
 print('flag',d[i],'len',int.from_bytes(d[i+1:i+5],'big'));i+=5+int.from_bytes(d[i+1:i+5],'big')" < body.bin

4. Enumerate methods with grpcurl

Call methods directly once you have names. Use an interactive UI for manual exploration.

grpcurl -plaintext -d '{"id":1}' target:50051 pkg.Service/GetUser
grpcurl -plaintext -import-path . -proto svc.proto -d '{}' target:50051 pkg.Service/Admin
grpcui -plaintext target:50051

5. Test authorization per method

The common flaw: the browser only shows methods you are allowed to call, but the backend never checks the token on that RPC. Replay every method with and without credentials.

# No metadata / no token
grpcurl -plaintext -d '{}' target:50051 pkg.Service/ListUsers
# With a captured low-privilege token
grpcurl -plaintext -H 'authorization: Bearer <low-priv>' -d '{}' target:50051 pkg.Service/DeleteUser

6. Probe metadata and identity headers

Metadata is HTTP/2 headers. Watch for trust in client-supplied x-user-id, role, or tenant keys, and confirm whether they override the token.

grpcurl -plaintext -H 'authorization: Bearer <user>' -H 'x-user-id: 1' -d '{}' target:50051 pkg.Service/GetAccount
grpcurl -plaintext -d '{}' target:50051 pkg.Service/GetAccount 2>&1 | jq -R 'select(test("grpc-message"))'

Verbose grpc-message strings often leak internal paths or validation logic.

7. Full pipeline (one block)

TARGET=target:50051
# Discover
grpcurl -plaintext $TARGET list | tee services.txt
while read s; do grpcurl -plaintext $TARGET describe $s; done < services.txt > schema.txt
# Call without auth to find weak methods
while read m; do
  echo "== $m"; grpcurl -plaintext -d '{}' $TARGET $m 2>&1 | head -n 5
done < <(grep -oE '^[A-Za-z0-9_.]+/[A-Za-z0-9_]+' schema.txt | sort -u)
# Replay with a token
grpcurl -plaintext -H 'authorization: Bearer <token>' -d '{}' $TARGET pkg.Service/Admin

Ethics & legality

  • Only test services in an official scope or with written authorization.
  • Do not exfiltrate real user data; prove access with your own test identities.
  • Capture request/response evidence per method for the report.