Skip to content

fix(security): verify a student belongs to the run before changing their password#332

Open
Isaries wants to merge 1 commit into
WISE-Community:developfrom
Isaries:fix/change-student-password-run-membership
Open

fix(security): verify a student belongs to the run before changing their password#332
Isaries wants to merge 1 commit into
WISE-Community:developfrom
Isaries:fix/change-student-password-run-membership

Conversation

@Isaries

@Isaries Isaries commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Summary

POST /api/teacher/run/{runId}/student/{studentId}/change-password checks that the signed-in teacher has write permission on the run taken from the path, but then loads the target user straight from studentId without ever checking that the two are related. The id is confined neither to the run nor to students.

A teacher who owns any one run can therefore set the password of any account in the system by id: another teacher's student, another teacher, or an administrator.

The class-level @Secured({"ROLE_TEACHER"}) and the teacherPassword re-authentication both only establish who the caller is; neither constrains whom they may act on. isTeacherPasswordCorrect also returns true immediately for Google users, so the re-authentication is skipped entirely for them.

This is the same confused-deputy pattern as #325 (authorize object A, then mutate object B), but on the endpoint the Angular client actually calls, and without even the group scoping the legacy controller had.

Changes

  • Verify the target is a student of that run before changing the password, using the existing Run.isStudentAssociatedToThisRun. One check covers all three cases: a student from another run is not in any of this run's periods, and neither is a teacher or an administrator.
  • Add tests for a student outside the run and for a teacher as the target.

I used isStudentAssociatedToThisRun rather than UserService.isUserAssociatedWithRun, because the latter also returns true for a teacher associated with the run, which would still let a shared owner change the run owner's password.

Testing

  • mvnw test -Dtest=ChangeStudentPasswordControllerTest passes (6 tests).
  • Reverting only the controller change makes exactly the two new tests fail, and they fail by the password being changed rather than the request being rejected.
  • Full mvnw test shows the same 3 failures / 21 errors as a clean develop on my machine (database, encoding and filesystem related), with the 2 added tests passing.

Note

RemoveStudentRunController has the same shape, and I have opened #333 for it separately. It turned out to be a much smaller problem than this one: both steps of removeStudentFromRun are already scoped to the run, so passing an id from outside the run does nothing at all. The only real gap there is the missing role check, and #333 has the details.

…eir password

The change student password endpoint checked that the signed-in teacher has
write permission on the run taken from the path, but then loaded the target
user directly from the student id without checking that the two are related.
The id was neither confined to the run nor to students.

Verify that the target is a student of that run before changing the password.
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.

2 participants