Skip to content

/approve-prs, /merge-prs 엔드포인트에 인증이 전혀 없고, 레포 제한도 빠져있음 #46

Description

@SimYunSup

배경

index.js의 라우팅을 보면 엔드포인트별 인증 방식이 다르다. /webhooksX-Hub-Signature-256 서명을 검증하고, /internal/*X-Internal-Secret 헤더를 검증한다(internal-dispatch.js verifyInternalRequest). 반면 /check-weeks, /approve-prs, /merge-prs는 요청 인증이 전혀 없다.

이 세 엔드포인트가 유일하게 걸어둔 방어는 utils/validation.jsvalidateOrganization(orgName)orgName === "DaleStudy" 문자열 비교뿐이다. orgName은 요청 바디의 repo_owner를 그대로 받고, 안 주면 parsePrActionPayload/checkWeeks 둘 다 data.repo_owner || "DaleStudy"로 기본값을 채운다. 즉 이 검증은 GitHub 조직 소속을 실제로 확인하는 게 아니라, 호출자가 그냥 아무것도 안 넣거나 "DaleStudy"라고 적기만 하면 통과한다.

문제

  • /approve-prs, /merge-prs가 공유하는 parsePrActionPayload(utils/prActions.js)에는 repo_nameALLOWED_REPO(leetcode-study)로 제한하는 로직이 없다. check-weeks.jsrepo_name !== ALLOWED_REPO 체크를 갖고 있다(check-weeks.js).
  • CORS는 Access-Control-Allow-Origin: *이라 브라우저에서도 직접 호출 가능.
  • 종합하면 POST /merge-prs{"repo_name": "<DaleStudy 조직의 임의 레포>"}만 보내면, 인증·서명·비밀값 없이 그 레포의 열려있는 PR을 자동 승인/auto-merge 활성화할 수 있다.

영향

  • leetcode-study 외 DaleStudy 조직의 다른(프로덕션) 레포가 있다면, 그쪽 PR도 승인·병합될 수 있음 — GitHub App 권한 범위 전체가 사실상 무방비.
  • 승인/병합은 되돌리기 어려운 동작이라 오남용 시 피해가 즉시 발생.

제안

  • /approve-prs, /merge-prs에도 /internal/*처럼 요청 인증(비밀 헤더 또는 서명) 추가.
  • parsePrActionPayloadcheck-weeks.js와 동일한 repo_name === ALLOWED_REPO 체크 추가(또는 허용 레포 목록화).
  • validateOrganization이 요청 바디의 자기 신고 값이 아니라 실제 인증된 컨텍스트를 검증하도록 재검토.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions