Skip to content

fix(server): clamp list RPC page limit to prevent unbounded queries#140

Merged
johntmyers merged 1 commit intomainfrom
fix/26-unbounded-list-limit/jomyers
Mar 6, 2026
Merged

fix(server): clamp list RPC page limit to prevent unbounded queries#140
johntmyers merged 1 commit intomainfrom
fix/26-unbounded-list-limit/jomyers

Conversation

@johntmyers
Copy link
Collaborator

🏗️ build-from-issue-agent

Closes #26

Summary

All list RPCs passed the client-provided limit directly to SQL queries with no upper bound, allowing a single request to load an unbounded number of rows and cause memory exhaustion (DoS). This fix introduces a MAX_PAGE_SIZE constant (1000) and a clamp_limit helper that caps the limit in every list handler before it reaches the persistence layer.

Changes Made

  • crates/navigator-server/src/grpc.rs: Added MAX_PAGE_SIZE constant (1000) and clamp_limit(raw, default, max) helper function. Applied clamp_limit in list_sandboxes, list_providers, and list_sandbox_policies handlers. Added 3 unit tests for clamp_limit.
  • crates/navigator-server/src/inference.rs: Imported MAX_PAGE_SIZE and clamp_limit from grpc module. Applied clamp_limit in list_inference_routes handler.

Deviations from Plan

None — implemented as planned.

Tests Added

  • Unit: 3 tests for clamp_limitclamp_limit_zero_returns_default, clamp_limit_within_range_passes_through, clamp_limit_exceeding_max_is_capped
  • Integration: N/A (existing sqlite_list_paging test covers store-level paging)
  • E2E: N/A

Documentation Updated

  • None needed (no API-facing changes; server silently clamps the limit)

Verification

  • Pre-commit checks passing (format, lint, all 72 server tests pass)
  • E2E tests (not applicable — no e2e/ changes)
  • Architecture documentation updated (not applicable)

Closes #26

All list RPCs (ListSandboxes, ListProviders, ListSandboxPolicies,
ListInferenceRoutes) passed the client-provided limit directly to SQL
queries with no upper bound. A client could send limit=u32::MAX and
cause the server to load all records into memory, risking OOM. This
introduces a MAX_PAGE_SIZE constant (1000) and a clamp_limit helper
that caps the limit in every list handler before it reaches the
persistence layer.
@johntmyers johntmyers self-assigned this Mar 6, 2026
@johntmyers johntmyers mentioned this pull request Mar 6, 2026
@johntmyers johntmyers merged commit 6bc4eb2 into main Mar 6, 2026
10 checks passed
@johntmyers johntmyers deleted the fix/26-unbounded-list-limit/jomyers branch March 6, 2026 00:31
drew pushed a commit that referenced this pull request Mar 16, 2026
…140)

Closes #26

All list RPCs (ListSandboxes, ListProviders, ListSandboxPolicies,
ListInferenceRoutes) passed the client-provided limit directly to SQL
queries with no upper bound. A client could send limit=u32::MAX and
cause the server to load all records into memory, risking OOM. This
introduces a MAX_PAGE_SIZE constant (1000) and a clamp_limit helper
that caps the limit in every list handler before it reaches the
persistence layer.

Co-authored-by: John Myers <johntmyers@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unbounded list limit

1 participant