GitHub Actions is a trap

Tyler Cipriani

GitHub Actions는 함정이다

원문은 Tyler Cipriani님이 에 게재했습니다. 이 블로그 구독하기

해커들이 지칠 정도로 빠른 속도로 패키지를 털고 있고, 모든 사후 분석 보고서에는 어김없이 GitHub Actions가 등장한다.

2월 말, hackerbot AI1가 단 하나의 프로젝트 배포 키를 빼돌렸다. 한 달도 채 되지 않아 50여 개에 달하는 다른 프로젝트에 자격 증명 탈취 코드가 심겼다. 감염된 저장소 하나하나가 다음 공격을 위한 자격 증명을 훔쳐갔다.

이번 공급망 해킹 사태는 GitHub Actions의 함정에서 시작됐다. 단순하지만 잘못된 기본값 하나, 그리고 5년 전에 이미 제안된 수정안이 방치된 채로.

GitHub Actions와 그 대가

GitHub Actions의 함정을 경고하는 아크바 제독
GitHub Actions의 함정을 경고하는 아크바 제독

Trivy는 오픈소스 보안 스캐너이다. 하지만 3월 말에 Trivy를 사용했다면 곤욕을 치렀을 것이다.

3월 19일, 해커들은 실행되는 모든 곳에서 비밀 정보를 빼돌리려는 Trivy 버전을 배포했다. Trivy 측은 지속적 통합(CI) 시스템인 GitHub Actions의 “설정 오류” 때문이라고 밝혔다.

하지만 이번 공격은 설정 오류라기보다는 GitHub Actions의 함정에 가깝다.

Trivy가 어떻게 뚫렸는지 단순화한 코드는 다음과 같다2:

# INSECURE. DO NOT USE.
on:
  pull_request_target

jobs:
  check:
    steps:
      - uses: action/checkout@deadbeefdeadbeefdeadbeefdeadbeefdeadbeef
        with:
          ref: refs/pull/${{ github.event.pull_request.number }}/merge
      - uses: ./.github/actions/setup-go
      - uses: some/go-static-analysis@c0ffeec0ffeec0ffeec0ffeec0ffeec0ff

얼핏 보면 이 코드는 문제없어 보인다:

  • 시크릿을 참조하지 않는다.
  • 서드파티 액션은 변경 불가능한 해시로 고정되어 있다.
  • 풀 리퀘스트를 체크아웃해 정적 분석을 수행한다.

하지만 이 코드는 2021년 GitHub 블로그 글 “preventing pwn requests”에 나온 안티패턴을 그대로 옮긴 것이다:

만약 pull_request_target 워크플로우가 […] 신뢰할 수 없는 코드만 실행하고 시크릿을 참조하지 않는다면, 그래도 취약한가요?

네, 취약합니다

GitHub Security Lab

문제는 pull_request_target에 있다:

  • pull_request_target – 환경에 탐스럽고 위험한 GITHUB_TOKEN을 통째로 넣어준다.
  • actions/checkoutpersist-credentials라는 선택적 매개변수를 받는데, 이를 false로 설정하면 시크릿을 제거한다. 하지만 기본값은 true다.

persist-credentials 매개변수를 false로 설정하는 것은 2021년부터 GitHub Actions에 열린 이슈로 남아 있다2021년부터.

당신의 $HOME은 범죄 현장이다

해커들이 Trivy의 키를 손에 넣자, 더 많은 키를 훔치기 위해 Trivy의 새로운 버전을 배포했다.

LiteLLM은 CI에서 Trivy를 사용하고 있었다. 파이썬 소프트웨어 저장소인 PyPI에 코드를 배포하는 바로 그 CI였다. LiteLLM의 CI가 오염된 Trivy를 실행했을 때, 해커들은 배포 키를 낚아챘다.

그리고 3월 24일, Callum McMahon이 IDE를 켰을 때 그의 MacBook이 멈춰 버렸다. 그렇게 그는 LiteLLM 탈취 사건을 발견하게 됐다.

McMahon의 MacBook은 해커들이 LiteLLM에 몰래 심은 악성 코드 때문에 버벅이고 있었다. 그 악성 코드는 다음과 같은 자격 증명을 훔치려 했다:

  • ~/.netrc
  • ~/.aws/credentials
  • ~/.config/gcloud
  • ~/.config/gh
  • ~/.azure
  • ~/.docker/config.json
  • ~/.npmrc
  • ~/.git-credentials
  • ~/.kube/

이런 파일들은 보통 $HOME 디렉터리 여기저기에 흩어져 있으며, 토큰과 키로 가득하고 대개 암호화되어 있지도 않다.

AI와 공급망 파멸의 소용돌이

암호화되지 않은 자격 증명, 고정되지 않은 의존성, CI의 자폭 버튼 같은 문제는 예전부터 계속 다뤄 온 것들이다.

하지만 AI는 보안 실수를 반복하는 것을 포함해 모든 것을 가속했다.

Trivy가 침해된 당일, 나는 Claude에게 “how do I scan docker registry images for security vulnerabilities?”라고 물었다.

답변의 일부는 다음과 같았다:

CI/CD Integration Example (GitHub Actions with Trivy)

    - name: Scan image for vulnerabilities
      uses: aquasecurity/trivy-action@master

두 가지 면에서 잘못됐다:

  1. 고정되지 않은 참조 – master는 수시로 바뀌는 참조다. 해커가 저장소를 좀비화하면 내가 첫 번째 피해자가 된다.
  2. 현존하는 취약점 – 그날 게시된 CVE에 대한 언급이 전혀 없다. 내가 묻지 않았으니 Claude도 확인하지 않았다.

한편 Vercel의 CEO는 최근 자사 데이터 유출을 “AI로 가속된” 해커의 소행으로 돌렸다. 그리고 Anthropic의 최근 홍보 투어에는 자사 프론티어 모델이 발견한 취약점에 대해 미국 연방준비제도 의장에게 브리핑한 일도 포함된다.

LLM을 손에 쥔 나쁜 놈들은 초능력을 얻는다. LLM을 쓰는 착한 사람들은 2010년대 중반의 CI 문제에 당한다.

그리고 OpenBSD의 27년 된 보안 문제를 뿌리 뽑을 수 있는 바로 그 도구가, 여전히 GitHub Actions를 @master에 고정하라고 알려준다.


  1. 어쨌든 스스로를 hackerbot-claw라고 칭하는 누군가.↩︎

  2. 내 GitHub Actions 예시는 aquasecurity/trivy #10259에서 제거된 액션을 더 단순화한 버전이다.↩︎

이 글은 muse-spark-1.2-contributor 모델을 사용해 번역했습니다.

댓글