fix(pods): default GET /api/pods to membership-filtered listing#299
Closed
fix(pods): default GET /api/pods to membership-filtered listing#299
Conversation
Previous behavior: GET /api/pods returned every chat/team/study/games pod on the instance to every authenticated user. Only the personal pod types (agent-admin / agent-room / agent-dm) had membership gating. This made the V2 sidebar unusable on a shared / multi-tenant instance — a fresh user account would see dozens of unrelated pods they have no business browsing. Especially bad for demos and test accounts on the dev cluster, which now sees ~58 pods leak. This commit extends the existing membership filter (used for the three personal pod types) to the default listing. Behavior: GET /api/pods — returns only pods the user is a member of GET /api/pods?scope=all — returns every readable pod (legacy) GET /api/pods?type=chat — returns only chat pods the user is in GET /api/pods?type=agent-dm — unchanged (already membership-gated) Global admins still bypass — preserves the audit surface for moderating the 1:1 invariant on agent-rooms (ADR-001 §3.10). Net diff: 11 lines in podController.getAllPods. No frontend changes — V2 sidebar's existing call hits the default path and will Just Work after deploy. For surfaces that legitimately need to enumerate all pods (admin tools, future marketplace browse, pod-discovery), pass `?scope=all` explicitly. That path still requires the user have read permission via the existing pod ACL. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
samxu01
added a commit
that referenced
this pull request
May 4, 2026
Extends the existing membership filter from agent-admin/agent-room/ agent-dm to chat/team/study/games on the default listing. Closes the isolation leak where every authenticated user saw every pod on the instance. Pass ?scope=all to opt into the legacy "list everything readable" behavior for admin tools, marketplace, pod-discovery. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes a long-standing isolation leak in
GET /api/pods: the default listing returns every chat/team/study/games pod on the instance to every authenticated user. Only the three personal pod types (agent-admin/agent-room/agent-dm) were membership-gated previously. This commit extends the same gate to the default listing.Repro on current main
A fresh test user on dev (created with no joined pods other than one) sees 58 pods in their V2 sidebar — none of which they're a member of:
```bash
curl -sS "$INSTANCE_URL/api/pods" -H "Authorization: Bearer $TEST_USER_TOKEN" | jq length
58
```
That's the entire active pod inventory of the dev instance leaking into a random test account's sidebar.
Behavior after this PR
GET /api/podsGET /api/pods?scope=allGET /api/pods?type=chatGET /api/pods?type=agent-dmGlobal admins still bypass the filter on every code path — preserves the moderation surface for the 1:1 invariant on agent-rooms (ADR-001 §3.10).
Why now
Surfaced while staging accounts for a YC demo recording — a clean test user (
Sam,Mike) had every dev-cluster pod showing in their sidebar, including unrelated agent-DMs between dev agents. The blast radius is bigger than the demo though: every multi-tenant Commonly instance has this leak.Frontend impact
None. V2 sidebar's existing
GET /api/podscall hits the default path and will get filtered listings post-deploy. Surfaces that legitimately need everything (admin tools, marketplace browse) need to add?scope=all— none currently exist in main, so no changes needed today.Test plan
tsc --noEmitcleancurlfrom a non-member token returns only joined pods🤖 Generated with Claude Code