summaryrefslogtreecommitdiffstats
path: root/packages
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-01 17:49:19 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-01 17:49:19 +0200
commit6b38704d459dec1271c7ca883de3eb14190218f7 (patch)
tree2fd1bd5c344092e4a115f3ab94e901517b3b6a03 /packages
parent7d8c774e250b134222374f45726d5426714475de (diff)
downloadmeshbay-6b38704d459dec1271c7ca883de3eb14190218f7.tar.gz
fix(hub): require user scope to add group members
Every mutating group endpoint depends on require_user_scope except POST /v1/groups/{group_id}/members/{username}, which depended on get_current_user — so a node-scoped daemon token (or a stolen one) whose subject owns the group could add any existing user to it, contradicting NS7 ("operator manages groups from the browser only"). test_node_auth.py::test_node_scope_blocks_add_member already existed and was red on main; it passes now. Third security review, finding M6. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011pG75yGK3NthNfyjH74omG
Diffstat (limited to 'packages')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/api/groups.py7
1 files changed, 6 insertions, 1 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/api/groups.py b/packages/meshbay-hub/src/meshbay_hub/api/groups.py
index fdb0444..15c7a5d 100644
--- a/packages/meshbay-hub/src/meshbay_hub/api/groups.py
+++ b/packages/meshbay-hub/src/meshbay_hub/api/groups.py
@@ -586,9 +586,14 @@ async def update_group(
async def add_group_member(
group_id: str,
username: str,
- current_user: User = Depends(get_current_user),
+ current_user: User = Depends(require_user_scope),
db: AsyncSession = Depends(get_db),
):
+ # `require_user_scope`, like every other mutating group endpoint: a
+ # node-scoped daemon token must not manage membership (NS7 — the operator
+ # manages groups from the browser). This was the one membership endpoint
+ # still on `get_current_user`, so a node token could add members to its
+ # operator's own groups.
group = await db.get(Group, group_id)
if not group:
raise HTTPException(status_code=404, detail="Group not found")