본문으로 건너뛰기
개발 머꼬
개발 노트GitHub Actions
hohyeon.dev21

포크 PR에서 시크릿을 쓰려고 pull_request_target을 썼다가 되돌린 이유

  • #Engineering Note
  • #GitHub Actions
  • #보안

문제 발생

포크에서 온 PR에서는 시크릿이 비어 있어 미리보기 배포가 실패했습니다. 검색해서 나온 대로 트리거를 바꿨습니다.

on: pull_request_target

jobs:
  preview:
    steps:
      - uses: actions/checkout@v5
        with:
          ref: ${{ github.event.pull_request.head.sha }}   # PR 코드를 체크아웃
      - run: pnpm install && pnpm build                     # 그 코드를 실행

동작은 했습니다. 그리고 이 워크플로는 아무나 우리 시크릿을 가져갈 수 있는 구멍이었습니다.

원인 분석

pull_request_target은 신뢰 경계가 다른 트리거입니다. GitHub 문서가 경고합니다 — pull_request_target 트리거에서 신뢰할 수 없는 코드를 실행하면 보안 취약점으로 이어질 수 있습니다. 여기에는 캐시 오염과 쓰기 권한 또는 시크릿에 대한 의도치 않은 접근이 포함됩니다.

핵심 차이는 실행 컨텍스트입니다. pull_request는 병합 커밋 컨텍스트에서 시크릿 없이, 읽기 권한으로 돌지만, pull_request_target기본 브랜치 컨텍스트에서 시크릿과 쓰기 토큰을 가진 채 돕니다.

그 상태에서 PR의 head SHA를 체크아웃해 빌드하면, PR 작성자가 넣은 코드(빌드 스크립트, 의존성 postinstall 하나면 충분합니다)가 시크릿과 토큰이 있는 환경에서 실행됩니다. 우리가 만든 것은 "포크 PR 미리보기"가 아니라 "임의 코드 실행 엔드포인트"였습니다.

해결 방안

  1. pull_request_target에서는 PR 코드를 체크아웃하지 않습니다. 이 트리거의 정당한 용도는 라벨링, 코멘트, 크기 계산처럼 PR 코드를 실행하지 않는 작업입니다.

  2. 빌드·테스트는 pull_request로 돌립니다. 시크릿 없이 도는 것이 기능이 아니라 설계입니다. 포크 PR에서 시크릿이 필요하다는 요구 자체를 다시 봅니다.

  3. 미리보기 배포가 꼭 필요하면 두 단계로 나눕니다. 신뢰 없는 job이 아티팩트만 만들고, 시크릿을 가진 별도 워크플로가 그 아티팩트를 받아 배포합니다. 코드는 실행하지 않고 산출물만 옮깁니다.

  4. environment 승인을 겁니다. 시크릿이 필요한 job에 environment protection rule을 붙이면 사람이 승인해야 진행됩니다.

  5. permissions:를 최소로 낮춥니다. 사고가 나도 토큰으로 할 수 있는 일이 줄어듭니다.

  6. 캐시 오염도 함께 고려합니다. 문서가 언급하는 그대로 신뢰 없는 코드가 캐시에 쓰면, 그 캐시를 복원하는 다음 빌드까지 오염됩니다.

공식 문서

마지막 수정

좋아요북마크

댓글0

아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.