AI가 고친 코드를 AI가 뚫었습니다 — 코파일럿 오토픽스·위즈·스노우플레이크 3자 공방

AI가 고친 코드를 AI가 뚫었습니다 — 코파일럿 오토픽스·위즈·스노우플레이크 3자 공방

매끄럽게 다듬어진 청록빛 표면을 가로지르는 가느다란 실금과 그 틈에서 새어 나오는 빛 — 잘 관리된 코드에 생긴 미세한 결함을 표현한 개념 이미지

AI가 코드를 고쳤습니다. 그 코드에 구멍이 생겼습니다. 다른 회사의 AI가 그 구멍을 찾아 뚫었습니다. 그리고 사람들은 누가 그 구멍을 만들었는지를 두고 다투기 시작했습니다. 2026년 8월 17일과 18일 사이에 벌어진 일입니다.

AI가 고치고, AI가 뚫고, 사람이 다퉜습니다

보안 회사 위즈(Wiz)가 자사 AI 에이전트로 스노우플레이크(Snowflake)의 공개 저장소에서 취약점을 찾아 실제로 악용했다고 발표했습니다. 그 취약점이 들어간 커밋에는 깃허브 코파일럿 오토픽스(Copilot Autofix)가 공동 저자로 적혀 있었습니다.

발표가 나오자 깃허브가 곧바로 반박했습니다. 자체 조사 결과 그 코드는 사람이 썼고, 코파일럿은 문제의 줄을 쓰지도 검토하지도 않았다는 것입니다. 같은 날 저녁 위즈도 자사 글의 표현을 수정했습니다.

이 사건이 흥미로운 이유는 기술적 결함 자체보다 그 결함을 둘러싼 책임 소재에 있습니다. AI가 코드에 관여하는 시대에, 누가 썼는가를 무엇으로 증명하는가라는 질문이 처음으로 실무 현장에서 터졌습니다.

무슨 일이 있었나 — 세 줄 요약

첫째, 2026년 6월 18일 스노우플레이크 저장소에 병합된 변경이 깃허브 액션 워크플로에 스크립트 인젝션 취약점을 만들었습니다.

둘째, 인증 없는 외부인이 깃허브 이슈 제목만 특수하게 작성해도 임의 명령을 실행할 수 있었고, 위즈는 이를 이용해 내부 지라(Jira)에 접근할 수 있는 토큰을 빼냈습니다.

셋째, 위즈는 6월 23일 이를 발견해 스노우플레이크에 보고했습니다. 병합에서 악용까지 5일이 걸렸습니다.

어두운 공간에 위아래로 나란히 놓인 여러 줄기의 청록빛 흐름 — 코드 병합에서 악용까지 차례로 이어진 사건의 순서를 표현한 개념 이미지

6월 18일, PR 1218이 병합됩니다

문제의 변경은 풀 리퀘스트(PR) 1218번이 병합되면서 메인 브랜치에 올라갔습니다. 대상 파일은 지라 이슈를 자동 생성하는 워크플로 설정이었습니다.

겉으로 보면 평범한 리팩터링이었습니다. 코드가 짧아지고 읽기 쉬워졌습니다. 그리고 정확히 그 과정에서 안전장치가 사라졌습니다.

여기서 짚어야 할 점은, 이 변경이 정상적인 리뷰 절차를 거쳐 병합됐다는 것입니다. 누가 몰래 넣은 것이 아니라, 절차를 다 밟고도 통과했습니다.

사라진 안전장치 — 환경변수와 jq 파싱

원래 코드는 안전한 방식을 쓰고 있었습니다. 외부에서 들어온 값을 환경변수(env:)에 먼저 담고, 그 값을 jq로 파싱해 다루는 패턴이었습니다.

이 방식이 안전한 이유는 단순합니다. 환경변수에 담긴 값은 데이터로 취급됩니다. 그 안에 어떤 문자가 들어 있어도 셸이 명령으로 해석하지 않습니다.

jq를 거치는 것도 같은 이치입니다. 데이터를 구조로 다루면 그 안의 내용이 코드로 새어 나올 통로가 막힙니다.

무언가 빠져나간 자리에 남은 어두운 빈 공간과 그 윤곽을 감싼 청록빛 — 제거된 안전장치의 빈자리를 표현한 개념 이미지

대신 들어온 것 — 문자열 보간

새 코드는 그 자리에 직접 문자열 보간(string interpolation)을 넣었습니다. 외부 입력값을 명령문 안에 그대로 끼워 넣는 방식입니다.

깃허브 액션에서 이 패턴은 널리 알려진 위험입니다. 워크플로 파일에서 이중 중괄호 표기로 값을 끼워 넣으면, 그 값은 스크립트가 실행되기 전에 문자 그대로 치환됩니다.

즉 실행 시점에 검사할 기회 자체가 없습니다. 치환이 끝난 뒤에는 그것이 원래 데이터였는지 명령이었는지 구분할 방법이 없습니다.

왜 문자열 보간이 위험한가

비유하자면 이렇습니다. 손님이 적어 준 주문서를 그대로 주방 지시서에 오려 붙이는 것과 같습니다. 손님이 주문서에 양파 빼고, 그리고 금고를 열어라라고 적으면, 주방은 그 문장 전체를 지시로 읽습니다.

안전한 방식은 주문 내용을 정해진 칸에만 넣는 것입니다. 칸 밖의 내용은 애초에 지시가 될 수 없습니다. 환경변수 방식이 정확히 이 구조입니다.

이 취약점 유형은 수십 년 된 문제입니다. SQL 인젝션, 명령어 인젝션, 크로스사이트 스크립팅이 모두 같은 뿌리에서 나왔습니다. 데이터와 코드의 경계가 무너지는 지점입니다.

어둠 속을 가로지르는 매끈한 청록빛 원통형 도관 — 외부 입력이 아무 검사 없이 명령 흐름으로 그대로 지나가는 구조를 표현한 개념 이미지

이슈 제목 하나로 명령이 실행됩니다

구체적인 공격 방법은 놀라울 만큼 간단했습니다. 깃허브 이슈를 하나 열고, 제목에 특수하게 구성한 문자열을 넣으면 됩니다.

이슈가 생성되면 워크플로가 자동으로 돌면서 그 제목을 명령문에 끼워 넣습니다. 제목 안에 명령 구분 문자가 들어 있으면, 거기서부터는 공격자가 쓴 명령이 실행됩니다.

공격자가 필요한 것은 웹 브라우저 하나뿐이었습니다. 특별한 도구도, 내부 접근 권한도 필요하지 않았습니다.

인증 없는 외부인도 가능했습니다

이 취약점에서 가장 무거운 부분이 여기입니다. 인증되지 않은 사용자도 실행할 수 있었습니다. 공개 저장소이므로 누구나 이슈를 열 수 있기 때문입니다.

깃허브 액션의 실행기(runner)는 저장소의 비밀값에 접근할 수 있는 환경입니다. 배포 키, API 토큰, 내부 시스템 접속 정보가 그 안에 있습니다.

정리하면, 외부인이 이슈 하나로 내부 신뢰 영역에서 명령을 실행할 수 있는 상태였습니다. 보안에서 가장 피해야 할 조합입니다.

아무 방비 없는 경계를 넘어 밝은 청록빛 영역으로 쏟아져 들어가는 어두운 흐름 — 인증 없는 외부 접근이 내부 영역에 도달하는 상황을 표현한 개념 이미지

위즈의 레드에이전트가 6월 23일에 찾아냅니다

위즈는 레드 에이전트(Red Agent)라 부르는 AI 공격 에이전트를 운영합니다. 사람 대신 저장소를 훑고, 의심스러운 지점을 찾고, 실제로 악용까지 시도하는 도구입니다.

이 에이전트가 6월 23일 해당 취약점을 발견하고, 익스플로잇을 만들고, 실행에 성공한 뒤 스노우플레이크에 보고했습니다. 발견에서 검증까지 사람 손을 거의 타지 않았습니다.

여기서 짚어야 할 것은 비대칭입니다. 공격 측이 AI로 자동화하면 훑을 수 있는 저장소의 수가 폭발적으로 늘어납니다. 방어 측이 사람 속도로 남아 있으면 격차는 계속 벌어집니다.

무엇이 새어 나갔나 — 내부 지라와 토큰

위즈는 이 취약점으로 비밀 토큰을 빼내는 데 성공했다고 밝혔습니다. 그 토큰은 스노우플레이크의 내부 지라에 인증된 계정으로 접근할 수 있는 것이었습니다.

지라는 회사의 일감 관리 시스템입니다. 어떤 버그가 있는지, 무엇을 고치는 중인지, 어떤 보안 문제를 아직 처리하지 못했는지가 모두 그 안에 있습니다.

즉 유출된 것은 정보 자체가 아니라 정보로 가는 열쇠였습니다. 공격자 입장에서는 아직 고쳐지지 않은 취약점 목록을 통째로 볼 수 있는 위치입니다.

굳게 닫힌 어두운 방의 좁은 이음새 틈으로 가느다란 청록빛이 새어 나오는 모습 — 내부 시스템 접근 토큰이 유출된 상황을 표현한 개념 이미지

5일 — 병합에서 악용까지 걸린 시간

6월 18일 병합, 6월 23일 악용. 닷새입니다.

이 숫자가 중요한 이유는 대응 창(window)의 크기를 알려주기 때문입니다. 취약점이 들어간 뒤 정기 보안 점검이 돌 때까지 기다리는 조직이라면, 그 주기가 주 단위나 월 단위인 경우가 많습니다.

AI 에이전트가 상시로 훑는 시대에 월 1회 점검은 사실상 방어가 아닙니다. 병합 시점에 막지 못하면 늦습니다.

코파일럿 오토픽스는 왜 못 잡았나

코파일럿 오토픽스는 코드 스캐닝이 찾은 취약점에 수정안을 제시하는 기능입니다. 이번 PR에도 관여한 기록이 남아 있고, 위즈에 따르면 문제없음으로 판단했습니다.

왜 놓쳤을까요. 정확한 내부 동작은 공개되지 않았지만, 이런 유형의 도구가 약한 지점은 대체로 맥락입니다. 문자열 보간 자체는 워크플로에서 매우 흔한 패턴이고, 어떤 값이 외부에서 오는지를 알아야만 위험 여부를 판단할 수 있습니다.

즉 이 취약점은 한 줄만 봐서는 보이지 않습니다. 이슈 제목이 외부 입력이라는 것, 그 워크플로가 이슈 이벤트로 실행된다는 것, 실행기에 비밀값이 있다는 것을 동시에 알아야 합니다.

촘촘한 청록빛 그물망을 아무 저항 없이 통과해 버리는 아주 작은 입자 하나 — 자동 검사를 빠져나간 취약점을 표현한 개념 이미지

깃허브의 반박 — 사람이 썼습니다

위즈의 글이 퍼지자 깃허브가 자체 조사를 거쳐 반박했습니다. 요지는 두 가지입니다.

첫째, 취약점으로 이어진 코드는 사람이 작성했다는 것입니다. 깃허브는 문제의 안전하지 않은 리팩터링이 2025년 8월 25일자 별도 커밋에 있고, 그 커밋은 스노우플레이크 소속 엔지니어의 것이라고 밝혔습니다.

둘째, 코파일럿이 공동 저자로 적힌 커밋은 다른 파일을 바꿨다는 것입니다. 즉 코파일럿이 관여한 변경과 취약점이 들어간 변경은 서로 다른 커밋이라는 주장입니다.

커밋의 공동저자 줄이 뜻하는 것

이 논쟁의 핵심에 Co-authored-by라는 한 줄이 있습니다. 깃 커밋 메시지 끝에 붙는 표기로, 여러 사람이 함께 작업했음을 나타냅니다.

문제는 이 표기가 어떤 줄을 누가 썼는지를 알려주지 않는다는 것입니다. 커밋 단위로만 붙기 때문에, 그 커밋에 100줄이 바뀌었다면 공동 저자가 그중 어느 줄에 관여했는지는 기록되지 않습니다.

더 근본적인 문제는 코파일럿이 이 줄을 참여 표시로 붙인다는 점입니다. 실제로 코드를 생성한 경우와 리뷰만 한 경우가 기록상 구분되지 않습니다. 깃허브가 참여를 기록한 것이지 저작을 기록한 것이 아니라고 설명한 이유입니다.

거의 완벽하게 포개져 하나처럼 보이지만 미세하게 어긋난 두 개의 청록빛 궤적 — 참여와 저작이 기록상 구분되지 않는 상태를 표현한 개념 이미지

위즈가 같은 날 저녁 문장을 고칩니다

깃허브의 반박이 나온 같은 날 저녁, 위즈는 자사 글의 표현을 완화했습니다.

수정된 설명은 이렇습니다. 코파일럿은 병합된 PR을 검토하고 문제없다고 판단한 공동 저자였다는 것, 그리고 해당 코드 변경이 AI의 도움을 받았는지는 불분명하다는 문장을 덧붙였습니다.

이 수정은 두 가지를 보여줍니다. 하나는 위즈의 원래 주장에 확실하지 않은 부분이 있었다는 것이고, 다른 하나는 수정 후에도 검토를 통과시킨 책임은 남는다는 것입니다.

누가 맞나 — 기록으로 확인되는 것과 안 되는 것

공개된 정보로 확인되는 사실을 먼저 정리하면 이렇습니다. 취약한 코드가 실제로 존재했고, 실제로 악용됐고, 커밋에 코파일럿이 공동 저자로 적혀 있었고, 코파일럿이 그 PR을 문제없다고 판단했습니다.

확인되지 않는 것은 하나입니다. 그 위험한 줄을 실제로 누가 타이핑했는가. 깃 이력은 커밋 저자를 기록하지만, AI 보조 도구가 제안한 것을 사람이 수락한 경우 그 구분이 남지 않습니다.

그래서 이 논쟁은 기록의 한계 때문에 끝나지 않습니다. 양쪽 모두 자신의 주장을 뒷받침할 근거를 갖고 있고, 결정적 증거는 애초에 남지 않는 구조입니다.

한 지점에서 출발해 좁은 각도로 갈라지며 서로 멀어지는 두 줄기 청록빛 직선 — 양측 주장이 같은 기록에서 출발해 다른 결론에 이른 상태를 표현한 개념 이미지

진짜 문제는 저자가 아니라 검토였습니다

여기까지 오면 질문이 잘못 설정됐다는 것이 보입니다. 누가 썼는지는 흥미로운 논쟁거리지만, 실무에서 바꿀 수 있는 것은 아닙니다.

바꿀 수 있는 것은 검토입니다. 이 취약점은 사람 리뷰를 통과했고, 코드 스캐닝을 통과했고, 코파일럿 오토픽스의 판단도 통과했습니다. 세 겹의 검토가 모두 같은 것을 놓쳤습니다.

세 검토가 같은 맹점을 공유했다는 사실이 핵심입니다. 층을 여러 겹 쌓아도 모두 같은 방식으로 보고 있다면 한 겹과 다르지 않습니다.

깃허브 액션이라는 특수한 실행 환경

이 사건이 깃허브 액션에서 벌어진 것은 우연이 아닙니다. CI/CD 파이프라인은 보안 관점에서 유난히 까다로운 자리에 있습니다.

첫째, 외부 입력이 자연스럽게 들어옵니다. 이슈 제목, PR 설명, 브랜치 이름, 커밋 메시지가 모두 워크플로의 입력이 될 수 있고, 이 중 상당수는 아무나 쓸 수 있습니다.

둘째, 실행 권한이 높습니다. 배포를 해야 하므로 비밀값을 쥐고 있습니다.

셋째, 검토가 느슨합니다. 워크플로 파일은 제품 코드가 아니라는 인식 때문에 리뷰가 가볍게 지나가는 경우가 많습니다. 가장 위험한 곳이 가장 덜 검토됩니다.

고립된 어둠 속에서 끝없이 같은 궤도를 도는 폐쇄된 청록빛 원환 — 자동으로 반복 실행되는 파이프라인 환경을 표현한 개념 이미지

실제 사례: 이슈 제목에 백틱을 넣는 공격

구체적으로 어떻게 동작하는지 봅시다. 워크플로가 이슈 제목을 셸 명령 안에 그대로 끼워 넣는다고 가정합니다.

공격자가 이슈 제목을 버그 리포트로 쓰면 아무 일도 없습니다. 그런데 제목에 백틱이나 명령 치환 문법을 넣으면, 셸은 그 부분을 실행할 명령으로 읽습니다.

제목 하나로 실행기 안의 환경변수를 전부 읽어 외부로 보내는 것이 가능해집니다. 그 환경변수 안에 토큰이 들어 있습니다.

방어는 간단합니다. 값을 환경변수에 담고 따옴표로 감싸 참조하면 됩니다. 원래 코드가 하던 방식이고, 리팩터링이 없앤 방식입니다.

실제 사례: 시크릿이 로그로 새는 경로

토큰이 새는 경로는 직접 전송만이 아닙니다. 로그를 통한 유출이 더 흔합니다.

깃허브 액션은 알려진 비밀값을 로그에서 자동으로 가려 줍니다. 하지만 이 보호는 값이 그대로 출력될 때만 작동합니다. 공격자가 값을 한 글자씩 쪼개거나 인코딩해서 출력하면 가림막이 걸리지 않습니다.

공개 저장소라면 그 로그를 누구나 볼 수 있습니다. 외부로 데이터를 보낼 필요조차 없습니다.

아주 작은 틈에서 어둠 속으로 하나씩 떨어지는 청록빛 물방울들 — 비밀값이 로그를 통해 조금씩 새어 나가는 경로를 표현한 개념 이미지

오늘 우리 저장소에서 확인할 것 4가지

첫째, 워크플로에서 외부 입력이 명령문에 직접 끼워 넣어지는 곳을 찾습니다. 이슈 제목, PR 제목과 본문, 브랜치 이름, 커밋 메시지가 대상입니다. 발견하면 환경변수 경유로 바꿉니다.

둘째, 어떤 이벤트로 워크플로가 실행되는지 확인합니다. 외부인이 촉발할 수 있는 이벤트로 도는 워크플로에는 비밀값 접근 권한을 주지 않는 것이 원칙입니다.

셋째, 토큰 권한을 최소로 줄입니다. 기본 권한을 읽기 전용으로 두고, 필요한 작업에만 개별적으로 열어 줍니다.

넷째, 워크플로 파일을 제품 코드와 같은 등급으로 리뷰합니다. 설정 파일이라는 이유로 가볍게 넘기는 관행이 이번 사건의 배경입니다.

AI 코드 리뷰를 믿는 만큼 두어야 할 안전장치

AI 코드 리뷰 도구는 쓸모가 있습니다. 문제는 그 판단을 어떻게 취급하는가입니다.

문제없음이라는 판정을 안전하다는 증명으로 읽으면 안 됩니다. 도구가 아는 패턴에서 걸리지 않았다는 뜻일 뿐입니다.

실무에서 지킬 만한 원칙은 세 가지입니다. 승인은 사람이 한다, 서로 다른 방식으로 보는 검사를 겹친다, 가장 위험한 영역은 자동 판정에 맡기지 않는다.

이번 사건은 이 원칙들이 모두 지켜지지 않았을 때 무슨 일이 생기는지를 보여줍니다.

앞뒤로 여러 겹 포개진 반투명한 청록빛 방어막과 그 사이를 채운 빛 — 서로 다른 방식의 검사를 겹쳐 쌓은 방어 구조를 표현한 개념 이미지

저시력 개발자에게 특히 위험한 지점

이 취약점 유형은 코드를 눈으로 훑어서 잡아내는 종류입니다. 안전한 참조와 위험한 참조의 차이가 따옴표 몇 개, 중괄호 위치 수준으로 미세합니다.

화면을 확대해서 보는 개발자에게 이런 검토는 구조적으로 불리합니다. 한 화면에 들어오는 코드가 적으면 여러 곳을 동시에 대조해야 하는 판단이 훨씬 어려워집니다.

이것은 개인의 능력 문제가 아니라 검토 방식의 문제입니다. 해법은 눈에 의존하지 않는 검사를 갖추는 것입니다. 린터와 정적 분석을 CI에 넣어 기계가 판정하게 하면, 화면 크기와 무관하게 같은 품질이 나옵니다.

이 사건이 남긴 질문

AI가 코드에 관여하는 비율이 계속 올라가면, 누가 썼는가라는 질문은 점점 답하기 어려워집니다. 지금의 깃 이력은 이 질문에 답하도록 설계되지 않았습니다.

그렇다면 선택지는 두 갈래입니다. 기록을 더 정밀하게 남기거나, 저자를 묻는 것을 그만두거나입니다.

전자는 비용이 큽니다. 후자는 책임 소재를 사람에게 고정하는 방식입니다. 도구가 무엇을 제안했든 병합 버튼을 누른 사람이 책임진다는 원칙이고, 현재로서는 이쪽이 더 현실적으로 보입니다.

광활한 어둠 속에 홀로 떠서 계속 회전하는 청록빛 소용돌이 — 아직 답이 정해지지 않은 책임 소재 문제를 표현한 개념 이미지

핵심 정리

무슨 일인가. 스노우플레이크 공개 저장소의 깃허브 액션 워크플로에 스크립트 인젝션 취약점이 있었고, 위즈의 AI 에이전트가 이를 악용해 내부 지라 접근 토큰을 빼냈습니다.

기술적 원인. 안전한 환경변수 + jq 파싱 패턴이 직접 문자열 보간으로 바뀌면서, 이슈 제목만으로 임의 명령 실행이 가능해졌습니다.

논쟁. 커밋에 코파일럿 오토픽스가 공동 저자로 적혀 있었지만, 깃허브는 사람이 쓴 코드라고 반박했고 위즈도 같은 날 표현을 완화했습니다.

확인되는 것과 아닌 것. 취약점 존재·악용·코파일럿의 문제없음 판정은 확인됩니다. 누가 그 줄을 썼는지는 기록으로 확정되지 않습니다.

실무 교훈. 사람 리뷰·코드 스캐닝·AI 판정이 모두 같은 맹점을 공유했습니다. 서로 다른 방식으로 보는 검사를 겹쳐야 합니다.

참고하실 만한 것

지금 운영 중인 저장소가 있다면, 오늘 할 수 있는 가장 값싼 점검은 워크플로 파일에서 외부 입력이 직접 끼워 넣어진 곳을 찾는 것입니다. 검색 한 번이면 목록이 나오고, 대부분은 환경변수 경유로 바꾸는 몇 줄 수정으로 끝납니다.

SVIL 연구소는 AI 개발 도구를 실제 작업 흐름에 넣었을 때 생기는 문제들을 계속 기록하고 있습니다. 특히 도구의 판정을 사람이 어떻게 취급해야 하는지는 앞으로 더 자주 부딪힐 주제입니다.

출처


협업문의 : kuroicode@gmail.com
블로그 : https://blog.svil.dev/
홈페이지 : https://kuroicode-beep.github.io/svil-homepage/