Merge pull request #4298 from Dokploy/fix/GHSA-f8wj-5c4w-frhg-cross-org-idor

Fix/ghsa f8wj 5c4w frhg cross org idor
This commit is contained in:
Mauricio Siu
2026-04-24 12:49:24 -06:00
committed by GitHub
9 changed files with 110 additions and 8 deletions

View File

@@ -458,9 +458,26 @@ export const backupRouter = createTRPCRouter({
serverId: z.string().optional(),
}),
)
.query(async ({ input }) => {
.query(async ({ input, ctx }) => {
try {
const destination = await findDestinationById(input.destinationId);
if (destination.organizationId !== ctx.session.activeOrganizationId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You don't have access to this destination.",
});
}
if (input.serverId) {
const targetServer = await findServerById(input.serverId);
if (
targetServer.organizationId !== ctx.session.activeOrganizationId
) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You don't have access to this server.",
});
}
}
const rcloneFlags = getS3Credentials(destination);
const bucketPath = `:s3:${destination.bucket}`;

View File

@@ -18,7 +18,16 @@ export const clusterRouter = createTRPCRouter({
serverId: z.string().optional(),
}),
)
.query(async ({ input }) => {
.query(async ({ input, ctx }) => {
if (input.serverId) {
const targetServer = await findServerById(input.serverId);
if (targetServer.organizationId !== ctx.session.activeOrganizationId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You don't have access to this server.",
});
}
}
const docker = await getRemoteDocker(input.serverId);
const workers: DockerNode[] = await docker.listNodes();
return workers;
@@ -32,6 +41,15 @@ export const clusterRouter = createTRPCRouter({
}),
)
.mutation(async ({ input, ctx }) => {
if (input.serverId) {
const targetServer = await findServerById(input.serverId);
if (targetServer.organizationId !== ctx.session.activeOrganizationId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You don't have access to this server.",
});
}
}
try {
const drainCommand = `docker node update --availability drain ${input.nodeId}`;
const removeCommand = `docker node rm ${input.nodeId} --force`;
@@ -65,7 +83,16 @@ export const clusterRouter = createTRPCRouter({
serverId: z.string().optional(),
}),
)
.query(async ({ input }) => {
.query(async ({ input, ctx }) => {
if (input.serverId) {
const targetServer = await findServerById(input.serverId);
if (targetServer.organizationId !== ctx.session.activeOrganizationId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You don't have access to this server.",
});
}
}
const docker = await getRemoteDocker(input.serverId);
const result = await docker.swarmInspect();
const docker_version = await docker.version();
@@ -88,7 +115,16 @@ export const clusterRouter = createTRPCRouter({
serverId: z.string().optional(),
}),
)
.query(async ({ input }) => {
.query(async ({ input, ctx }) => {
if (input.serverId) {
const targetServer = await findServerById(input.serverId);
if (targetServer.organizationId !== ctx.session.activeOrganizationId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You don't have access to this server.",
});
}
}
const docker = await getRemoteDocker(input.serverId);
const result = await docker.swarmInspect();
const docker_version = await docker.version();

View File

@@ -16,6 +16,7 @@ import {
checkServicePermissionAndAccess,
findMemberByUserId,
} from "@dokploy/server/services/permission";
import { findServerById } from "@dokploy/server/services/server";
import { TRPCError } from "@trpc/server";
import { desc, eq } from "drizzle-orm";
import { z } from "zod";
@@ -52,7 +53,14 @@ export const deploymentRouter = createTRPCRouter({
}),
allByServer: withPermission("deployment", "read")
.input(apiFindAllByServer)
.query(async ({ input }) => {
.query(async ({ input, ctx }) => {
const targetServer = await findServerById(input.serverId);
if (targetServer.organizationId !== ctx.session.activeOrganizationId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You don't have access to this server.",
});
}
return await findAllDeploymentsByServerId(input.serverId);
}),
allCentralized: withPermission("deployment", "read").query(

View File

@@ -15,7 +15,9 @@ import {
updateVolumeBackupSchema,
volumeBackups,
} from "@dokploy/server/db/schema";
import { findDestinationById } from "@dokploy/server/services/destination";
import { checkServicePermissionAndAccess } from "@dokploy/server/services/permission";
import { findServerById } from "@dokploy/server/services/server";
import {
execAsyncRemote,
execAsyncStream,
@@ -265,7 +267,23 @@ export const volumeBackupsRouter = createTRPCRouter({
serverId: z.string().optional(),
}),
)
.subscription(async ({ input }) => {
.subscription(async ({ input, ctx }) => {
const destination = await findDestinationById(input.destinationId);
if (destination.organizationId !== ctx.session.activeOrganizationId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You don't have access to this destination.",
});
}
if (input.serverId) {
const targetServer = await findServerById(input.serverId);
if (targetServer.organizationId !== ctx.session.activeOrganizationId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You don't have access to this server.",
});
}
}
return observable<string>((emit) => {
const runRestore = async () => {
try {

View File

@@ -85,6 +85,11 @@ export const setupDockerContainerLogsWebSocketServer = (
if (serverId) {
const server = await findServerById(serverId);
if (server.organizationId !== session.activeOrganizationId) {
ws.close();
return;
}
if (!server.sshKeyId) return;
const client = new Client();
client

View File

@@ -61,6 +61,12 @@ export const setupDockerContainerTerminalWebSocketServer = (
try {
if (serverId) {
const server = await findServerById(serverId);
if (server.organizationId !== session.activeOrganizationId) {
ws.close();
return;
}
if (!server.sshKeyId)
throw new Error("No SSH key available for this server");

View File

@@ -57,6 +57,11 @@ export const setupDeploymentLogsWebSocketServer = (
if (serverId) {
const server = await findServerById(serverId);
if (server.organizationId !== session.activeOrganizationId) {
ws.close();
return;
}
if (!server.sshKeyId) {
ws.close();
return;

View File

@@ -154,6 +154,11 @@ export const setupTerminalWebSocketServer = (
return;
}
if (server.organizationId !== session.activeOrganizationId) {
ws.close();
return;
}
const { ipAddress: host, port, username, sshKey, sshKeyId } = server;
if (!sshKeyId) {

View File

@@ -481,8 +481,10 @@ export const validateRequest = async (request: IncomingMessage) => {
};
}
const organizationId = JSON.parse(
apiKeyRecord.metadata || "{}",
const organizationId = (
JSON.parse(apiKeyRecord.metadata || "{}") as {
organizationId?: string;
}
).organizationId;
if (!organizationId) {