#861·fonoster

Cross-workspace authorization bypass in Identity/UpdateWorkspace

Author: geo-chenCreated Jul 1, 2026Updated Jul 1, 2026
Labelsbug

What happened?

reported on 26 May 2026 via email - no response.

I want to report an authorization bug in mods/identity/src/workspaces/createUpdateWorkspace.ts that allows any authenticated Fonoster user to rename any workspace in the system, regardless of membership.

The updateWorkspace handler calls createIsWorkspaceMember(...), and on failure it calls callback({code: PERMISSION_DENIED, ...}) but is missing a return statement. Execution falls through to prisma.workspace.update({ where: { ref }, data: { name } }), which is scoped only by workspace ref. The database update commits before the second callback is issued, so the attacker receives a PERMISSION_DENIED response but the rename has already happened.

Because the gRPC interceptor in mods/common/src/identity/createAuthInterceptor.ts only enforces tokenHasAccessKeyId on paths in workspaceResourceAccess / workspaceResourceOwnerOrAdminAccess, and UpdateWorkspace is in fullIdentityAccess, the workspace accessKeyId is not bound to the caller's token. The role check passes for Role.USER (the fallback for users with no workspaces), Role.WORKSPACE_OWNER, and Role.WORKSPACE_ADMIN, so the bar is effectively any authenticated user.

Steps to reproduce

Expected behavior

Suggested fix: add return; after the callback({code: PERMISSION_DENIED, ...}) call, and as defense-in-depth tighten the Prisma update to where: { ref, members: { some: { userRef, status: ACTIVE } } } or move UpdateWorkspace into workspaceResourceAccess so the interceptor enforces the accessKeyId binding.

Additional context

No response