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