Skip to content

fix(programs): scope session-progress/start session to the enrolled program#231

Open
evan188199-tech wants to merge 1 commit into
Snouzy:mainfrom
evan188199-tech:fix/session-progress-start-scopes-session-to-enrollment-program
Open

fix(programs): scope session-progress/start session to the enrolled program#231
evan188199-tech wants to merge 1 commit into
Snouzy:mainfrom
evan188199-tech:fix/session-progress-start-scopes-session-to-enrollment-program

Conversation

@evan188199-tech

Copy link
Copy Markdown

What

POST /api/programs/session-progress/start created a UserSessionProgress for any session id the client passed, without checking that the session belongs to the program the enrollment is for. The user's enrollment pointer (currentWeek / currentSession) was then overwritten with numbers from that unrelated session.

Bug found while auditing the programs API — not covered by any existing issue/PR.

Root cause

In app/api/programs/session-progress/start/route.ts:

const enrollment = await prisma.userProgramEnrollment.findFirst({
  where: { id: enrollmentId, userId },
  include: { program: true },
});
...
const programSession = await prisma.programSession.findUnique({
  where: { id: sessionId },     // no programId constraint
});
...
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. UserSessionProgress only relates to ProgramSession, not to the enrollment's program, so the schema doesn't enforce a match either.

A request { enrollmentId: <enrollment in Program A>, sessionId: <Program-B session> } would (1) create a progress row linking a Program-A enrollment to a Program-B session, (2) overwrite the enrollment's currentWeek/currentSession with Program-B's values, (3) break the user's real position (the complete route then inherits the wrong row).

Fix

Reject any session whose week's programId doesn't match the enrollment's program:

if (!programSession || programSession.week.programId !== enrollment.program.id) {
  return NextResponse.json({ error: "Session not found" }, { status: 404 });
}

enrollment.program is already loaded and programSession.week is already included, so no extra query is needed.

Fixes #230.

…rogram

session-progress/start fetched the ProgramSession by id alone and never
compared programSession.week.programId against enrollment.programId, so a
request passing an enrollment in Program A with a sessionId from Program B
created a UserSessionProgress pointing at the wrong program and overwrote
the user's currentWeek/currentSession with that program's values. Reject
any session whose week's programId doesn't match the enrollment's program.

Fixes Snouzy#230
@vercel

vercel Bot commented Jul 7, 2026

Copy link
Copy Markdown

Someone is attempting to deploy a commit to the Workoutcool Team Team on Vercel.

A member of the Team first needs to authorize it.

@evan188199-tech

Copy link
Copy Markdown
Author

此 PR 由 GLM-5.2 修复。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: session-progress/start lets a session from a different program overwrite the user enrollment pointer

1 participant