GitHub Actions script 블록 주입

actions/github-script에 외부 값을 코드로 삽입하지 말고 JavaScript 데이터로 전달하세요.

설명

actions/github-script의 script는 JavaScript 함수 본문으로 실행됩니다. 이슈 제목 등 외부 값을 ${{ }} 표현식으로 직접 삽입하면 코드가 만들어지는 과정에서 문자열을 벗어나 다른 코드를 실행할 수 있습니다. 파일 경로에 사용할 때는 별도로 경로 범위도 제한해야 합니다.

잠재적 영향

  • 주입된 코드가 실행기의 파일을 읽거나 결과물을 변조할 수 있습니다.
  • 작업에 제공된 토큰과 권한에 따라 댓글·이슈 등 저장소 기능이 악용되거나 비밀정보가 노출될 수 있습니다.

해결 방법

  • 필요한 값은 context.payload에서 데이터로 읽거나 env로 전달한 뒤 process.env로 읽으세요. 코드 문자열에 삽입하거나 eval로 평가하지 마세요.
  • 파일 경로·API 인자는 허용된 형식과 범위를 검증하세요. 데이터로 전달했다고 해서 모든 사용 방식이 안전한 것은 아닙니다.
  • 토큰 권한과 비밀정보 접근을 필요한 범위로 제한하고 신뢰하지 않는 코드를 권한이 높은 작업에서 실행하지 마세요.

예시

댓글 작성에 필요한 권한을 명시한 예시입니다. 첫 예시의 /tmp 파일 읽기는 위험을 보여 주기 위한 것으로, 해당 파일이 준비되지 않으면 실패합니다. 액션 버전은 검토한 버전이나 커밋으로 고정하세요.

변경 전

yaml
name: test-script-run

on:
  issues:
    types: [opened]

permissions:
  contents: read
  issues: write

jobs:
  script-run:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Run script
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const body = fs.readFileSync('/tmp/${{ github.event.issue.title }}.txt', {encoding: 'utf8'});

            await github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: 'Thanks for reporting!'
            })

            return true;

이슈 제목이 JavaScript 문자열과 파일 경로에 직접 포함됩니다. 코드 주입과 경로 조작을 모두 고려해야 합니다.

변경 후

yaml
name: test-script-run

on:
  issues:
    types: [opened]

permissions:
  contents: read
  issues: write

jobs:
  script-run:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Run script
        uses: actions/github-script@v7
        with:
          script: |
            await github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: 'Thanks for reporting!'
            })

            return true;

필요하지 않은 파일 읽기를 제거하고 고정된 댓글만 작성합니다. 제목을 사용할 필요가 있다면 코드에 삽입하지 말고 데이터로 읽어 검증하세요.

참조