설명
이슈·PR 제목과 본문, 댓글, 커밋 메시지와 작성자 정보는 외부 사용자가 제어할 수 있습니다. 이런 값을 ${{ }} 표현식으로 run의 명령 문자열에 직접 넣으면 셸이 실행하기 전에 코드에 삽입되어 명령 주입으로 이어질 수 있습니다. 따옴표로 감싸는 것만으로 충분하지 않습니다.
잠재적 영향
- 주입된 명령이 실행되면 실행기의 파일과 해당 작업에 제공된 토큰·비밀정보에 접근할 수 있습니다.
- 실제 권한에 따라 결과물 변조나 저장소 작업 오용으로 이어질 수 있습니다.
해결 방법
- 외부 값을 인라인 셸 코드에 직접 삽입하지 마세요. 필요한 값은 단계의
env로 전달하고 셸에서는"$VALUE"처럼 인용된 변수로 사용하세요.eval등으로 다시 코드로 평가하지 마세요. - 형식 검증과 명령의 인자 구분을 적용하고
GITHUB_TOKEN및 비밀정보 접근을 필요한 범위로 제한하세요. pull_request_target처럼 권한이 높은 워크플로에서는 신뢰하지 않는 PR 코드를 체크아웃하거나 실행하지 마세요.
예시
첫 예시는 PR 본문을 명령에 삽입합니다. 두 번째는 저장소의 고정된 테스트 명령을 실행하는 별도 예시이며, 신뢰하는 기본 브랜치의 코드와 테스트 스크립트가 있다는 전제입니다.
변경 전
yaml
name: Pull Request Workflow
on:
pull_request_target:
types:
- opened
jobs:
process_pull_request:
runs-on: ubuntu-latest
steps:
- name: Echo Pull Request Body
run: |
echo "Pull Request Body: ${{ github.event.pull_request.body }}"
PR 본문이 실행할 셸 코드에 포함됩니다. 공격자가 제어하는 본문을 단순히 큰따옴표 안에 넣어도 코드 주입 위험은 남습니다.
변경 후
yaml
name: check-go-coverage
on:
pull_request_target:
branches: [master]
jobs:
coverage:
name: Check Go coverage
runs-on: ubuntu-latest
steps:
- name: Checkout Source
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Go 1.22.x
uses: actions/setup-go@v5
with:
go-version: 1.22.x
- name: Run test metrics script
id: testcov
run: |
make test-coverage-report | tee test-results
echo "coverage=$(cat test-results | grep "Total coverage: " test-results | cut -d ":" -f 2 | bc)" >> $GITHUB_ENV
이 명령에는 PR 본문을 직접 삽입하지 않습니다. 이후 외부 값을 추가한다면 데이터로 전달하고, 권한이 높은 실행에서 신뢰하지 않는 코드를 실행하지 않는 원칙을 유지하세요.