Skip to content

gRPC surface is not rate limited, so the HTTP rate limit is bypassable by switching transport #363

Description

@zeljkoX

Guardian's rate limiter is attached only to the axum HTTP router. The tonic gRPC server — same mutating operations, same public hostname, same ALB — has no rate limiting. A client that wants to exceed GUARDIAN_RATE_BURST_PER_SEC/GUARDIAN_RATE_PER_MIN only has to speak gRPC. Since gRPC is the primary transport for the Rust SDK and the benchmark harness, the default client path is the unthrottled one.

Proposed behavior

  1. Tonic-side layer sharing one RateLimitStore with HTTP, so the transports draw from a single budget rather than one each. The store and its check logic are already transport-agnostic; only the layer is HTTP-bound (Service<Requestaxum::body::Body>, rate_limit.rs:350).
  2. Reuse the keying scheme: gRPC metadata are HTTP/2 headers, so x-pubkey enhanced keying works as-is, and the gRPC path gives per-method burst keys for free. Only the account_id query-param branch (rate_limit.rs:451-457) has no analogue.
  3. Reject with ResourceExhausted via the existing mapping — no new code, and retryable() already returns true (error.rs:384).
  4. Retry hint in Status metadata (no Retry-After on gRPC) — decide retry-after key vs. google.rpc.RetryInfo details.
  5. Same rejection counter, with a transport label.

Acceptance criteria

  • gRPC counted against the same limiter; over-limit returns ResourceExhausted with a retry hint
  • Client IP (or chosen substitute) verified on the deployed gRPC path, with a test that fails if the key degrades to a single shared bucket
  • guardian_rate_limit_rejections_total distinguishes transports
  • Dead arm at error.rs:211 reachable and covered
  • Rust + TS clients treat it as retryable with backoff (cross-check Make multisig SDK prover retries configurable (429 / timeout), default 2 attempts #360)
  • Docs: spec/api.md Rate Limiting, docs/CONFIGURATION.md:214-217, docs/TROUBLESHOOTING.md:215-229, transport caveat in docs/PERFORMANCE.md

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingsecurity

Type

Projects

Status
Review

Relationships

None yet

Development

No branches or pull requests

Issue actions