fix(ci): PR 제목의 '따옴표'가 셸에 삽입되던 Discord 알림 워크플로 - #191
Merged
Conversation
직전 PR(#190) 제목에 작은따옴표(`'잠시 중단'`)가 들어가자 notify 잡이 실패했다: curl: (3) bad range specification in URL position 253 `${{ github.event.pull_request.title }}` 를 작은따옴표로 감싼 셸 문자열 안에 그대로 끼워 넣고 있었다. `${{ }}` 는 셸 실행 **전에** 치환되므로, 제목에 따옴표가 있으면 그 자리에서 문자열이 끝나고 나머지가 셸 토큰으로 해석된다. 깨지는 것만이 문제가 아니다. 같은 이유로 **러너에서 임의 명령을 실행할 수 있다** (GitHub Actions script injection). 이 잡에는 `DISCORD_WEBHOOK` 시크릿이 env 로 들어온다. fork PR 에는 시크릿이 전달되지 않지만, 같은 저장소 브랜치에서는 전달된다. - 사용자 제어 값(제목·브랜치·actor)을 전부 `env:` 로만 넘긴다 — 러너가 직접 주입하므로 셸이 그 내용을 파싱하지 않는다 - JSON 은 `jq --arg` 가 만든다 — 따옴표·개행·백슬래시가 알아서 이스케이프된다 - Discord embed title 상한(256자)에 맞춰 자른다 - `curl -f` 추가. 지금까지는 Discord 가 400 을 돌려줘도 잡이 성공으로 끝나 잘못된 페이로드를 알 수 없었다
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
어떻게 발견했나
직전 PR(#190) 제목에 작은따옴표가 들어 있었다 —
면접 '잠시 중단' — 이어하기를…. notify 잡이 실패했다:코드 잡 4개는 전부 통과했는데 알림만 죽었다.
원인
${{ }}는 셸 실행 전에 치환된다. 제목에'가 있으면 그 자리에서 작은따옴표 문자열이 끝나고, 나머지 JSON 조각이 셸 토큰으로 쪼개져 curl 의 인자가 된다. curl 은 그중 하나를 URL 로 보고[...]범위 문법을 파싱하려다 실패했다.깨지는 것보다 큰 문제
같은 이유로 러너에서 임의 명령을 실행할 수 있다 — GitHub Actions script injection 의 교과서적 형태다. 제목을 이렇게 지으면 된다:
이 잡에는
DISCORD_WEBHOOK시크릿이 env 로 들어온다. fork PR 에는 시크릿이 전달되지 않지만(pull_request이벤트), 같은 저장소 브랜치에서는 전달된다.수정
env:로만 넘긴다. env 는 러너가 프로세스에 직접 주입하므로 셸이 그 내용을 코드로 파싱하지 않는다jq --arg가 만든다 — 따옴표·개행·백슬래시가 알아서 이스케이프된다curl -f추가. 지금까지는 Discord 가 400 을 돌려줘도 잡이 성공으로 끝나, 잘못된 페이로드를 아무도 몰랐다이 PR 자체가 검증이다
pull_request이벤트의 워크플로는 PR 브랜치 버전으로 실행된다. 이 PR 제목에 일부러 작은따옴표를 넣었다 — notify 잡이 통과하면 수정이 동작한 것이고, 실패하면 아직 덜 된 것이다.영향 범위