From 4aee66b2d1dc2c027749a541e553aa49947075c1 Mon Sep 17 00:00:00 2001 From: Mauricio Siu Date: Mon, 20 Jul 2026 17:14:35 -0600 Subject: [PATCH] fix(security): enforce organization ownership on server.remove server.remove deleted a server (and its deployment rows) by caller-supplied serverId without checking it belongs to the active organization, unlike server.one and server.update. An owner/admin of org A could delete org B's server registration. Resolve and compare the server's organizationId before the active-services guard, so cross-org callers are rejected without leaking existence. --- apps/dokploy/server/api/routers/server.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/dokploy/server/api/routers/server.ts b/apps/dokploy/server/api/routers/server.ts index 7a4b818f3..1f3ed2c3b 100644 --- a/apps/dokploy/server/api/routers/server.ts +++ b/apps/dokploy/server/api/routers/server.ts @@ -413,6 +413,14 @@ export const serverRouter = createTRPCRouter({ .input(apiRemoveServer) .mutation(async ({ input, ctx }) => { try { + const currentServer = await findServerById(input.serverId); + if (currentServer.organizationId !== ctx.session.activeOrganizationId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to delete this server", + }); + } + const activeServers = await haveActiveServices(input.serverId); if (activeServers) { @@ -421,7 +429,6 @@ export const serverRouter = createTRPCRouter({ message: "Server has active services, please delete them first", }); } - const currentServer = await findServerById(input.serverId); await audit(ctx, { action: "delete", resourceType: "server",