gRPC's typed contract and binary encoding solve real problems a JSON REST API leaves on the table — a protobuf schema rejects a malformed field before your handler code ever sees it, and HTTP/2 multiplexing lets one connection carry many concurrent calls efficiently. Teams adopting gRPC for service-to-service traffic often carry over an assumption from that efficiency story that does not actually hold: that because the transport is encrypted and the schema is strict, the security work is largely done. It is not — a strict schema validates shape, not authorization, and an encrypted transport authenticates the connection, not necessarily the specific call being made over it.
The failure that follows from that assumption is specific and recurring: a service mesh terminates mutual TLS between pods, every call between two services is genuinely encrypted and the peer certificate genuinely proves which service is calling, and the receiving service treats that proof of identity as sufficient — skipping a per-method check of whether this specific caller is allowed to invoke this specific RPC. mTLS answers "who is this connection from"; it does not answer "should this caller be allowed to call this particular method with these particular arguments," and conflating the two is where a well-encrypted gRPC deployment still ends up over-permissive.
A second, less obvious risk sits in gRPC's own tooling: the reflection service, which lets a client enumerate every RPC method and message type a server exposes at runtime, is the gRPC equivalent of GraphQL introspection, built for development convenience and easy to leave reachable in production without anyone deciding to leave it there.