Bug: deleteWorkoutSessionAction has no auth/ownership check — any user can delete others sessions
Bug
deleteWorkoutSessionAction lets any authenticated user delete any other user's workout session. It's built on the unauthenticated actionClient, fetches the session's userId but never compares it to the caller, and deletes by id alone.
Root cause
src/features/workout-session/actions/delete-workout-session.action.ts:
export const deleteWorkoutSessionAction = actionClient.schema(...).action(async ({ parsedInput }) => {
const { id } = parsedInput;
const session = await prisma.workoutSession.findUnique({
where: { id },
select: { userId: true }, // ← fetched, but never compared to anyone
});
if (!session) { ... }
await prisma.workoutSession.delete({ where: { id } }); // ← deletes unconditionally
...
});actionClient (vs authenticatedActionClient) performs no auth and exposes no ctx.user, so the action has no idea who the caller is. The session row's userId is selected and then discarded. Any logged-in user who sends a valid session id deletes it — cross-user data loss.
The codebase already has authenticatedActionClient (used by favorites/get-users) that injects ctx.user via serverAuth(); the delete action just doesn't use it.
Impact
A user can delete another user's workout history by id (guessable/enumerable cuids, leaked via leaderboard/session-share). No audit, no ownership check.
Fix
Switch to authenticatedActionClient and require ownership:
export const deleteWorkoutSessionAction = authenticatedActionClient
.schema(deleteWorkoutSessionSchema)
.action(async ({ parsedInput, ctx }) => {
const { id } = parsedInput;
const session = await prisma.workoutSession.findUnique({ where: { id }, select: { userId: true } });
if (!session || session.userId !== ctx.user.id) {
return { serverError: "Session not found" };
}
await prisma.workoutSession.delete({ where: { id } });
return { success: true };
});Returning the same "not found" for both missing and non-owned prevents existence-disclosure. I have a PR ready.
Source: Snouzy/workout-cool