사고 · GitHub Action 침해
tj-actions/changed-files 침해: 발생한 일과 Kilobat의 역할이 작은 이유
2025년 3월 14일과 15일, 23,000개가 넘는 저장소에서 사용하던 GitHub Action이 이를 실행한 모든 워크플로의 비밀 정보를 해당 워크플로 로그에 출력했습니다. 이 일은 개발자의 Mac이 아닌 CI 러너에서 발생했으므로 이 페이지는 주로 저장소에서 확인할 사항을 다루고 Kilobat이 볼 수 있었던 범위가 얼마나 제한적인지 분명히 설명합니다.
요약
- 보호: 도움이 되지 않음
공격은 GitHub 러너에서 실행되었습니다. 단 한 번의 다운로드는 gist.githubusercontent.com에서 이루어졌으며 외부 서버로 전송된 정보는 전혀 없었습니다.
- 에이전트 보호: 도움이 되지 않음
에이전트는 관여하지 않았고 비밀 정보는 연결이 아닌 로그 출력을 통해 유출되었습니다.
- 에이전트 네트워크 로그: 도움이 되지 않음
act로 실행한 워크플로는 Docker에서 실행되며 Kilobat은 해당 트래픽을 에이전트에 귀속할 수 없습니다. - 앱 트래픽: 제한적
워크플로를 자체 호스팅 러너로 직접 실행하는 Mac에서만 앱 목록에 gist 다운로드를 포함한 러너의 연결이 표시됩니다. 차단되는 항목은 없습니다.
발생한 일
CVE-2025-30066에 대한 GitHub 권고에 따르면 공격자는 v1.0.0부터 해당 액션의 기존 버전 태그 대부분이 악성 커밋 0e58ed8을 가리키도록 변경했습니다. 태그로 액션을 사용하던 모든 워크플로는 다음 실행에서 해당 코드를 받았습니다. 코드는 GitHub gist에서 Python 스크립트를 다운로드하고 sudo로 실행했습니다. 스크립트는 GitHub의 Runner.Worker 프로세스를 찾아 메모리를 읽고 비밀 정보로 표시된 값을 추출해 base64로 두 번 인코딩하여 로그에 출력했습니다. 전체 커밋 해시로 고정된 워크플로는 영향을 받지 않았습니다.
공개 저장소의 워크플로 로그는 공개되므로 누구나 비밀 정보를 읽을 수 있었습니다. Wiz는 비밀 정보가 노출된 저장소 수십 개를 발견했으며 비공개 저장소의 위험은 훨씬 작았습니다. StepSecurity는 러너 모니터링이 예상치 못한 gist.githubusercontent.com 호출을 표시해 이를 발견했습니다.
tj-actions 유지 관리자는 봇 계정의 개인 액세스 토큰이 침해되었다고 밝혔습니다. Unit 42가 경로를 더 거슬러 추적한 결과 SpotBugs 저장소에 푸시된 워크플로에서 reviewdog/action-setup에 쓰기 권한이 있는 유지 관리자의 토큰이 유출되었습니다. 이어 해당 액션이 침해되었고(CVE-2025-30154), 이를 사용한 tj-actions 워크플로에서 봇 토큰이 유출되었습니다. Unit 42에 따르면 첫 표적은 Coinbase 오픈 소스 프로젝트였으며 공격자는 그곳의 비밀 정보를 사용하지 못했습니다.
타임라인
- 2024년 11월
Unit 42는 공격자의 첫 단계를 이 달로 추정합니다.
- 2025년 3월 11일
SpotBugs에 푸시된 워크플로에서 유지 관리자의 토큰이 유출되고
reviewdog/action-setup@v1이 18:42~20:31 UTC 사이에 침해됩니다(Unit 42, CISA). - 3월 14일 약 16:00 UTC
액션 태그가 악성 커밋을 가리킵니다. StepSecurity는 이를 감지하고 한 시간 내에 대부분 버전이 영향을 받았음을 확인합니다.
- 2025년 3월 15일
gist가 삭제되고 GitHub는 액션을 내린 뒤 정리하여 복원합니다(StepSecurity의 타임라인 기준 14:00 및 22:00 UTC). 수정 버전은 46.0.1입니다.
- 2025년 3월 18일
StepSecurity가 여러 reviewdog 액션도 침해된 것을 발견하고 CISA가 경고를 발표합니다.
- 2025년 3월 26일
CISA 경고가 알려진 악용 취약점 목록에 두 CVE를 모두 기록합니다.
- 2025년 4월 2일
Unit 42가 침해로 이어진 SpotBugs 및 Coinbase 단계를 발표합니다.
네트워크에서 보인 모습
모든 일은 CI 러너에서 발생했습니다. 악성 단계는 memdump.py을 가져오기 위해 gist.githubusercontent.com에 한 번의 외부 요청을 보냈으며 나머지는 러너 내부에서 이루어졌습니다. 비밀 정보는 공격자의 서버로 전송되지 않았습니다. 로그에 기록되었고 GitHub가 그 로그를 열람자에게 제공했습니다.
공개된 스크립트는 Linux의 /proc 파일 시스템을 통해 러너 프로세스를 찾으며 출처들은 Linux 러너에서의 영향을 설명합니다. 탈취된 토큰은 이후 어디서든 GitHub와 해당 토큰이 속한 다른 서비스에 사용할 수 있었습니다.
침해 지표
출처에 기록된 그대로입니다. 도메인은 링크가 아닌 텍스트이며 출처가 무해화한 경우 그대로 무해화했습니다([.]). 이 인프라는 대부분 오래전에 사라졌습니다. 지표는 현재 캠페인을 차단하기보다 오래된 로그, 파일 및 계정을 확인하는 데 도움이 됩니다.
| 지표 | 유형 | 표시 위치 | 참고 |
|---|---|---|---|
0e58ed8671d6b60d0890c21b07f8835ace038e67 | 커밋 | tj-actions/changed-files | 변경된 태그가 가리킨 커밋. |
gist.githubusercontent.com/nikitastupin/30e525b776c409e03c2d6f328f254965/raw/memdump.py | URL | CI 러너 | 메모리 덤프 스크립트. 2025년 3월 15일 삭제됨. |
A double-base64 string in the changed-files step’s log | 로그 출력 | 워크플로 로그 | 페이로드가 실행되었다면 존재합니다. 디코딩하면 해당 실행의 비밀 정보가 들어 있습니다. |
reviewdog/action-setup@v1, 11 March 2025, 18:42–20:31 UTC | 액션, 기간 | 워크플로 | CVE-2025-30154. 이를 사용하는 다른 reviewdog 액션에도 영향을 주었습니다. |
tj-actions/changed-files, 12 March 00:00 to 15 March 12:00 UTC | 액션, 기간 | 워크플로 | CISA가 감사를 요청한 기간. |
Kilobat이 표시하거나 차단했을 내용
- 앱 트래픽. Mac이 자체 호스팅 러너로 액션을 실행했다면 Kilobat 앱 목록에 러너 프로세스의
gist.githubusercontent.com연결이 표시되었을 것입니다. 해당 호스트는 위협 목록에 없으며 정상적으로 gist를 자주 사용하므로 목록에 들어가서도 안 됩니다. - 에이전트 네트워크 로그. AI 에이전트에서 실행하더라도 Mac에서
act로 워크플로를 실행하면 단계는 Docker 컨테이너 안에서 실행됩니다. 연결은 Docker 자체 프로세스를 통해 나가며 Kilobat은 이를 에이전트에 귀속할 수 없으므로 에이전트 네트워크 로그에 표시되지 않습니다. - 보호. 보호가 대응할 대상은 없었습니다. 유출된 로그의 토큰이 나중에 사용자에게 사용되었다면 해당 사용은 공격자의 컴퓨터에서 GitHub를 대상으로 이루어졌습니다.
Kilobat이 도움이 되지 않았을 경우
- 침해, 비밀 정보 덤프 및 유출은 모두 GitHub Actions에서 발생했습니다. Mac의 도구는 다른 사람의 러너를 볼 수 없습니다.
- 비밀 정보는 차단할 수 있는 연결이 아닌 GitHub가 정상적으로 제공한 로그 출력을 통해 유출되었습니다.
- 스크립트는 GitHub가 호스팅하는 gist에서 가져왔으며 네트워크 필터가 허용해야 하는 호스트입니다.
- Mac의 Docker 컨테이너와 VM 내부는 Kilobat의 프로세스별 보기에서 확인할 수 없습니다.
지금 Mac 확인하기
저장소에서 영향을 받은 액션을 사용하는 워크플로를 나열하세요.
grep -rnE "tj-actions/changed-files|tj-actions/eslint-changed-files|reviewdog/action-" .github/workflows또는 GitHub의 모든 저장소를 한 번에 검색하세요.
gh search code "tj-actions/changed-files" --owner YOUR-ACCOUNT-OR-ORG2025년 3월 12~15일의 실행에 대해 changed-files 단계의 로그를 열고 두 번 디코딩되는 긴 문자열을 찾으세요. 발견하면 해당 워크플로가 읽을 수 있었던 모든 비밀 정보가 노출된 것입니다.
echo 'PASTE-THE-STRING' | base64 -d | base64 -d해당 비밀 정보를 교체한 다음 영향을 받은 로그를 기록용으로 다운로드하고 실행 기록을 삭제하여 더 이상 비밀 정보를 읽을 수 없게 하세요.
커밋이 아닌 태그로 고정된 액션을 찾으세요. GitHub 권장대로 전체 커밋 해시에 고정하세요.
grep -rnE "uses: *[^ ]+@(v[0-9][^ ]*|main|master) *$" .github/workflowsMac에서 사용하는 토큰이 저장소 비밀 정보로 저장되었다면 Settings › Developer settings › Personal access tokens에서 폐기하고 GitHub CLI가 어떤 계정으로 로그인했는지 확인하세요.
gh auth status
출처
- GitHub 권고 데이터베이스: GHSA-mrrh-fwg8-r2c3, CVE-2025-30066
- CISA: 서드파티 tj-actions/changed-files(CVE-2025-30066) 및 reviewdog/action-setup@v1(CVE-2025-30154) 공급망 침해
- StepSecurity: Harden-Runner 감지, tj-actions/changed-files 액션 침해
- Wiz: GitHub Action tj-actions/changed-files 공급망 공격
- Unit 42: GitHub Actions 공급망 공격, Coinbase 표적 공격에서 광범위한 tj-actions/changed-files 사고로 확대
2026년 11월 1일에 확인했습니다.
에이전트와 앱이 어디에 연결하는지 확인하세요
Kilobat은 모든 연결 뒤에 있는 앱, 프로세스 및 에이전트의 이름을 표시하고 알려진 악성 호스트를 차단하며 각 에이전트 세션이 연결한 대상을 기록하는 Mac 메뉴 막대 앱입니다.
brew install seifip/kilobat/kilobat