Bug
POST /api/programs/session-progress/start creates a UserSessionProgress for any session id the client passes, without checking that the session belongs to the program the enrollment is for. The user's enrollment pointer (currentWeek / currentSession) is then overwritten with numbers from that unrelated session.
Root cause
In app/api/programs/session-progress/start/route.ts:
const enrollment = await prisma.userProgramEnrollment.findFirst({
where: { id: enrollmentId, userId },
...
});
...
const programSession = await prisma.programSession.findUnique({
where: { id: sessionId }, // ← no programId constraint
...
});
...
const sessionProgress = await prisma.userSessionProgress.create({
data: { enrollmentId, sessionId },
});
await prisma.userProgramEnrollment.update({
where: { id: enrollmentId },
data: {
currentWeek: programSession.week.weekNumber, // ← from the OTHER program
currentSession: programSession.sessionNumber, // ← from the OTHER program
},
});
The enrollment captures programId (program A), but programSession.week.programId (program B) is never compared against it. Nothing in the schema enforces a program match either: UserSessionProgress.session only relates to ProgramSession, not to the enrollment's program.
So a request like { enrollmentId: <my enrollment in Program A>, sessionId: <session from Program B> } succeeds and:
- creates a
UserSessionProgress linking my Program-A enrollment to a Program-B session,
- sets my enrollment's
currentWeek / currentSession to Program-B's values,
- breaks the user's "current position" in the program they actually enrolled in (and the
complete route inherits the wrong row).
It's effectively a cross-program data-integrity / authorization-scope gap.
Fix
Scope the session lookup to the enrollment's program and reject mismatches:
const programSession = await prisma.programSession.findUnique({
where: { id: sessionId },
include: { week: true, ... },
});
if (!programSession || programSession.week.programId !== enrollment.programId) {
return NextResponse.json({ error: "Session not found" }, { status: 404 });
}
I have a PR ready.
Bug
POST /api/programs/session-progress/startcreates aUserSessionProgressfor any session id the client passes, without checking that the session belongs to the program the enrollment is for. The user's enrollment pointer (currentWeek/currentSession) is then overwritten with numbers from that unrelated session.Root cause
In
app/api/programs/session-progress/start/route.ts:The enrollment captures
programId(program A), butprogramSession.week.programId(program B) is never compared against it. Nothing in the schema enforces a program match either:UserSessionProgress.sessiononly relates toProgramSession, not to the enrollment's program.So a request like
{ enrollmentId: <my enrollment in Program A>, sessionId: <session from Program B> }succeeds and:UserSessionProgresslinking my Program-A enrollment to a Program-B session,currentWeek/currentSessionto Program-B's values,completeroute inherits the wrong row).It's effectively a cross-program data-integrity / authorization-scope gap.
Fix
Scope the session lookup to the enrollment's program and reject mismatches:
I have a PR ready.