Pentesting gRPC-Web
Reading time: 7 minutes
tip
Learn & practice AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking:
HackTricks Training GCP Red Team Expert (GRTE)
Learn & practice Az Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Check the subscription plans!
- Join the đŹ Discord group or the telegram group or follow us on Twitter đŚ @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
Quick protocol recap and attack surface
- Transport: gRPCâWeb speaks a browserâcompatible variant of gRPC over HTTP/1.1 or HTTP/2 via a proxy (Envoy/APISIX/grpcwebproxy/etc.). Only unary and serverâstreaming calls are supported.
- Content-Types you will see:
- application/grpc-web (binary framing)
- application/grpc-web-text (base64-encoded framing for HTTP/1.1 streaming)
- Framing: every message is prefixed with a 5âbyte gRPC header (1âbyte flags + 4âbyte length). In gRPCâWeb, trailers (grpc-status, grpc-message, âŚ) are sent inside the body as a special frame: first byte with MSB set (0x80) followed by a length and a HTTP/1.1âstyle header block.
- Common request headers: x-grpc-web: 1, x-user-agent: grpc-web-javascript/âŚ, grpc-timeout, grpc-encoding. Responses expose grpc-status/grpc-message via trailers/body frames and often via Access-Control-Expose-Headers for browsers.
- Securityârelevant middleware often present:
- Envoy grpc_web filter and gRPCâJSON transcoder (HTTP<->gRPC bridge)
- Nginx/APISIX gRPCâWeb plugins
- CORS policies on the proxy
What this means for attackers:
- You can craft requests by hand (binary or base64 text), or let tooling generate/encode them.
- CORS mistakes on the proxy can allow crossâsite, authenticated gRPCâWeb calls (similar to classic CORS issues).
- JSON transcoding bridges may unintentionally expose gRPC methods as unauthenticated HTTP endpoints if routes/auth are misconfigured.
Testing gRPCâWeb from the CLI
Easiest: buf curl (speaks gRPCâWeb natively)
- List methods via reflection (if enabled):
# list methods (uses reflection)
buf curl --protocol grpcweb https://host.tld --list-methods
- Call a method with JSON input, autoâhandling gRPCâWeb framing and headers:
buf curl --protocol grpcweb \
-H 'Origin: https://example.com' \
-d '{"field":"value"}' \
https://host.tld/pkg.svc.v1.Service/Method
- If reflection is disabled, provide a schema/descriptor set with --schema or point to local .proto files. See buf help curl.
Raw with curl (manual headers + framed body)
For binary mode (application/grpc-web), send a framed payload (5âbyte prefix + protobuf message). For text mode, base64âencode the framed payload.
# Build a protobuf message, then gRPC-frame it (1 flag byte + 4 length + msg)
# Example using protoscope to compose/edit the message and base64 for grpc-web-text
protoscope -s msg.txt | python3 grpc-coder.py --encode --type grpc-web-text | \
tee body.b64
curl -i https://host.tld/pkg.svc.v1.Service/Method \
-H 'Content-Type: application/grpc-web-text' \
-H 'X-Grpc-Web: 1' \
-H 'X-User-Agent: grpc-web-javascript/0.1' \
--data-binary @body.b64
Tip: Force base64/text mode with application/grpc-web-text when HTTP/1.1 intermediaries break binary streaming.
Check CORS behavior (preflight + response)
- Preflight:
curl -i -X OPTIONS https://host.tld/pkg.svc.v1.Service/Method \
-H 'Origin: https://evil.tld' \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: content-type,x-grpc-web,x-user-agent,grpc-timeout'
- A vulnerable setup often reflects arbitrary Origin and sends Access-Control-Allow-Credentials: true, allowing crossâsite authenticated calls. Also check Access-Control-Expose-Headers includes grpc-status, grpc-message (many deployments expose these for client libs).
For generic techniques to abuse CORS, check CORS - Misconfigurations & Bypass.
Manipulating gRPCâWeb payloads
gRPCâWeb uses Content-Type: application/grpc-web-text as a base64âwrapped gRPC frame stream for browser compatibility. You can decode/modify/encode frames to tamper with fields, flip flags, or inject payloads.
Use the gprc-coder tool (and its Burp extension) to speed up roundâtrips.
Manual with gGRPC Coder Tool
- Decode the payload:
echo "AAAAABYSC0FtaW4gTmFzaXJpGDY6BVhlbm9u" | python3 grpc-coder.py --decode --type grpc-web-text | protoscope > out.txt
- Edit the content of decoded payload
nano out.txt
2: {"Amin Nasiri Xenon GRPC"}
3: 54
7: {"<script>alert(origin)</script>"}
- Encode the new payload
protoscope -s out.txt | python3 grpc-coder.py --encode --type grpc-web-text
- Use output in Burp interceptor:
AAAAADoSFkFtaW4gTmFzaXJpIFhlbm9uIEdSUEMYNjoePHNjcmlwdD5hbGVydChvcmlnaW4pPC9zY3JpcHQ+
Manual with gRPCâWeb Coder Burp Suite Extension
You can use gRPCâWeb Coder Burp Suite Extension in gRPCâWeb Pentest Suite which is easier. You can read the installation and usage instruction in its repo.
Analysing gRPCâWeb JavaScript files
Web apps using gRPCâWeb ship at least one generated JS/TS bundle. Reverse them to extract services, methods, and message shapes.
- Try using gRPC-Scan to parse bundles.
- Look for method paths like /
. / , message field numbers/types, and custom interceptors that add auth headers.
- Download the JavaScript gRPCâWeb file
- Scan it with grpc-scan.py:
python3 grpc-scan.py --file main.js
- Analyse output and test the new endpoints and new services:
Output:
Found Endpoints:
/grpc.gateway.testing.EchoService/Echo
/grpc.gateway.testing.EchoService/EchoAbort
/grpc.gateway.testing.EchoService/NoOp
/grpc.gateway.testing.EchoService/ServerStreamingEcho
/grpc.gateway.testing.EchoService/ServerStreamingEchoAbort
Found Messages:
grpc.gateway.testing.EchoRequest:
+------------+--------------------+--------------+
| Field Name | Field Type | Field Number |
+============+====================+==============+
| Message | Proto3StringField | 1 |
+------------+--------------------+--------------+
| Name | Proto3StringField | 2 |
+------------+--------------------+--------------+
| Age | Proto3IntField | 3 |
+------------+--------------------+--------------+
| IsAdmin | Proto3BooleanField | 4 |
+------------+--------------------+--------------+
| Weight | Proto3FloatField | 5 |
+------------+--------------------+--------------+
| Test | Proto3StringField | 6 |
+------------+--------------------+--------------+
| Test2 | Proto3StringField | 7 |
+------------+--------------------+--------------+
| Test3 | Proto3StringField | 16 |
+------------+--------------------+--------------+
| Test4 | Proto3StringField | 20 |
+------------+--------------------+--------------+
grpc.gateway.testing.EchoResponse:
+--------------+--------------------+--------------+
| Field Name | Field Type | Field Number |
+==============+====================+==============+
| Message | Proto3StringField | 1 |
+--------------+--------------------+--------------+
| Name | Proto3StringField | 2 |
+--------------+--------------------+--------------+
| Age | Proto3IntField | 3 |
+--------------+--------------------+--------------+
| IsAdmin | Proto3BooleanField | 4 |
+--------------+--------------------+--------------+
| Weight | Proto3FloatField | 5 |
+--------------+--------------------+--------------+
| Test | Proto3StringField | 6 |
+--------------+--------------------+--------------+
| Test2 | Proto3StringField | 7 |
+--------------+--------------------+--------------+
| Test3 | Proto3StringField | 16 |
+--------------+--------------------+--------------+
| Test4 | Proto3StringField | 20 |
+--------------+--------------------+--------------+
| MessageCount | Proto3IntField | 8 |
+--------------+--------------------+--------------+
grpc.gateway.testing.ServerStreamingEchoRequest:
+-----------------+-------------------+--------------+
| Field Name | Field Type | Field Number |
+=================+===================+==============+
| Message | Proto3StringField | 1 |
+-----------------+-------------------+--------------+
| MessageCount | Proto3IntField | 2 |
+-----------------+-------------------+--------------+
| MessageInterval | Proto3IntField | 3 |
+-----------------+-------------------+--------------+
grpc.gateway.testing.ServerStreamingEchoResponse:
+------------+-------------------+--------------+
| Field Name | Field Type | Field Number |
+============+===================+==============+
| Message | Proto3StringField | 1 |
+------------+-------------------+--------------+
grpc.gateway.testing.ClientStreamingEchoRequest:
+------------+-------------------+--------------+
| Field Name | Field Type | Field Number |
+============+===================+==============+
| Message | Proto3StringField | 1 |
+------------+-------------------+--------------+
grpc.gateway.testing.ClientStreamingEchoResponse:
+--------------+----------------+--------------+
| Field Name | Field Type | Field Number |
+==============+================+==============+
| MessageCount | Proto3IntField | 1 |
+--------------+----------------+--------------+
Bridging and JSON transcoding gotchas
Many deployments put an Envoy (or similar) proxy in front of the gRPC server:
- grpc_web filter translates HTTP/1.1 POSTs into HTTP/2 gRPC.
- gRPCâJSON Transcoder exposes gRPC methods as HTTP JSON endpoints when .proto options (google.api.http) are present.
From a pentesting perspective:
- Try direct HTTP JSON calls to /
. / with application/json when a transcoder is enabled (auth/route mismatches are common):
curl -i https://host.tld/pkg.svc.v1.Service/Method \
-H 'Content-Type: application/json' \
-d '{"field":"value"}'
- Review whether unknown methods/parameters are rejected or passed through. Some configs forward unmatched paths upstream, occasionally bypassing auth or request validation.
- Observe x-envoy-original-path and related headers added by proxies. Upstreams that trust these may be abusable if the proxy fails to sanitize them.
References
- Hacking into gRPCâWeb Article by Amin Nasiri
- gRPCâWeb Pentest Suite
- gRPCâWeb protocol notes (PROTOCOLâWEB.md)
tip
Learn & practice AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking:
HackTricks Training GCP Red Team Expert (GRTE)
Learn & practice Az Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Check the subscription plans!
- Join the đŹ Discord group or the telegram group or follow us on Twitter đŚ @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
HackTricks