Gh Actions - Context Script Injections
Reading time: 4 minutes
tip
AWS 해킹 배우기 및 연습하기:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기:
HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 Discord 그룹 또는 텔레그램 그룹에 참여하거나 Twitter 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
위험 이해
GitHub Actions는 단계가 실행되기 전에 ${{ ... }} 표현식을 렌더링합니다. 렌더된 값은 해당 단계의 프로그램(예: run 단계의 경우 셸 스크립트)에 붙여넣어집니다. run: 안에 신뢰할 수 없는 입력을 직접 인터폴레이션하면 공격자가 셸 프로그램의 일부를 제어하여 임의의 명령을 실행할 수 있습니다.
Docs: https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions and contexts/functions: https://docs.github.com/en/actions/learn-github-actions/contexts
핵심 요점:
- 렌더링은 실행 전에 발생합니다. 모든 표현식이 해석된 상태로 run 스크립트가 생성된 다음 셸에서 실행됩니다.
- 많은 contexts는 트리거 이벤트(issues, PRs, comments, discussions, forks, stars 등)에 따라 사용자 제어 필드를 포함합니다. 신뢰할 수 없는 입력에 대한 참고는 다음을 보세요: https://securitylab.github.com/resources/github-actions-untrusted-input/
- run: 내부의 셸 따옴표는 신뢰할 수 있는 방어책이 아닙니다. 인젝션은 템플릿 렌더링 단계에서 발생하기 때문입니다. 공격자는 조작된 입력을 통해 따옴표를 탈출하거나 연산자를 주입할 수 있습니다.
취약한 패턴 → RCE on runner
취약한 workflow (누군가 새 이슈를 열 때 트리거됨):
name: New Issue Created
on:
issues:
types: [opened]
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: New issue
run: |
echo "New issue ${{ github.event.issue.title }} created"
- name: Add "new" label to issue
uses: actions-ecosystem/action-add-labels@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
labels: new
공격자가 제목이 $(id)인 이슈를 열면, 렌더된 단계는 다음과 같이 됩니다:
echo "New issue $(id) created"
command substitution은 runner에서 id를 실행합니다. 예시 출력:
New issue uid=1001(runner) gid=118(docker) groups=118(docker),4(adm),100(users),999(systemd-journal) created
따옴표로 감싸는 것으로는 안전해지지 않는 이유:
- 표현식은 먼저 렌더링된 다음, 그 결과 스크립트가 실행됩니다. 만약 신뢰할 수 없는 값에 $(...),
;,"/', 또는 개행이 포함되어 있다면, 따옴표로 감싸더라도 프로그램 구조를 변경할 수 있습니다.
안전한 패턴 (shell variables via env)
올바른 완화 방법: 신뢰할 수 없는 입력을 환경 변수에 복사한 다음, run 스크립트에서 네이티브 shell 확장($VAR)을 사용하세요. 명령 내부에 ${{ ... }}로 다시 포함시키지 마세요.
# safe
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: New issue
env:
TITLE: ${{ github.event.issue.title }}
run: |
echo "New issue $TITLE created"
Notes:
- run: 안에서 ${{ env.TITLE }} 사용을 피하세요. 이는 명령에 템플릿 렌더링을 다시 도입하여 동일한 injection 위험을 초래합니다.
- untrusted inputs는 env: 매핑을 통해 전달하고 run:에서 $VAR로 참조하는 것이 바람직합니다.
Reader-triggerable surfaces (treat as untrusted)
읽는 사용자가 트리거할 수 있는 이벤트는 많습니다. public repositories에 대해 read 권한만 있는 계정도 여러 이벤트를 트리거할 수 있습니다. 이러한 이벤트로부터 유래한 contexts의 모든 필드는 달리 입증되지 않는 한 공격자에 의해 조작될 수 있다고 간주해야 합니다. 예시:
- issues, issue_comment
- discussion, discussion_comment (orgs는 discussions를 제한할 수 있음)
- pull_request, pull_request_review, pull_request_review_comment
- pull_request_target (오용 시 위험함, base repo 컨텍스트에서 실행됨)
- fork (누구나 public repos를 fork할 수 있음)
- watch (리포지토리에 star를 누르는 행위)
- workflow_run/workflow_call 체인을 통한 간접적 경로
어떤 특정 필드가 공격자 제어인지 여부는 이벤트별로 다릅니다. GitHub Security Lab의 untrusted input 가이드를 참조하세요: https://securitylab.github.com/resources/github-actions-untrusted-input/
Practical tips
- run: 안에서 expressions 사용을 최소화하세요. env: 매핑 + $VAR를 선호하세요.
- 입력을 변환해야 한다면 shell에서 안전한 도구(printf %q, jq -r 등)를 사용해 변환하되, 항상 shell 변수에서 시작하세요.
- 스크립트, 명령행 플래그, 파일 경로에 branch names, PR titles, usernames, labels, discussion titles, PR head refs 등을 보간할 때 각별히 주의하세요.
- reusable workflows와 composite actions에도 동일한 패턴을 적용하세요: env로 매핑한 다음 $VAR로 참조합니다.
References
- GitHub Actions: A Cloudy Day for Security - Part 1
- GitHub workflow syntax
- Contexts and expression syntax
- Untrusted input reference for GitHub Actions
tip
AWS 해킹 배우기 및 연습하기:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기:
HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 Discord 그룹 또는 텔레그램 그룹에 참여하거나 Twitter 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
HackTricks Cloud