Skip to content

fix(be): allow querying past contest submissions from public problem#3578

Open
Choi-Jung-Hyeon wants to merge 9 commits into
mainfrom
t2717-closed-contest-problem-submission
Open

fix(be): allow querying past contest submissions from public problem#3578
Choi-Jung-Hyeon wants to merge 9 commits into
mainfrom
t2717-closed-contest-problem-submission

Conversation

@Choi-Jung-Hyeon
Copy link
Copy Markdown
Contributor

@Choi-Jung-Hyeon Choi-Jung-Hyeon commented May 23, 2026

Description

이 PR은 대회 종료 후 공개 문제로 전환된 페이지에서 유저가 과거 대회 당시 제출했던 내역을 조회할 때 발생하는 버그(EntityNotExistException)를 수정하고, 해당 과정에서 제기된 보안 및 권한 우회 취약점을 보완합니다.

Root Cause & Fix:

  • getSubmission 메서드에서 프론트엔드로부터 contestId: null이 넘어올 때, Prisma가 WHERE contest_id IS NULL 조건을 쿼리하여 과거 대회의 contestId가 채워져 있는 제출물을 찾지 못하는 문제가 있었습니다.
  • 이를 해결하기 위해 contestId가 null일 경우 undefined로 변환하여 Prisma 필터에서 제외함으로써 정상 조회가 가능하도록 수정했습니다.

Security & Privacy Enforcement:

  • 기존에는 제출물 조회 후 contestRecord를 2차로 조회하여 대회 접근 권한을 확인했습니다. 하지만 이 방식은 조회자가 '해당 대회의 참가자'가 아닐 경우 contestRecord가 null이 되어 진행 중인 대회의 타인 제출물 열람 차단 로직이 우회되는 치명적 취약점이 있었습니다.
  • 2차 contestRecord 조회를 제거하고, 첫 submission 쿼리 시에 contestassignment 릴레이션 데이터를 조인(Join)하여 바로 가져오도록 로직을 수정했습니다. 이를 통해 대회 비참가자라도 강력하고 일관된 권한 검증을 받게 됩니다.
  • 과제(Assignment) 제출물이 공개 문제 페이지에서 노출되는 것을 방지하기 위해 assignmentId에 대한 필터는 원래대로 강제 유지하도록 수정했습니다.

Testing:

  • 공개 문제 페이지(contestId=null)에서 자신의 과거 대회 제출물 조회 성공 테스트 케이스를 추가했습니다.
  • 보안 검증을 위해, 진행 중인 대회의 참가자 및 비참가자가 공개 페이지 경로를 통해 타인의 진행 중 대회 제출물 조회를 시도할 때 ForbiddenAccessException으로 정확히 차단되는 테스트 케이스 2종을 추가했습니다.

Additional context

  • 리뷰어 분들은 특히 submission.service.tsgetSubmission 쿼리에서 contest, assignment 릴레이션을 조인하여 권한을 체크하는 로직(11371150행, 11771185행)이 의도대로 안전하게 구현되었는지, 그리고 과제 제출물 노출 위험이 제대로 차단되었는지 집중적으로 확인해 주시면 좋겠습니다.
  • @libs/exception 등의 alias 문제로 실패하던 로컬 테스트 환경을 픽스하여 전체 35개의 SubmissionService 테스트 케이스가 성공함을 검증했습니다.

Before submitting the PR, please make sure you do the following

…page

대회 종료 후 공개 문제로 전환된 problem에서 유저가 대회 당시 제출했던
submission을 조회할 때 EntityNotExistException이 발생하는 버그를 수정한다.

Root cause:
- getSubmission의 submission 조회 where 조건에 contestId: null이 그대로 전달되어
  Prisma가 WHERE contest_id IS NULL을 생성, contestId가 채워진 과거 대회
  submission을 찾지 못함

Fix:
- contestId/assignmentId가 null인 경우 undefined로 변환하여 해당 필드를
  where 조건에서 제외 (no filter)
- submission 조회 후 실제 contestId가 존재하면 해당 대회 정보를 로드하여
  진행 중인 대회의 타인 제출 열람 차단 로직을 정상 동작하도록 보완

Security:
- contestId 없이 공개 엔드포인트를 호출하더라도 submission의 실제 contestId가
  진행 중인 대회이면 ForbiddenAccessException으로 차단

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 23, 2026 01:56
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request fixes a bug preventing users from viewing their past contest submissions on public problem pages by ensuring Prisma filters ignore null contest and assignment IDs. It also introduces logic to prevent unauthorized access to submissions from ongoing contests. The reviewer identified a critical security vulnerability where the access control check could be bypassed if a user had not registered for the contest. To resolve this, the reviewer suggests fetching contest and assignment relations directly in the initial database query to ensure consistent security validation and improved performance.

Comment thread apps/backend/apps/client/src/submission/submission.service.ts Outdated
Comment thread apps/backend/apps/client/src/submission/submission.service.ts Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a backend bug where users could not fetch their past contest submissions from a problem page after the contest ended and the problem became public, due to Prisma generating WHERE contest_id IS NULL when contestId=null was passed.

Changes:

  • Adjusts getSubmission Prisma where clause to omit contestId/assignmentId filters when they are null.
  • Adds a fallback contest load path when the request omits contestId but the fetched submission has a contestId, to preserve “ongoing contest => block viewing others” behavior.
  • Adds service tests covering public-page access to past contest submissions and a security-related scenario.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
apps/backend/apps/client/src/submission/submission.service.ts Updates submission lookup filters and adds contest lookup logic for public-page access patterns.
apps/backend/apps/client/src/submission/test/submission.service.spec.ts Adds tests for querying contest submissions via public problem page inputs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread apps/backend/apps/client/src/submission/submission.service.ts Outdated
Comment thread apps/backend/apps/client/src/submission/submission.service.ts Outdated
Comment thread apps/backend/apps/client/src/submission/test/submission.service.spec.ts Outdated
@Choi-Jung-Hyeon Choi-Jung-Hyeon self-assigned this May 23, 2026
@Choi-Jung-Hyeon Choi-Jung-Hyeon added the 🪰 bug Something isn't working label May 23, 2026
@github-project-automation github-project-automation Bot moved this to Pending ✋ in Codedang May 23, 2026
@Choi-Jung-Hyeon Choi-Jung-Hyeon linked an issue May 23, 2026 that may be closed by this pull request
27 tasks
Choi-Jung-Hyeon and others added 4 commits May 23, 2026 02:38
…mission

- Revert assignmentId filter to keep WHERE assignment_id IS NULL
  (prevents assignment submissions from leaking to public pages)
- Select contest/assignment relations directly in submission query
  instead of separate contestRecord lookup
- Non-participants can no longer bypass ongoing contest access check
  by omitting contestId parameter
- Add non-participant security test case
Copy link
Copy Markdown
Contributor

@RyuRaseul RyuRaseul left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@github-project-automation github-project-automation Bot moved this from Pending ✋ to Approved 👌 in Codedang May 25, 2026
Comment thread apps/backend/apps/client/src/submission/submission.service.ts Outdated
Copy link
Copy Markdown
Contributor

@zero1177 zero1177 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1137-1150번행에서 submission이랑 연관된 contest, assignment 두 테이블 각각의 isJudgeResultVisible이 빠짐없이 잘 fetch 되고 있어서,
조회할때 ID가 null이어도(과거 기록) 실제 엔티티에 기록되어 있는 열람 가능 여부를 잘 반영하는것을 확인했습니다! (contest는 1178-1181행, assignment는 승민이 코멘트대로 불필요해서 제거되어있네용)

@nhjbest22
Copy link
Copy Markdown
Contributor

  1. isJudgeResultVisible 이 만약 대회 중에 false 였다면 대회가 끝나고 나서 true로 바뀌어서 채점 결과를 볼 수 있는지?
    1-1. 만약에 false인 상태에서 바뀌지 않는다면 추후 공개 문제로 바뀌고 나서도 계속 채점 결과가 나오지 않아야 하는지?

학재한테도 물어봤었는데, Contest 관련해서 위 2개 사항이 궁금하네요.
혹시 아시는 분 있으실까요?

Comment on lines +1144 to +1150
assignment: {
select: {
startTime: true,
endTime: true,
isJudgeResultVisible: true
}
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assignment 검사하는 부분이 삭제되어서 JOIN 연산도 필요없을 것 같습니다.
select도 없애주세요

@github-project-automation github-project-automation Bot moved this from Approved 👌 to In Progress 🏃 in Codedang May 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🪰 bug Something isn't working ⛳️ team-backend

Projects

Status: In Progress 🏃

Development

Successfully merging this pull request may close these issues.

[Bug]: 26-1 백엔드 버그픽스

5 participants