GitHub Dependency Review Action으로 새 의존성을 PR 단계에서 검증하기

2026-05-21 hit count image

새 의존성을 추가하는 PR이 알려진 CVE를 가진 패키지, 라이선스 위반, 위험한 메인테이너 변경을 끌어들이지 못하도록 GitHub Dependency Review Action으로 PR 게이트를 거는 방법을 실제 사고 사례와 함께 정리합니다.

web

들어가며

공급망 시리즈에서 cooldown은 “새로 게시된 악성 버전”을 막는 시간 기반 게이트라고 했습니다. 한편 yarn npm audit은 이미 의존 트리에 들어와 있는 알려진 CVE를 잡습니다.

그 사이에 있는 마지막 빈틈이 하나 더 있습니다 — 개발자가 PR로 새 의존성을 추가하는 순간입니다. 이 글에서는 GitHub의 dependency-review-action으로 이 단계를 자동 검증하는 방법을 다룹니다.

어떤 위험이 있는가

PR로 새 의존성을 추가할 때 일어날 수 있는 일은 다음과 같습니다.

1. 알려진 CVE가 있는 패키지를 들이는 경우

yarn add some-cool-lib를 실행했을 때, 그 라이브러리(또는 그것의 간접 의존성)에 이미 high 등급 CVE가 등록되어 있는 경우가 있습니다. 리뷰어가 CVE 데이터베이스를 매번 직접 조회하지 않으면 그대로 머지됩니다.

2. 타이포스쿼팅 패키지를 잘못 추가

yarn add react-doom 같은 오타. 또는 의도적으로 인기 패키지와 비슷한 이름의 가짜 패키지가 npm에 올라와 있어, 무심코 그것을 설치하게 되는 경우입니다.

3. 의존성 컨퓨전을 통한 내부 패키지 사칭

내부 사설 패키지와 같은 이름의 가짜 패키지가 공개 레지스트리에 올라와, 빌드 시스템이 잘못 가져오게 되는 경우입니다. Alex Birsan의 2021년 연구에서 Microsoft·Apple·Uber 등 35개 이상 기업에서 코드 실행이 확인된 공격 방식입니다.

4. 라이선스 위반

GPL/AGPL 같은 강한 카피레프트 라이선스의 패키지를 상용 SaaS에 무심코 도입하면, 회사 차원의 법적 리스크가 됩니다. 이 검사도 사람이 매번 하긴 어렵습니다.

5. 메인테이너 변경

같은 패키지라도 메인테이너가 바뀐 뒤 새 버전이 나오는 경우, 신뢰 기반이 달라집니다. 2018년의 event-stream 사례처럼 새 메인테이너가 악성 코드를 의도적으로 삽입한 전례가 있습니다.

cooldown은 이 중 일부만 막을 수 있고(악성 신규 게시), 나머지는 PR 단계에서의 자동 검증이 필요합니다.

실제 사례: 타이포스쿼팅과 의도하지 않은 위험

crossenv vs cross-env (2017)

가장 자주 인용되는 타이포스쿼팅 사례입니다. 정상 패키지 cross-env 대신 한 글자 다른 crossenv를 설치하면 환경 변수와 시스템 정보를 외부로 유출하는 악성 코드가 실행되었습니다. (공식 분석)

이 종류의 패키지는 게시 후 비교적 빨리 npm에서 삭제되지만, 그 사이에 누군가의 PR로 한 번 들어가면 끝입니다. Dependency Review Action을 PR 게이트에 걸어 두면 이런 패키지가 의존성 그래프에 추가되는 시점에 알림이 가도록 만들 수 있습니다.

Alex Birsan의 의존성 컨퓨전 (2021)

Alex Birsan은 Microsoft, Apple, Uber 등 35개 이상 기업의 빌드 시스템에서 코드 실행에 성공했습니다. 방법은 단순했습니다 — 내부 사설 패키지 이름을 추측하거나 GitHub에서 수집한 뒤, 공개 npm에 같은 이름의 패키지를 더 높은 버전으로 게시. 그러면 빌드 시스템이 공개 버전을 우선시해 가져갔습니다.

이 공격의 본질은 “들어와서는 안 될 패키지가 의존성 그래프에 새로 추가되는 것”입니다. Dependency Review Action은 PR diff에서 의존성 그래프 변경을 자동으로 감지하므로, 이런 신규 추가를 가장 빨리 포착할 수 있는 지점이 됩니다.

Dependency Review Action의 동작 방식

actions/dependency-review-action은 PR의 base 브랜치와 head 브랜치의 의존성 그래프 차이를 계산한 뒤, 추가되거나 변경된 의존성에 대해 다음을 검사합니다.

  • 알려진 CVE (GitHub Advisory Database 매칭)
  • 심각도(severity) — low / moderate / high / critical
  • 라이선스 (allow-licenses / deny-licenses 화이트/블랙리스트)
  • (선택) OpenSSF Scorecard 점수 — 메인테이너 활동성·코드 리뷰 빈도 등

설정한 임계치를 초과하는 변경이 있으면 PR이 실패하고, PR 댓글로 어떤 의존성이 어떤 이유로 막혔는지가 자동으로 표시됩니다.

어떻게 적용하는가

가장 간단한 워크플로우는 다음과 같습니다.

# .github/workflows/dependency-review.yml
name: Dependency Review
on: pull_request

permissions:
  contents: read
  pull-requests: write # PR에 댓글로 결과 보고

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@<SHA> # v6
      - uses: actions/dependency-review-action@<SHA>
        with:
          fail-on-severity: high
          comment-summary-in-pr: always

옵션 의미:

옵션설명
fail-on-severity이 등급 이상의 CVE가 추가되면 PR 실패. low / moderate / high / critical
comment-summary-in-pralways로 두면 PR마다 자동 요약 댓글
allow-licenses / deny-licenses허용/금지 라이선스 목록

권장 시작 설정

처음 도입할 때는 다음 조합이 비용 대비 효과가 좋습니다.

fail-on-severity: high
comment-summary-in-pr: always

high 이상만 막으면 false positive가 거의 없고, 댓글로 시각화되면 리뷰어가 추가 의존성의 위험도를 한눈에 확인할 수 있습니다. 운영 안정성이 확보되면 moderate로 단계적으로 좁혀갈 수 있습니다.

한계

  • GitHub Advisory Database에 등재된 CVE만 잡습니다. 0-day나 등재 전 단계의 악성 패키지는 cooldown이나 Socket 같은 행위 분석 SaaS가 보완해야 합니다.
  • 이미 머지된 의존성은 검사 대상이 아닙니다. 새 PR의 diff만 봅니다. 이미 있는 의존성에 새 CVE가 추가되는 경우는 yarn npm audit이 잡습니다.
  • GitHub 외 호스팅에서는 작동하지 않습니다. GitLab·Bitbucket을 쓴다면 Snyk PR Checks 같은 대안을 봐야 합니다.

마무리

PR 단계는 공급망 방어의 마지막 인간 검수 지점입니다. 그 지점에서 의존성 변경의 위험도를 사람이 매번 직접 판단하기란 현실적으로 어렵습니다. Dependency Review Action은 이 판단을 자동화해서, 리뷰어가 “이 PR에 추가되는 새 의존성에 알려진 CVE가 있는가?”를 별도로 조사하지 않아도 되게 만듭니다.

워크플로우 하나, 옵션 두 개로 끝납니다. 적용 비용 대비 막아낼 수 있는 사고 범위가 넓어, 공급망 방어 시리즈의 세 전략 다음으로 도입하기 좋은 네 번째 층입니다.

참고 자료

제 블로그가 도움이 되셨나요? 하단의 댓글을 달아주시면 저에게 큰 힘이 됩니다!

앱 홍보

책 홍보

블로그를 운영하면서 좋은 기회가 생겨 책을 출판하게 되었습니다.

아래 링크를 통해 제가 쓴 책을 구매하실 수 있습니다.
많은 분들에게 도움이 되면 좋겠네요.



SHARE
Twitter Facebook RSS