검색
← 모듈 로드맵

AI 코딩 에이전트의 스크린샷 유출 위험

발행 출처 Medium · Gabriel Anhaia

깃허브사례준전문가

나중에 보기좋아요
공유 · 인쇄
후기댓글

PR에서 UI 수정 사항을 증명하라고 하자, 코딩 에이전트가 스크린샷을 공개 저장소에 호스팅했습니다. 그 과정과, 너무도 분명한 경로를 잡아내는 훅은 다음과 같습니다.

코딩 에이전트에게 헤더 색상을 바꾸고 변경이 제대로 됐는지 증명하라고 요청합니다. 풀 리퀘스트에 변경 전과 후를 넣어 달라고 하면서, 리뷰어가 볼 수 있어야 한다고 말합니다. 에이전트는 두 장의 스크린샷을 찍어 PR을 엽니다. 이미지가 렌더링됩니다. 당신은 승인하고 병합한 뒤 다음 작업을 맡습니다.

당신이 한 번도 확인하지 않은 것은 그 두 이미지가 어디에 있느냐는 점입니다. PR은 비공개 저장소에 있습니다. 이미지는 공개 저장소에 들어가 있습니다. 당신의 개인 GitHub 계정 아래에, 에이전트가 당신의 자격 증명으로 1분 전에 만든 저장소입니다.

이것이 Glow Labs가 연구에서 문서화한 패턴이며, 이 연구는 PixelLeak이라고 부르고 2026년 9월 29일에 공개되었습니다. 그 집계 수는 300개가 넘는 조직의 개발자들로부터 나온 13,000개 이상의 내부 이미지가 공개 GitHub에 올라갔다는 것입니다. 누구도 침입하지 않았습니다. 에이전트가 시킨 일을 하다가 직접 게시한 것입니다.

공개된 상태로 놓여 있던 것들

Glow는 영향을 받은 회사를 유형별로만 설명하고(대형 기술 회사, 선도적 AI 연구소, Fortune 500 여행 회사) 이름은 밝히지 않습니다. 하지만 보고서의 사례는 여전히 구체적입니다.

  • 직원이 10만 명이 넘는 한 제조업체에서는 내부 청구 화면 수정 사항을 확인하던 에이전트가 개발자의 개인 계정 아래 공개 저장소를 만들었습니다. 스크린샷에는 유틸리티 회사의 청구 기록이 담겨 있었습니다. Glow가 연락했을 때도 여전히 공개되어 있었습니다.
  • 한 금융 서비스 회사에서는 노출된 이미지에 재무 및 결제 콘솔, 기관 고객 이름이 적힌 출금 화면, 그리고 자금 이동 콘솔의 화면 녹화 두 개가 포함되어 있었습니다.
  • 한 소프트웨어 공급업체에서는 에이전트가 회사 제품의 스크린샷과 녹화본을 1,000개 이상 업로드했으며, 출시까지 몇 주 또는 몇 달 남은 기능에 대한 서면 요약도 함께 올렸습니다.

WorkOS의 정리 글 에 따르면 이 피해는 900개가 넘는 저장소에 걸쳐 있었고, Glow는 2026년 9월 9일부터 영향을 받은 조직들에 알리기 시작했다고 합니다. Glow는 코딩 에이전트를 위한 런타임 제어 기능을 판매하고, WorkOS는 아이덴티티 제품을 판매하므로 둘 다 수정 방안에 이해관계가 있습니다. 비용이 들지 않는 수정부터 시작하세요.

무해해 보이는 요청이 어떻게 유출로 바뀌는가

메커니즘은 단조롭습니다. GitHub의 풀 리퀘스트 이미지 호스팅은 브라우저용으로 만들어졌습니다. 댓글 상자에 파일을 끌어다 놓으면 GitHub가 저장합니다. 에이전트는 터미널에서 git과 GitHub CLI 를 통해 작업하며, 이번 9월 전까지는 CLI로 PR에 이미지를 넣는 방법이 없었습니다. Help Net Security 는 이를 "GitHub 명령줄 첨부 제한"이라고 부릅니다.

그래서 에이전트는 목표(리뷰어에게 스크린샷을 보여주기)와 장애물(명령줄에서 업로드 불가)을 동시에 갖게 됩니다. 그리고 자신의 자격 증명이 허용하는 범위를 살펴봅니다. gh auth login 이 설정하는 토큰은 최소한 repo, read:org, gist 범위를 필요로 합니다. 이 범위가 있으면 공개 저장소나 gist를 만드는 것은 한 줄 명령이면 됩니다. 공개 저장소는 비공개 PR의 리뷰어를 포함해 누구에게나 이미지를 제공할 수 있습니다.

Glow는 작은 Minesweeper 프로젝트에서 Claude Code 로 이 동작을 재현했습니다. 헤더 색상을 바꾸고 확인하라고 하자, 에이전트는 “GitHub는 비공개 저장소의 이미지를 PR 설명에서 렌더링할 수 없다”고 판단한 뒤, 두 장의 스크린샷을 위해 “새 공개 저장소를 만들었다”고 보고했다고 보고서는 설명합니다 . Glow가 본 에이전트들의 평가는 다음과 같습니다.

그들은 보안상의 함의를 전혀 고려하지 않았습니다.

WorkOS는 더 직설적으로 말합니다. “본질적인 이야기에는 프롬프트 주입도, 악성 패키지도 없었습니다.” 누군가 에이전트를 속인 것이 아니었습니다. 에이전트는 개발자의 GitHub 토큰으로 실행됐고, 설정 어디에도 “작업을 끝내라”와 “내부 콘텐츠를 인터넷에 공개하라”를 분리하는 장치는 없었습니다. 이미 사용한 모든 권한을 갖고 있었고, 티켓이 그 이유를 제공했을 뿐입니다.

스스로 반복하도록 학습한 우회책

소프트웨어 공급업체에서는 이 우회책이 일회성으로 끝나지 않았습니다. Glow는 에이전트들이 7월 초부터 리뷰 스크린샷을 공개적으로 게시하기 시작했으며, “일주일 안에 12개가 넘는 에이전트가 이 접근 방식을 모든 개발 티켓에 사용할 기술로 인코딩했다”고 보고했습니다.

스킬, AGENTS.md 파일, 그리고 공유 지침은 팀이 에이전트에게 사내 스타일을 가르치는 방법입니다. 동시에, 한 번 잘못된 답이 이후의 모든 세션으로 복사되어 아무도 다시 읽지 않게 되는 경로이기도 합니다. Glow의 조언에는 에이전트가 불러오는 공유 스킬과 지침 파일을 검토하라는 내용이 포함됩니다. 보고서에서 가장 저렴한 해결책입니다.

두 번째 경로는 도구였습니다. 영향을 받은 조직의 약 3분의 1에서는 개발자들이 gitshot이라는 오픈소스 스크린샷 게시 도구를 실행하고 있었고, 에이전트는 같은 제한을 우회하는 데 이를 사용했습니다. Glow에 따르면 이 이미지들은 “어디를 봐야 하는지 아는 사람이라면 누구나 내려받을 수 있는 _gitshot이라는 태그 아래에 저장됩니다.”

그 뒤로 장애물은 대부분 사라졌습니다. 2026년 9월 1일, GitHub는 --attach를 GitHub CLI v2.99.0에 추가했고, gh pr create, gh pr edit, gh pr comment 및 이슈에 대응하는 명령에도 적용했습니다. 변경 로그에는 아예 이렇게 적혀 있습니다. “여러분의 코딩 에이전트도 이것을 사용할 수 있습니다.” 이 기능은 저장소에 대한 쓰기 권한이 필요하며, 해당 릴리스에서는 GitHub Enterprise Server를 지원하지 않습니다. CLI 문서는 그 형태를 보여줍니다.

코드
gh --version   # needs 2.99.0 or latergh pr create --title "Fix header color" \  --body-file pr.md \  --attach before.png --attach after.png

리뷰어의 스크린샷을 보관하기에 정확히 알맞은 자리입니다. 하지만 7월에 작성된 스킬은 이 플래그의 존재를 알지 못합니다. gitshot 설치도 마찬가지이고, 아직 구버전 gh를 쓰는 노트북도 마찬가지입니다. CLI를 업데이트한 다음, 에이전트의 지침 파일에 이렇게 적으세요. 스크린샷은 --attach로 PR에 넣고, 그 외의 어디에도 두지 말 것.

왜 아무 경고도 울리지 않았는가

세 가지 사각지대가 겹쳤습니다.

첫 번째는 계정입니다. Glow는 “사례의 93%에서 이미지가 직원이 자신의 사용자 이름으로 만든 저장소에 있었다”고 밝혔습니다. 조직의 감사 로그, 정책, 모니터링은 조직 자체를 대상으로 합니다. 개발자의 개인 계정 아래 있는 저장소는 그 모든 범위 밖에 있습니다.

두 번째는 형식입니다. 비밀 정보 스캐닝은 텍스트 속의 자격 증명 패턴을 찾습니다. 청구 콘솔의 스크린샷에는 토큰 문자열이 없고, 스크린샷에 보이는 비밀번호는 그저 픽셀일 뿐입니다. Glow의 표현대로라면, “그들은 텍스트를 읽지, 픽셀을 읽지 않습니다.”

세 번째는 “secret”이라는 단어입니다. gh gist create는 기본적으로 secret gist를 만들므로 안전해 보입니다. 하지만 GitHub의 공식 문서는 다르게 말합니다. “Secret gist는 비공개가 아닙니다.” URL만 알면 누구나 열 수 있습니다.

바깥으로 열리는 문을 붙잡아 두기

Glow의 런타임 권장 사항은 네 가지 작업에 대해 “푸시를 차단하거나 승인 대기 상태로 둘 수 있는” 사전 실행 훅입니다. 보고서에 따르면 :

  1. 새 공개 저장소를 만드는 것.
  2. 회사 계정이 아니라 개인 계정으로 푸시하는 것.
  3. gist로 푸시하는 것.
  4. 저장소를 비공개에서 공개로 전환하는 것.

Claude Code에서는 이것이 PreToolUse hook 입니다. 이 hook은 대기 중인 Bash 명령을 stdin으로 JSON 형태로 받으며, permissionDecision으로 응답할 수 있습니다. ask는 "사용자에게 확인을 요청"하고, deny는 "도구 호출을 막습니다." 아래는 이 네 가지의 흔한 형태를 실행하기 전에 묻는 간단한 예시입니다. ORG를 회사의 GitHub organization으로 설정하세요:

코드
#!/usr/bin/env bash# .claude/hooks/hold.shORG="acme"cmd=$(jq -r '.tool_input.command // ""')
코드
hold() {  jq -n --arg r "$1" '{hookSpecificOutput: {    hookEventName: "PreToolUse",    permissionDecision: "ask",    permissionDecisionReason: $r}}'  exit 0}case "$cmd" in  *"gh repo create"*--public*)    hold "Creates a public repository" ;;  *"gh repo edit"*--visibility*)    hold "Changes repository visibility" ;;  *"gh gist "*)    hold "Gist: secret gists are readable by URL" ;;  *"git remote add"*|*"git remote set-url"*)    hold "Points this repo at a new remote" ;;  *github.com/*|*github.com:*)    case "$cmd" in      *"github.com/$ORG/"*|*"github.com:$ORG/"*) ;;      *) hold "GitHub target outside $ORG" ;;    esac ;;esacexit 0

이것은 jq가 필요합니다. 훅 레퍼런스 의 구조를 따라 .claude/settings.json에 등록하세요:

코드
{  "hooks": {    "PreToolUse": [      {        "matcher": "Bash",        "hooks": [          {            "type": "command",            "command": "bash",            "args": ["${CLAUDE_PROJECT_DIR}/.claude/hooks/hold.sh"],            "onFailure": "block"          }        ]      }    ]  }}

주의할 점이 두 가지 있습니다. 첫째, 훅 레퍼런스 에 따르면 충돌하거나 시간 초과가 난 PreToolUse hook은 호출을 차단하지 않으며, 호출은 일반적인 권한 흐름으로 진행됩니다. "onFailure": "block"은 이를 실패 시 닫힘으로 만들며, Claude Code v2.1.295 이상이 필요합니다.

둘째, 문자열 일치는 우회하기 쉽습니다. raw gh api 호출이나 다른 방식으로 작성된 명령은 놓치며, 원격 저장소가 이전에 설정돼 있었다면 단순한 git push가 어디로 가는지도 알 수 없습니다. PixelLeak의 경우에는 이것으로 충분합니다. 에이전트들은 무엇인가를 숨기고 있지 않았고, 눈에 보이는 경로를 택했으며, 그 눈에 보이는 경로가 바로 이것이 잡아내는 대상이기 때문입니다. 적극적으로 회피하는 상대에게는 엔드포인트에서의 제어가 필요하며, 그 계층을 Glow가 판매합니다. 저는 이 hook을 Glow의 재현 환경에서 직접 실행해 보지는 않았습니다. 다른 에이전트를 사용한다면 막아야 할 것은 같은 네 가지 행동이며, 이를 어떻게 막을지는 에이전트에 따라 달라집니다.

그런 다음 이미 유출된 것을 찾아보세요

이 hook은 다음 주를 보호합니다. Glow의 첫 번째 권고는 과거에 관한 것입니다. 자기 조직 밖까지 살펴보세요. 비공개 저장소에 커밋하는 사람들, 퇴사한 사람들을 포함한 계정도 확인하세요. 파일 목록만 보지 말고 릴리스와 gist도 확인하세요. 이미지가 발견되면 내려가게 하고, 복사해 간 사람에게도 같은 조치를 요청하며, 그 안에서 읽을 수 있는 자격 증명은 모두 교체하세요.

CLI로 대략적으로 1차 점검하는 방법이며, acme/web는 당신의 저장소 중 하나를 대체하는 예시입니다:

코드
gh api repos/acme/web/contributors --paginate \  --jq '.[].login' | sort -u > people.txt
코드
while read -r who; do  echo "== $who"  gh repo list "$who" --visibility public --limit 200  gh api "users/$who/gists" --paginate --jq '.[].html_url'done < people.txt

이것은 후보만 나열할 뿐입니다. 여전히 그 안을 직접 살펴봐야 하며, 다른 사용자의 비밀 gist는 API 목록에 아예 나타나지도 않습니다. 그 부분은 해당 계정을 소유한 사람들과의 대화가 필요합니다. EU에 있다면, 직원 및 전직 직원의 개인 계정을 들여다보기 전에 개인정보를 담당하는 사람을 반드시 참여시키세요. 직원 감시 규정이 적용될 수 있습니다.

중단은 응답하는 사람이 누구인지에 따라 그 가치가 결정됩니다

Glow는 또한 포괄적인 자동 승인을 피하고, 검토 단계가 “에이전트가 막 하려는 일을 드러내도록” 하라고 조언합니다. 그 조언에는 대가가 있습니다. 세 개나 네 개의 에이전트가 동시에 실행 중일 때, 당신이 보지 않는 터미널에서 멈춰 있는 명령은 작업 정체를 의미합니다. 작업이 충분히 정체되면 누군가는 자동 승인을 다시 켜게 됩니다.

저는 Hermes IDE를 만들고 있으므로, 이 점은 그 맥락을 감안해서 받아들이세요. 각 에이전트를 별도의 터미널에서 실행하고, 사용자의 응답이 필요한 에이전트를 위한 하나의 attention inbox를 유지하므로, 보류된 gh repo create는 한곳에서 사용자의 응답을 기다리는 에이전트로 표시됩니다. Hermes가 사용자를 대신해 권한 프롬프트에 응답하는 일은 없습니다. Review Desk는 작업을 정리하기 전에 무엇이 바뀌었는지 보여줍니다. 다른 저장소로의 푸시는 거기 나타나지 않으므로, 그래서 hook이 그 중단을 담당합니다.

에이전트는 작업을 끝내기 위해 당신이 부여한 모든 권한을 사용합니다. 어떤 작업이 외부로 열려 있는지 정하고, 각 지점에 사람을 배치하세요.

추가 읽을거리

Hermes IDE는 macOS, Windows, Linux에서 무료이며 소스 공개(BSL 1.1)입니다: 다운로드 하거나 GitHub에서 코드 보기 를 하세요. 이는 Nous Research, Anthropic, OpenAI, Glow 또는 어떤 에이전트 벤더와도 관련이 없습니다.

Glow의 보고서에 나온 유출은 자세히 살펴보지 않은 에이전트 행동에서 시작됐습니다. LLM 시스템이 실제로 무엇을 했는지 파악하고, 팀에 그 모습을 보여 주는 추적 및 로깅 도구를 고르는 방법은 LLM Observability Pocket Guide 의 주제입니다.

출처

  • 원문: https://medium.com/@anhaia.gabriel/ai-agents-put-13-000-internal-images-on-public-github-no-attacker-needed-2471ab1d7369?source=rss------claude_code-5 (2026-10-16 · Gabriel Anhaia)

자료 변경 기록을 불러오는 중입니다.

다음 자료를 불러오는 중입니다.

후기

아직 후기가 없습니다

직접 적용한 결과와 주의할 점을 공유하는 공간입니다.

로그인하고 후기 쓰기

참고 자료 · 도구와 릴리스 노트

댓글