Trivy가 다시 공격받다: 광범위한 GitHub Actions 태그 변조로 비밀정보 유출

3 days ago 4
  • 공식 GitHub Action이 태그 강제 업데이트로 변조되어 악성코드가 배포된 공급망 공격 발생
  • 공격자는 76개 중 75개 태그를 악성 커밋으로 교체, 약 1만 개 이상의 워크플로가 영향을 받음
  • 변조된 스크립트는 비밀정보 수집·암호화·유출의 3단계로 동작하며, TeamPCP Cloud stealer 코드가 포함됨
  • 감염된 태그는 여전히 활성 상태로, @0.35.0 또는 특정 commit SHA만 안전한 것으로 확인됨
  • 모든 자격 증명 교체와 commit SHA 고정 사용이 필수이며, Docker Hub 이미지도 동일한 오염이 확인됨

Trivy GitHub Actions 공급망 공격 개요

  • Trivy의 공식 GitHub Action(aquasecurity/trivy-action)이 공격자에 의해 태그 강제 업데이트(force-push) 방식으로 변조되어 악성코드가 배포된 사건
  • 공격자는 76개 버전 태그 중 75개를 악성 커밋으로 교체, CI/CD 파이프라인에서 자동 실행되도록 조작
  • 10,000개 이상의 GitHub 워크플로 파일이 해당 액션을 참조하고 있어 피해 범위가 광범위함
  • 감염된 태그는 여전히 활성 상태이며, @0.35.0만이 유일하게 안전한 버전으로 확인됨
  • Socket은 19:15 UTC부터 실시간으로 182건의 악성 GitHub Action 이벤트를 탐지, Backdoor, Infostealer, Reconnaissance 유형으로 분류

공격의 원인과 진행 방식

  • Trivy 유지관리자에 따르면, 이번 공격은 쓰기 권한이 있는 자격 증명 탈취로 인해 발생
    • 3월 초 발생한 이전 침해에서 CI 환경의 비밀이 유출되었으며, 회전(rotating) 과정이 완전하지 않아 새 자격 증명 일부가 공격자에게 남음
    • 공격자는 이 자격 증명을 이용해 GitHub 자체 취약점 없이 인증된 태그 업데이트를 수행
  • 공격자는 브랜치 푸시나 릴리스 생성 대신, 기존 태그를 강제로 새 커밋으로 덮어씀
    • 각 태그는 원래 커밋의 메타데이터(작성자, 이메일, 타임스탬프, 커밋 메시지)를 복제해 정상처럼 보이게 위조
    • 단, 원본 커밋은 GPG 서명되어 있었으나 공격자의 커밋은 서명 누락, 부모 커밋 날짜가 2026년으로 불일치
  • GitHub의 Immutable Release 표시가 있더라도, 공격자가 악성 상태로 게시 후 잠금 처리했을 가능성 있음
    • 따라서 “Immutable” 배지에 의존하지 말고 commit SHA 고정(pinning) 방식만이 안전한 소비 방법임

태그 변조 구조

  • 공격자는 master 브랜치의 최신 커밋(57a97c7e)을 기반으로 새 커밋을 생성
    • entrypoint.sh 파일만 악성 버전으로 교체하고 나머지 파일은 그대로 유지
    • 각 태그는 원래의 PR 번호, 커밋 메시지, 작성자 정보를 그대로 복제해 위조
  • GitHub 릴리스 페이지에서 “0 commits to master since this release”로 표시되는 경우, 변조된 태그의 시각적 지표로 확인 가능
  • 0.35.0 태그만 변조되지 않은 이유는 이미 master HEAD를 가리키고 있었기 때문

악성 페이로드 구조

  • 변조된 entrypoint.sh는 총 204줄이며, 4~105줄에 Infostealer 코드, 이후 정상 Trivy 스캔 코드 포함
  • 악성코드는 세 단계로 구성됨
    • 1단계: 수집(Collection) — 런너 프로세스 메모리 및 파일시스템에서 비밀정보 추출
    • 2단계: 암호화(Encryption) — AES-256-CBC 및 RSA-4096으로 수집 데이터 암호화
    • 3단계: 유출(Exfiltration) — 공격자 제어 도메인 또는 피해자 GitHub 계정으로 전송
  • 1단계: 비밀정보 수집

    • GitHub Actions 런너 프로세스(Runner.Worker, Runner.Listener, runsvc, run.sh)의 환경변수를 /proc/<pid>/environ에서 읽어 env, ssh 키워드 포함 항목을 추출
    • GitHub 호스팅 런너에서는 Python 기반 메모리 덤프 스크립트를 sudo로 실행, Runner.Worker 프로세스 메모리에서 "isSecret":true 패턴을 검색
    • 자체 호스팅 런너에서는 TeamPCP Cloud stealer로 식별되는 파일시스템 크리덴셜 수집기 실행
      • SSH 키, AWS/GCP/Azure 자격 증명, Kubernetes 토큰, Docker 설정, DB 비밀번호, 환경파일, TLS 키, VPN 설정, Webhook URL, 지갑 키 등 광범위한 대상 포함
  • 2단계: 암호화

    • openssl rand로 32바이트 세션 키 생성 후, AES-256-CBC로 데이터 암호화
    • 세션 키는 RSA-4096 공개키로 OAEP 패딩을 적용해 암호화
    • 암호화된 데이터(payload.enc)와 세션 키(session.key.enc)를 tpcp.tar.gz로 묶음
  • 3단계: 데이터 유출

    • 1차 채널: https://scan[.]aquasecurtiy[.]org로 HTTPS POST 전송 (aquasecurity 오타 도메인 사용)
    • 2차 채널: 실패 시 피해자의 GitHub Personal Access Token을 이용해 tpcp-docs라는 공개 저장소 생성
      • 릴리스 자산으로 tpcp.tar.gz 업로드 → 공격자는 GitHub 검색으로 해당 저장소를 찾아 데이터 수집
    • GitHub 인프라를 이용해 방화벽 우회를 시도, 탐지 회피 가능성 높음
    • 마지막으로 임시 파일 삭제, 흔적 최소화

공격자 및 배후

  • 악성 코드 내 주석에 “TeamPCP Cloud stealer” 명시
    • TeamPCP(DeadCatx3, PCPcat, ShellForce)는 클라우드 네이티브 환경 공격 그룹으로, Docker API·Kubernetes·Redis·Ray 대시보드 취약점 악용 사례 존재
    • 2026년 2월 Flare와 The Hacker News에서 랜섬웨어·데이터 탈취·암호화폐 채굴 캠페인으로 보고된 바 있음
  • Solana 검증자 키 및 암호화폐 지갑 수집 기능은 재정적 동기와 일치

대응 및 권고

  • 모든 Trivy Action 버전 태그 사용 중단, 오직 commit SHA 57a97c7e7821a5776cebc9bb87c984fa69cba8f1 또는 태그 0.35.0 만 사용
  • 감염된 파이프라인은 완전한 비밀 유출로 간주, 모든 클라우드 자격 증명·SSH 키·API 토큰·DB 비밀번호·Docker 토큰 즉시 교체 필요
  • GitHub 조직 내 tpcp-docs 저장소 존재 여부 점검 및 3월 19일 19:00 UTC 이후 실행된 trivy-action 로그 검토 권장

침해 지표 (IOCs)

  • 네트워크 지표: scan[.]aquasecurtiy[.]org
  • 파일 해시: 18a24f83e807479438dcab7a1804c51a00dafc1d526698a66e0640d1e5dd671a (entrypoint.sh)
  • 감염된 GitHub Actions: aquasecurity/trivy-action@0.0.1 ~ @0.34.2 전 버전 포함 (총 75개 태그)

추가 업데이트 (3월 22일)

  • Docker Hub에서도 Trivy 이미지(0.69.4, 0.69.5, 0.69.6, latest) 가 동일한 Infostealer 페이로드로 오염된 사실 확인
  • latest 태그가 악성 이미지로 지정되어 노출 기간 동안 사용자에게 배포됨
  • 관련 상세 내용은 Socket의 별도 보고서 *“Trivy Docker Images Compromised”*에서 확인 가능
Read Entire Article