From 0edc3a385c0cf35aa5b587e674ca4faa669246a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Malfait?= Date: Wed, 4 Feb 2026 10:47:24 +0100 Subject: [PATCH] fix: prevent anonymous users from bypassing workspace creation restriction (#17635) When `IS_WORKSPACE_CREATION_LIMITED_TO_SERVER_ADMINS` is true, anonymous users could still create workspaces because `checkWorkspaceCreationIsAllowedOrThrow` checked per-user workspace count (always 0 for new users) instead of system-wide workspace count. The bootstrap bypass now only applies when no workspaces exist in the entire system. Also adds the same check in `signUpOnNewWorkspace` to guard the `signInUp` code path. Fixes #17631 Generated with [Claude Code](https://claude.ai/claude-code) Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> --- .../auth/services/sign-in-up.service.ts | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/packages/twenty-server/src/engine/core-modules/auth/services/sign-in-up.service.ts b/packages/twenty-server/src/engine/core-modules/auth/services/sign-in-up.service.ts index e8ed4a1553..794e6a8174 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/services/sign-in-up.service.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/services/sign-in-up.service.ts @@ -403,8 +403,8 @@ export class SignInUpService { ); } - private async isFirstWorkspaceForUser(userId: string): Promise { - const count = await this.userWorkspaceService.countUserWorkspaces(userId); + private async isFirstWorkspaceInSystem(): Promise { + const count = await this.workspaceRepository.count(); return count === 0; } @@ -414,7 +414,8 @@ export class SignInUpService { ): Promise { if (!this.isWorkspaceCreationLimitedToServerAdmins()) return; - if (await this.isFirstWorkspaceForUser(currentUser.id)) return; + // Only allow bypass during initial system bootstrap (no workspaces exist yet) + if (await this.isFirstWorkspaceInSystem()) return; if (!currentUser.canAccessFullAdminPanel) { throw new AuthException( @@ -445,6 +446,25 @@ export class SignInUpService { ); } + if ( + this.isWorkspaceCreationLimitedToServerAdmins() && + !(await this.isFirstWorkspaceInSystem()) + ) { + const isExistingAdmin = + userData.type === 'existingUser' && + userData.existingUser.canAccessFullAdminPanel; + + if (!isExistingAdmin) { + throw new AuthException( + 'Workspace creation is restricted to admins', + AuthExceptionCode.FORBIDDEN_EXCEPTION, + { + userFriendlyMessage: msg`Workspace creation is restricted to admins`, + }, + ); + } + } + const { canImpersonate, canAccessFullAdminPanel } = await this.setDefaultImpersonateAndAccessFullAdminPanel();