
GitLost: AI 에이전트가 단 하나의 GitHub Issue를 통해 코드를 유출하는 방법
요약
AI 에이전트 워크플로우의 권한 설정 오류로 인해 공개 GitHub Issue를 통해 프라이빗 리포지토리의 코드가 유출될 수 있는 'GitLost' 공격 방식을 설명합니다. 에이전트가 읽기 권한과 쓰기 권한을 동시에 가질 때 발생하는 접근 제어 문제를 경고합니다.
핵심 포인트
- 공개 Issue를 통해 프라이빗 코드를 탈취하는 GitLost 공격 메커니즘
- AI 에이전트의 과도한 권한 부여(Permission Mix)가 보안 취약점의 핵심
- 에이전트가 조직 내 여러 리포지토리에 접근할 때의 접근 제어 필요성 강조
- 단순한 텍스트 입력이 에이전트의 행동을 조종할 수 있는 위험성
GitLost: AI 에이전트가 단 하나의 GitHub Issue를 통해 코드를 유출하는 방법
공개된 GitHub issue가 사용자의 프라이빗 리포지토리 (private repositories)에서 텍스트를 추출할 수 있어서는 안 됩니다.
위험할 정도로 과도한 권한이 부여된 GitHub 에이전트 워크플로우 (Agentic Workflow)를 사용한다면, Noma Labs가 증명했듯이 정확히 그런 일이 발생할 수 있습니다.
그들의 2026년 7월 보고서는 단순하지만 악랄한 체인을 보여주었습니다: 공격자가 공개 리포지토리 (public repository)에 issue를 생성하면, AI 에이전트가 자동화된 워크플로우 (workflow)의 일부로 이를 읽고, 에이전트가 접근 가능한 다른 리포지토리들에 접근하여, 그 결과가 공개 댓글로 돌아오는 방식입니다. 탈취된 로그인 정보도, 내부자 접근도, 정교한 메모리 오염 (memory corruption)도 필요 없습니다. 그저 잘못된 텍스트를 신뢰한 워크플로우가 문제였습니다.
저는 제 장비에서 GitHub 인접 워크플로우를 대상으로 Hermes 에이전트를 실행해 보는데, 이것은 제가 모델 벤치마크 점수보다 훨씬 더 걱정하는 종류의 버그입니다. 일단 에이전트가 한 곳을 읽고, 다른 곳에 쓰고, 그 사이에 스스로 다음 단계를 결정할 수 있게 되면, 당신의 문제는 더 이상 "AI 출력 품질"이 아닙니다. 당신의 문제는 접근 제어 (access control)입니다.
제 견해는 단호합니다: 만약 에이전트가 동일한 실행 과정에서 프라이빗 코드를 읽고 공개적으로 게시할 수 있다면, 그 설계는 이미 잘못된 것입니다.
GitLost가 실제로 보여준 것
Noma Labs는 2026년 7월 6일에 GitLost를 발표했습니다. 이 공격은 GitHub의 새로운 에이전트 워크플로우 (agentic workflow) 패턴을 겨냥했습니다: GitHub Actions와 연결되어 Markdown으로 정의된 워크플로우이며, AI 에이전트가 issue를 읽고, 도구 (tools)를 호출하며, 자동으로 답변하는 방식입니다.
위험한 부분은 추상적인 의미에서의 "AI"가 아니었습니다. 그것은 권한의 혼합 (permission mix)이었습니다.
Noma의 보고서에 따르면, 취약한 패턴은 다음과 같았습니다:
- 프라이빗 리포지토리들과 동일한 GitHub 조직 (organization) 내에 있는 공개 리포지토리
issues.assigned와 같은 issue 활동에 의해 트리거되는 자동화된 워크플로우- issue의 제목과 본문을 읽는 에이전트
- 해당 에이전트가 조직 내의 다른 리포지토리들을 읽을 수 있는 권한
- 동일한 에이전트가 공개 issue에 다시 게시할 수 있는 권한
이러한 조합만으로도 충분합니다.
Noma의 개념 증명 (Proof of Concept, PoC)은 에이전트가 공개 리포지토리와 비공개 리포지토리 모두에서 README.md를 가져온 다음, 누구나 읽을 수 있는 공개 댓글 스레드에 그 내용을 다시 게시하는 과정을 보여주었습니다. 그들의 보고서에 따르면, 유출된 파일은 poc 및 testlocal이라는 이름의 리포지토리에서 가져온 것이며, 워크플로 (Workflow)는 공개 이슈 (Issue)가 할당된 후에 트리거되었습니다.
이것이 중요한 이유는 지루한 워크플로 이벤트를 신뢰 경계 실패 (Trust-boundary failure)로 바꾸기 때문입니다.
많은 사람들이 여전히 "프롬프트 인젝션 (Prompt Injection)"이라는 말을 들으면, 누군가 재미 삼아 ChatGPT에 "이전 지침을 무시해"라고 입력하는 장면을 상상합니다. 이것은 그런 것이 아닙니다. 이것은 실제 리포지토리 권한이 부여된 실시간 자동화 경로입니다.
시스템을 과도하게 신뢰하기 때문에 공격은 단순합니다
대략적인 시퀀스 (Sequence)는 다음과 같습니다:
- 공격자가 공개 리포지토리에 이슈를 생성합니다.
- 해당 이슈는 일반적인 사람의 검토를 통과할 만큼 충분히 무해해 보입니다.
- 워크플로가 에이전트를 할당하거나 트리거합니다.
- 에이전트는 입력값의 일부로 이슈 본문을 읽습니다.
- 해당 이슈에 숨겨진 지침이 에이전트로 하여금 다른 리포지토리들을 읽고 찾아낸 내용을 게시하도록 유도합니다.
Noma는 테스트 과정에서
컴퓨터 과학을 가르친다면, 교실 비유를 통해 이를 쉽게 설명할 수 있습니다. 이는 마치 학생에게 화이트보드에 메모를 쓰게 하고, 보조 교사가 그 메모를 지침서로 취급하게 한 뒤, 동일한 보조 교사가 잠겨 있는 서류 보관함을 열어 그 안의 내용물을 교실 문에 다시 붙여 놓게 하는 것과 같습니다.
여기서 취약점은 서류 보관함이 아닙니다. 절차(Procedure)가 취약점입니다.
GitHub의 정확한 설정을 사용하지 않더라도 이것이 중요한 이유
대부분의 사람들은 GitLost를 읽고 이렇게 물을 것입니다. "GitHub Agentic Workflows (에이전트 워크플로우)를 사용하지 않는다면 저도 영향을 받나요?"
이 정확한 개념 증명(Proof of Concept, PoC)에 의해서는 아닐 수도 있습니다.
하지만 더 넓은 교훈은 자체 호스팅(Self-hosted) 방식을 포함한 모든 에이전트 스택(Agent stack)에 적용됩니다.
저는 최근에 로컬 AI가 중요한 이유와 자체 호스팅 Ollama를 보호하는 방법에 대해 글을 썼습니다. 모델을 로컬에서 실행하는 것은 개인정보 보호에 도움이 됩니다. 프롬프트와 코드가 클라우드 제공업체로 자동으로 유출되는 것을 막아주기 때문입니다.
하지만 이것이 이 문제를 해결하지는 못합니다.
GitLost는 주로 모델 호스팅의 문제가 아닙니다. 이는 오케스트레이션 (Orchestration)의 문제입니다.
만약 당신의 에이전트가 다음과 같은 작업을 수행할 수 있다면:
- 공개된 이슈(Issue)나 댓글을 읽을 수 있음
- 프라이빗 리포지토리(Private repository), 비밀값(Secrets), 또는 내부 문서를 액세스할 수 있음
- 풀 리퀘스트(Pull Request), 댓글, 이메일, 또는 티켓을 자동으로 생성할 수 있음
그렇다면 당신은 신뢰할 수 없는 텍스트(Untrusted text)가 신뢰할 수 있는 동작(Trusted actions)에 영향을 미칠 수 있는 시스템을 구축한 것입니다.
그것이 바로 중요한 신뢰 경계(Trust boundary)입니다.
저는 많은 AI 도구 관련 대화에서 동일한 오해를 목격합니다. 사람들은 어떤 모델이 가장 똑똑한지에 집착하며, 어떤 도구가 가장 넓은 토큰 범위를 가졌는지, 리포지토리 권한 범위(Repository scope)가 얼마나 느슨한지, 또는 가장 위험한 기본 동작(Default action)을 가지고 있는지는 무시합니다. 이는 본말이 전도된 것입니다. 실제로 모델은 종종 가장 흥미롭지 않은 부분입니다. 저는 멀티 에이전트 토론 및 AI 아키텍처에 관한 포스트에서도 동일한 주장을 했습니다. 사람들이 감탄하는 지능은 대개 오케스트레이션에 존재하며, 실패 모드(Failure modes) 또한 마찬가지입니다.
진짜 실수: 하나의 에이전트, 너무 많은 권한
GitLost를 생각하는 가장 명확한 방법은 다음과 같습니다: 시스템 내의 한 행위자(actor)에게 너무 많은 종류의 작업이 허용되었다는 것입니다.
신뢰할 수 없는 공개 텍스트를 검사할 수 있었고,
비공개 정보를 가져올 수 있었으며,
공개적으로 발언할 수 있었습니다.
이는 하나의 자동화된 단계에 부여하기에는 너무 과도한 권한입니다.
만약 제가 학생 계정에 모든 시험지, 모든 답안지, 그리고 모든 교직원 노트를 읽을 수 있는 권한을 주었다면, 검토 없이 해당 계정이 학급 전체에 메시지를 게시하도록 허용하지는 않았을 것입니다. 하지만 일부 에이전트 워크플로(agent workflows)는 대략 이와 유사한 방식으로 동작하고 있습니다.
이것이 바로 GitLost가 헤드라인을 장식하는 수많은 AI 공포(AI panic)보다 더 나은 교훈인 이유입니다. 이는 실제로 수정할 수 있는 설계 오류(design error)를 드러내기 때문입니다.
이 위험을 빠르게 줄이는 다섯 가지 변화
이 중 그 어떤 것도 에이전트 워크플로를 "안전(safe)"하게 만들지는 않습니다. 보안 작업에서 그 단어는 너무 절대적입니다. 다만 이들은 공격 표면(attack surface)을 줄여줍니다.
GitHub 에이전트 워크플로(GitHub Agentic Workflows)는 기본적으로 읽기 전용(read-only)이며 안전한 출력을 통해 쓰기 작업(write operations)을 분리하지만, 이러한 제어 장치들도 불필요하게 광범위한 읽기 권한을 가지고 민감한 출력을 게시할 수 있는 에이전트를 보완할 수는 없습니다.
1. 가능한 한 각 에이전트의 범위를 하나의 리포지토리로 제한하세요
리포지토리 간 액세스(Cross-repository access)는 편리하지만, 한 리포지토리의 공개 이슈가 다른 리포지토리의 유출로 이어지는 방식이기도 합니다.
워크플로가 이슈가 생성된 리포지토리에만 액세스할 필요가 있다면, 오직 그 권한만 부여하십시오. 만약 두 번째 비공개 리포지토리가 진정으로 필요하다면, 별도의 토큰과 자체 검토 지점을 가진 명시적인 별도 단계로 만드십시오.
이는 모든 비밀(secret)이나 서비스 계정(service account)에 적용되는 최소 권한 원칙(least-privilege logic)과 동일합니다. 에이전트에게 키가 필요하지 않다면, 키를 건네주지 마십시오.
2. 공개 쓰기 단계와 비공개 읽기 단계를 분리하세요
이것이 가장 큰 아키텍처적 해결책입니다.
다음 두 가지 작업을 동일한 워크플로 (workflow)가 자동으로 수행하게 두지 마십시오:
- 내부 또는 비공개 자료 읽기
- 공개 스레드에 직접 게시
두 가지가 모두 필요하다면, 그 사이에 게이트 (gate)를 추가하십시오. 첫 번째 단계에서는 데이터를 비공개 검토 채널로 수집하도록 만드십시오. 민감한 워크플로의 경우, 어떤 것이라도 공개적으로 다시 나가기 전에 반드시 사람의 승인을 거치도록 하십시오.
네, 이것은 워크플로를 느리게 만듭니다.
좋습니다.
비용이 전혀 들지 않는 보안 제어는 보통 아무것도 보호하지 못합니다.
3. 이슈 (issue), 풀 리퀘스트 (pull request), 댓글을 신뢰할 수 없는 입력값으로 취급하세요
에이전트가 읽는 모든 이슈 본문, PR 설명, 코드 주석, 변경 로그 (changelog), 그리고 마크다운 (Markdown) 파일은 그렇지 않음이 증명될 때까지 적대적인 것으로 취급해야 합니다.
그것이 자동화 사용을 중단하라는 뜻은 아닙니다. 사용자 제어 텍스트가 단순한 데이터일 뿐이라고 가장하는 것을 멈추라는 뜻입니다. 에이전트 시스템 (agentic system)에서 텍스트는 제어 표면 (control surface)이기도 합니다.
이것이 제가 많은 개인적인 작업을 위해 여전히 Docker, Ollama, Open WebUI를 사용한 더 단순한 셀프 호스팅 LLM 설정을 선호하는 이유입니다. 제가 생각하는 것을 돕는 로컬 채팅 인터페이스는, 저장소 권한과 공개 게시 권한을 가진 워크플로 에이전트와는 매우 다른 리스크 프로필 (risk profile)을 가집니다.
4. 더 좁은 범위의 토큰과 설치 스코프 (scope)를 사용하세요
조직 전체 (Org-wide) 액세스는 설정할 때는 편하지만 운영 환경 (production)에서는 위험합니다.
가능한 경우 저장소별 설치 권한을 사용하십시오. 읽기 액세스와 쓰기 액세스를 분리하십시오. 코드 액세스와 이슈 관리 액세스를 분리하십시오. 내부 자동화와 외부 지향 봇 (external-facing bots)을 분리하십시오.
목표는 우아함이 아닙니다. 목표는 폭발 반경 (blast-radius)의 감소입니다.
무언가 잘못되었을 때, 20개가 아니라 단 하나의 저장소만 영향을 받기를 원하기 때문입니다.
5. 관리자 세션을 로그로 남기는 것처럼 에이전트의 도구 호출 (tool calls)을 기록하세요
공개 이슈가 에이전트를 유도하여 에이전트가 비공개 파일을 가져온다면, 당신에게는 추적 경로 (trail)가 필요합니다.
어떤 트리거 (trigger)가 실행되었는지 기록하십시오.
어떤 저장소들이 건드려졌는지 기록하십시오.
어떤 도구들이 호출되었는지 기록하십시오.
어떤 텍스트가 다시 외부로 게시되었는지 기록하십시오.
그것이 없다면, 문제가 발생했다는 첫 번째 신호는 종종 유출된 출력물 그 자체일 것입니다.
저는 한 가지 실질적인 규칙을 추가하고 싶습니다. 새로운 워크플로우(workflow)를 실행할 때는 먼저 테스트 저장소(test repositories)를 대상으로 드라이 런(dry-run) 모드로 실행하십시오. 만약 공개된 댓글이 스테이징(staging) 환경에서 비공개 읽기(private read)에 영향을 줄 수 있다면, 프로덕션(production) 환경에서도 똑같이 수행할 것입니다.
GitLost가 컴퓨터 과학(CS) 학생들에게 가르쳐 주는 것
이 사례는 여러 핵심 개념을 하나의 사건에 묶어 놓았기 때문에 매우 강력한 교육적 예시가 됩니다.
인증(Authentication)은 인가(Authorization)가 아니다
공격자는 비공개 저장소(private repository)에 직접 침입할 필요가 없었습니다. 시스템 자체의 권한을 가진 에이전트(agent)가 공격자를 대신하여 읽기 작업을 수행했습니다.
이것은 인가(authorization) 설계의 실패입니다.
공개된 입력이 비공개 결과를 변경할 수 있다
학생들은 흔히 사용자 입력(user input)을 자신이 입력한 페이지나 양식에만 영향을 미치는 것으로 생각합니다. 에이전트 시스템은 그러한 사고 모델을 깨뜨립니다. 한 곳에 작성된 문장이 완전히 다른 곳에서 동작을 트리거(trigger)할 수 있습니다.
보안은 시스템 전체의 속성이다
모델(model), 워크플로우 트리거(workflow trigger), GitHub 토큰(token), 저장소 권한(repository permissions), 그리고 응답 경로(response path)가 모두 함께 작용합니다. 단 하나의 요소에만 집중하는 것은 핵심을 놓치는 것입니다.
이것이 제가 일반적인 AI 파멸론(AI doom-posting)보다 이런 사건들이 더 유용하다고 생각하는 이유입니다. 이러한 사건들은 구체적입니다. 데이터 흐름(data flow)을 도식화할 수 있고, 신뢰 경계(trust boundary)를 지목할 수 있으며, 설계가 정확히 어디서 잘못되었는지 설명할 수 있습니다.
에이전트 워크플로우에 대한 나의 결론
저는 에이전트를 좋아합니다. 저도 사용합니다. 유용하다고 생각합니다.
하지만 동시에 많은 사람들이 에이전트를 프로덕션 시스템에 너무 무심하게 연결하고 있다고 생각합니다.
GitLost는 경고 사격입니다. AI가 유독 위험하기 때문이 아니라, 기존의 접근 제어(access-control) 실수가 자동화되었을 때 얼마나 빠르게 유출로 이어지는지를 보여주기 때문입니다.
만약 당신의 에이전트가 공개된 텍스트를 읽고, 비공개 코드에 접근하며, 인간의 확인 절차(human checkpoint) 없이 공개적으로 게시한다면, 다음 모델 업그레이드를 걱정하기 전에 그것부터 수정하십시오.
그 부분이 바로 진지하게 받아들일 가치가 있는 대목입니다.
참고 문헌
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기