Because createLesson checks only the global permission string, not course ownership.
In apps/web/graphql/lessons/logic.ts, the flow is:
- Authenticate user.
- Require
course:manage.
- Fetch course by
courseId and domain.
- Create lesson and push it into that course.
The missing check is between steps 3 and 4. It should call the existing owner-aware helper, like:
if (!canManageCourseInContext(course, ctx)) {
throw new Error(responses.action_not_allowed);
}
That helper already encodes the intended rule in apps/web/graphql/courses/permissions.ts: course:manage_any can manage any course, while course:manage can manage only owned courses.
So the root cause is: createLesson treats course:manage as tenant-wide course management. Also, the public API lesson creation route delegates to the same function at apps/web/app/api/products/[productId]/lessons/route.ts, so fixing createLesson should close both GraphQL and REST creation paths.
Because
createLessonchecks only the global permission string, not course ownership.In apps/web/graphql/lessons/logic.ts, the flow is:
course:manage.courseIdand domain.The missing check is between steps 3 and 4. It should call the existing owner-aware helper, like:
That helper already encodes the intended rule in apps/web/graphql/courses/permissions.ts:
course:manage_anycan manage any course, whilecourse:managecan manage only owned courses.So the root cause is:
createLessontreatscourse:manageas tenant-wide course management. Also, the public API lesson creation route delegates to the same function at apps/web/app/api/products/[productId]/lessons/route.ts, so fixingcreateLessonshould close both GraphQL and REST creation paths.