어두운 슬레이트 바탕 위에 생성된 추상 일러스트: 가늘고 옅은 시안색과 앰버색 빛줄기로 이루어진 긴 가로 리본이 양쪽 가장자리까지 이어지다가 중앙 근처의 한 정확한 지점에서 끊어지고, 밝은 앰버색 파편 하나가 위쪽의 빈 어두운 채널로 솟아오릅니다. 희미한 동심원과 격자선이 파이프라인을 암시합니다. 텍스트, 사람, 조직 로고는 나타나지 않습니다. OrcaRouter 로고가 오른쪽 아래 모서리에 합성되어 있습니다.
AI Safety Incidents

Snowflake의 Jira 토큰: Copilot이 함께 서명한 결함, 그리고 GitHub가 작성했다고 밝힌 사람

작성자

Gideon Frost

게시일

최신 모델 · 20모든 모델 보기 →
벤치마크: Artificial Analysis · 매일 업데이트
모든 게시물로 돌아가기

2026년 6월 23일, Wiz가 구축한 자율 보안 에이전트 Red Agent는 Snowflake가 소유한 공개 GitHub 저장소에 이슈를 열고 자격 증명을 확보해 돌아왔다. 해당 저장소는 snowflakedb/snowflake-connector-net이었으며, 문제가 된 워크플로 .github/workflows/jira_issue.yml은 누군가 이슈를 열 때마다 Jira 티켓을 생성하기 위해 존재한다. 이 워크플로는 티켓 제목을 환경 변수로 전달하는 대신 셸 명령에 직접 삽입했기 때문에, 조작된 제목이 GitHub Actions 러너에서 코드로 실행되었다. Red Agent가 확보한 토큰은 snowflakecomputing.atlassian.net에 대해 qa@snowflake.net으로 인증되었고, Snowflake의 엔지니어링, 보안 규정 준수 및 버그 바운티 Jira 프로젝트에 대한 읽기 권한을 갖고 있었다. 이 취약점은 5일 동안 노출되어 있었다. Wiz는 2026년 8월 17일 전체 분석을 공개했다. 이 사건은 Orca AI Incident Archive에 기록 2026-08-17-snowflake-jira-zhao-dao-can으로 등록되어 있으며, 이 아카이브는 신뢰도 등급과 인용 출처와 함께 전체 기록 세트를 보관한다.

보간, 그리고 한 번도 실행되지 않은 가드

워크플로는 GitHub 이벤트 "issues: opened"에서 트리거되었습니다. GitHub 계정이 있는 사람이라면 누구나 공개 리포지토리에 이슈를 열어 이를 실행할 수 있었습니다 — 초대도, 유지 관리자 역할도, 포크도 필요 없었습니다. 취약한 단계는 이슈 제목을 셸 변수로 읽어들였습니다: TITLE=$(echo '${{ github.event.issue.title }}' | sed ...), 문자열이 조립되기 전에 큰따옴표와 작은따옴표를 이스케이프하기 위한 두 개의 필터가 있었습니다.

실패는 이스케이프가 아니라 연산 순서에 있습니다. GitHub는 bash가 스크립트를 파싱하기도 전에 표현식의 내용을 스크립트 텍스트에 치환하므로, 이슈 제목 안의 작은따옴표 하나가 echo가 열어 둔 인용 문자열을 닫아 버립니다. 두 개의 sed 필터는 같은 스크립트 안에서, 즉 치환 이후에 실행되며, 이미 해당 줄의 파싱 방식이 바뀐 인용을 복구할 수 없습니다. Wiz의 분석글은 이스케이프가 탈출을 막기에는 너무 늦게 적용되며, 닫는 따옴표와 세미콜론으로 조작된 제목이 공격자가 원하는 명령을 실행 단계에 덧붙인다고 명시하고 있습니다.

두 번째 제어 장치는 대상 범위를 좁히도록 되어 있었지만 그러지 못했다. 해당 작업에는 github.event.pull_request.user.login을 whitesource-for-github-com 봇의 로그인과 비교하는 if 조건이 있었는데, 이는 분명 자동화된 의존성 풀 리퀘스트가 티켓을 생성하는 것을 막기 위한 것이었다. issues 이벤트에는 풀 리퀘스트 객체가 전혀 없으므로, 비교 대상은 null 속성이다. The Hacker News가 인용한 GitHub 자체 문서에 따르면 존재하지 않는 속성을 역참조하면 빈 문자열로 평가된다. Wiz의 분석도 null 값을 통해 같은 결과에 도달한다. 어느 쪽이든 그 조건은 모든 사용자에 대해 true로 평가되었고, 봇을 위한 예외는 인터넷 전체가 통과할 수 있는 통로가 되었다.

이 인젝션이 일상적인 문제가 아니라 보고할 가치가 있었던 것은 그 인젝션과 함께 있었던 대상들 때문입니다. 같은 단계에는 JIRA_BASE_URL, JIRA_USER_EMAIL, JIRA_API_TOKEN이 환경 변수로 설정되어 있어, 러너에서 임의 명령을 실행할 수 있었다면 빈 기반이 아니라 손 닿는 곳에 자격 증명이 있었던 셈입니다. 영향을 받은 Snowflake Connector for .NET 릴리스는 확인되지 않았습니다. 이 약점은 출시된 커넥터 코드가 아니라 저장소의 CI/CD 자동화에 존재했습니다.

Red Agent가 가져간 것, 그리고 그것이 버렸다고 말하는 것

Wiz의 악용 경위 설명은 이것이 단순한 스캐너 발견과 구분되는 부분입니다. 첫 번째 페이로드는 해시 문자를 사용해 TITLE=$(...) 할당의 닫는 괄호를 주석 처리했고, 콜백 대신 bash 구문 오류를 발생시켰습니다. 에이전트는 오류를 읽고 페이로드를 다시 작성해 세미콜론과 새 echo 인용으로 셸 블록을 닫았으며, 그런 다음 대역 외 호출을 수신했습니다. 페이로드는 curl을 사용해 세 가지 자격 증명 변수의 base64 인코딩 값으로 oast.me의 하위 도메인에 접근했고, 콜백은 Azure IP 20.106.182.197에서 도착했으며, Wiz는 이 주소를 GitHub Actions 러너에 귀속시킵니다.

반환된 토큰은 qa@snowflake.net용 Jira API 토큰이었으며, Wiz는 그 영향 범위를 Snowflake의 Atlassian 클라우드 인스턴스에서 엔지니어링, 보안 규정 준수, 버그 바운티 추적 프로젝트 전반에 걸친 읽기 접근이라고 설명합니다. 이것이 아카이브에 기록된 피해입니다. 빌드 머신에서 5일간 코드를 실행할 수 있었다는 것이 아니라, 수정되지 않은 엔지니어링 및 보안 버그가 접수되는 티켓 큐를 읽을 수 있었던 자격 증명이라는 점입니다 — Wiz의 설명에 따르면 버그 바운티 추적기까지 포함해서요.

A self-built HTML card titled 'What the run step could reach', badged 'snowflakedb/snowflake-connector-net · .github/workflows/jira_issue.yml · 18-23 June 2026'. A left panel lists the environment variables held by the step: JIRA_BASE_URL, JIRA_USER_EMAIL, JIRA_API_TOKEN. A right panel reads: identity qa@snowflake.net; Jira host snowflakecomputing.atlassian.net; access, read across engineering, security-compliance and bug-bounty Jira projects. Three tiles read: trigger 'issues: opened'; account required 'any GitHub user'; token rotated '24 June 2026'. A footer cites Wiz Research, published 17 August 2026, and notes no CVE identifier accompanies the flaw.

Wiz는 개념 증명(proof of concept) 과정에서 접근했던 모든 데이터를 안전하게 삭제했다고 밝혔다. Snowflake는 CSO Online에 보낸 성명에서 해당 보고서가 "즉시 조사되고 조치되었다"며 "우리 조사에서는 무단 접근의 증거를 발견하지 못했다"고 말했다. Wiz의 블로그는 Snowflake가 5일간의 기간에 대한 감사 로그를 검토했으며 Wiz 자체의 테스트 주소 외에는 제3자 사용을 발견하지 못했다고 덧붙였다. Snowflake는 해당 로그를 공개하지 않았기 때문에, 다른 행위자가 없다는 결론은 두 조직 외부의 누구나 읽을 수 있는 문서가 아니라 Snowflake의 설명과 이에 대한 Wiz의 요약에 근거한다.

취약한 줄은 누가 작성했나요?

그 질문은 두 번째, 더 큰 이야기를 만들어냈습니다. "SNOW-2069227: Update jira workflows"라는 제목의 PR #1218은 2026년 6월 18일 커밋 4a1b8ce로 스쿼시 병합되었으며, 해당 스쿼시 커밋은 공동 작성자 중 하나로 Copilot Autofix powered by AI를 기재합니다. Wiz의 원래 헤드라인은 바로 그 점에 기댔고, 이 취약점이 GitHub Copilot이 지원한 풀 리퀘스트에 있다고 설명했으며, 초기 업계 보도도 같은 논조를 따랐습니다 — SC Media의 헤드라인은 "Wiz 에이전트, GitHub Copilot Autofix가 공동 작성한 코드에서 Snowflake 저장소 취약점 발견"이었습니다.

The Next Web이 보도하고 Cloud Security Alliance 리서치 노트에 요약한 바에 따르면, GitHub의 입장은 내부 검토에서 "취약점을 초래한 기여를 작성한 것은 사람이었다"고 밝혔으며 Copilot Autofix는 "이를 검토하지도 기여하지도 않았다"는 것입니다. 그 반박의 기술적 근거는 git 기록에 있습니다. 스쿼시 병합은 풀 리퀘스트를 단일 커밋으로 합치고 해당 작성자가 어떤 줄을 건드렸든 모든 공동 작성자 트레일러를 그대로 이어 붙이므로, 공동 작성자 줄은 특정 헝크의 저자임이 아니라 해당 풀 리퀘스트에 참여했음을 기록합니다. 같은 풀 리퀘스트에서 Copilot의 공동 작성 커밋 6d0e2fa는 취약한 jira_issue.yml과 다른 워크플로인 jira_close.yml을 변경했습니다. 안전하지 않은 보간은 2025년 8월 25일자 커밋 094038e에 기인하며, GitHub는 이를 Snowflake 엔지니어 sfc-gh-hpathak의 것으로 돌렸습니다. PR #1218은 2026년 6월에 그 패턴을 기본 브랜치에 반영했습니다.

Wiz는 해당 발견을 철회하지 않았고, 게시 당일 그 프레이밍을 바꿨다. Wiz의 블로그에는 8월 17일 19:57 UTC에 게시된 업데이트가 실려 있으며, 여기서 Copilot을 “병합된 PR과 코드 변경을 점검한 공동 작성자”라고 묘사하면서 취약점을 알아채지 못한 채 “모두 이상 없음”으로 판정했다고 했고, “그 코드 변경이 AI의 지원을 받은 것인지는 불분명하다”고 인정했다. 그 설명에서 AI의 실패는 작성이 아니라 검토에 관한 것이다. 병합된 풀 리퀘스트에는 Copilot의 공동 서명이 있었고, 인젝션은 그 검토를 통과해 남아 있었다. CSO Online은 Wiz CTO Ami Luttwak의 말을 인용해, 인간과 AI 사이의 명확한 귀속을 “확립하기가 다소 더 어려워지고 있다”고 했으며, “PR의 공동 작성자만 살펴보는 것만으로는 충분하지 않다”고 전했다.

A self-built HTML card titled 'Two accounts of one commit', badged 'PR #1218 · SNOW-2069227 · squash-merged 18 June 2026 as commit 4a1b8ce'. A cyan-headed left panel, 'GitHub, internal review', reads: a human wrote the contributions that led to the vulnerability; Copilot Autofix neither reviewed nor contributed to them; Copilot's co-authored commit 6d0e2fa changed jira_close.yml, not the vulnerable file; the unsafe pattern traces to commit 094038e of 25 August 2025; squash-merging carries each co-author trailer forward regardless of which lines that author touched. An amber-headed right panel, 'Wiz, blog update, 17 August 2026, 19:57 UTC', reads: Copilot was a co-author that checked the merged PR and code change; it identified it as all-clear without noticing the vulnerabilities; it is unclear whether the code-change was AI-assisted; Copilot Autofix is listed among the squash commit's co-authors; the post was revised on the evening of publication without retracting the finding. Below, an open-question strip asks whether Copilot reviewed jira_issue.yml inside PR #1218, and a dashed band lists what is not in dispute.

두 측의 설명이 공유하는 부분은 서로 다투는 부분과 분리해서 볼 가치가 있다. 양쪽 모두 squash 커밋에 Copilot Autofix 공동 작성자 트레일러가 포함되어 있고 워크플로가 악용 가능했다는 점에 동의한다. 어느 쪽도 GitHub Advanced Security가 풀 리퀘스트의 최종 리비전을 스캔하고 jira_issue.yml을 추출했으며 인젝션을 표시하지 않았다는 점을 부인하지 않는다. Wiz는 이를 놓친 사례로 보고하고, GitHub의 반박은 스캔에 관한 것이 아니라 작성 주체에 관한 것이다. 아직 해결되지 않은 것은 Copilot이 취약한 줄을 검토했는지 여부다. Wiz는 검토가 실행되어 해당 줄을 통과시켰다고 말하고, GitHub는 해당 도구가 그 줄에 어떤 역할도 하지 않았다고 말하며, 이를 판가름할 로그는 두 회사 중 한 곳이 갖고 있다. 기록은 어느 쪽을 선택하기보다 두 설명을 모두 담고 있다.

5일, 그리고 그 후에 달라진 것

신고가 접수되자 수정은 신속하게 이루어졌다. Wiz는 6월 23일 Snowflake의 HackerOne 프로그램을 통해 #3819931 보고서로 제출했고, 같은 날 Slack을 통해 Snowflake 보안팀에 알렸다. Snowflake는 PR #1402, 커밋 1dc7766을 병합했으며, 이는 직접적인 표현식 확장을 jq에 인수로 전달되는 환경 변수로 대체했다. Wiz의 타임라인은 Jira 토큰 교체를 6월 24일로 잡고 있고, The Hacker News도 같은 날짜 구분을 보도한다. 반면 Wiz의 자체 소개 글은 Snowflake가 취약점을 완화하고 자격 증명을 "같은 날" 교체했다고 말한다. 이는 기록이 덮어서는 안 될 1차 출처 내부의 불일치다. 수정은 6월 23일에 반영되었고, Wiz의 표에서 교체는 6월 24일로 기록되어 있다.

공개 일정은 Snowflake의 기준에 따라 진행됐다. Wiz는 해당 프로그램 정책에 따른 6월 25일 해결 조치 이후 30일인 2026년 7월 25일을 공개 기한으로 정하고, 8월 17일에 분석을 발표했다. Snowflake가 CSO Online에 보낸 성명에서 회사는 "Wiz의 책임 있는 보고에 감사한다"고 밝혔으며, 업계와 교훈을 공유하기 위해 Wiz와 협력하고 있다고 말했다. Wiz의 분석과 The Hacker News의 보도 어느 쪽에도 CVE 식별자, CVSS 점수, CISA의 알려진 악용 목록 항목은 없다. 이 결함은 공개 저장소의 워크플로 구성이었지 배포된 라이브러리가 아니었기 때문에 일반적인 방식으로 취약점 데이터베이스에 들어간 적이 없다.

A self-built HTML card titled 'Five days live, five weeks to publication', subtitled 'Every date below is day-precision, as reported by Wiz Research and The Hacker News'. A vertical timeline lists six entries: 25 August 2025, commit 094038e introduces the unsafe jira_issue.yml refactor, attributed by GitHub to a Snowflake engineer; 18 June 2026, PR #1218 squash-merged as 4a1b8ce and the flaw goes live on the default branch; 23 June 2026, Wiz reports via HackerOne #3819931 and Snowflake merges fix PR #1402 as 1dc7766; 24 June 2026, Jira API token rotated, the fix having landed a day earlier; 25 July 2026, public disclosure deadline under Snowflake's HackerOne policy; 17 August 2026, Wiz publishes the full analysis, blog updated at 19:57 UTC. An amber band reads 'Exposure window: five days, 18 to 23 June 2026'. A footer notes no CVE identifier, CVSS score or known-exploited entry accompanies the record.

기록이 입증하는 것과 입증하지 못하는 것

아카이브는 이를 배포 사건이 아니라 연구 결과로 분류하며, 심각도는 높음, 신뢰도 등급은 A이고, AI 관여가 확인되었으며 실제 피해가 기록되었다. 그 날짜인 2026년 8월 17일은 Wiz가 발표한 날이며, 사건 자체는 6월 18일부터 23일까지에 걸쳐 있다. 확립된 핵심은 좁고 검증 가능하다. 즉, 공개 워크플로가 공격자가 제어하는 텍스트를 셸 명령에 보간했고, 그 가드 조건이 해당 이벤트에서 null인 속성과 비교되었으며, Jira 토큰이 같은 단계에 있었고, 자율 에이전트가 이를 악용했으며, Snowflake는 하루 안에 수정 사항을 병합하고 자격 증명을 교체했다.

기록이라기보다 추론에 해당하는 부분은 가벼운 재전달에서 흔히 뭉개지는 부분이다. Copilot Autofix는 해당 풀 리퀘스트의 공동 작성자로 문서화되어 있지만, 취약한 코드 라인의 작성자로 문서화된 것은 아니다. 첫 뉴스 사이클을 이끌었던 ‘AI 대 AI’ 구도는 보도 기관이 몇 시간 만에 부분적으로 철회했고 GitHub가 반박했다. 머지된 풀 리퀘스트의 AI 리뷰가 jira_issue.yml을 들여다봤는지는 여전히 열린 사실 문제이지, 확정된 사안이 아니다. 또한 접근 범위는 Wiz가 상세히 설명했지만 독립적으로 감사되지는 않았다. Jira 권한, 워크플로 실행 내역, 감사 기록 중 어느 것도 공개되지 않았다.

수정 패턴은 GitHub 자체 가이드가 2025년 7월부터 권장해 온 방식입니다. 신뢰할 수 없는 이슈 데이터를 환경 변수에 넘기고, run 블록 안에서 확장하는 대신 jq에 인자로 전달하는 것입니다. Snowflake의 병합된 커밋이 정확히 그렇게 했으며, 수정된 처리 방식은 기본 브랜치에 그대로 남아 있습니다. 이 기록을 선례로 읽는 사람이라면, 오래 남을 발견은 주입이 아니라 기여자 귀속에 관한 것입니다. 풀 리퀘스트에 여러 사람과 여러 에이전트가 함께할 때 공동 작성자 트레일러만으로는 누가 어떤 줄을 작성했는지 알 수 없으며, Wiz와 GitHub 모두 결국 서로 다른 표현으로 그 점을 인정했습니다.