AI 코딩 에이전트 프라이버시: 흔한 오해 5가지 검증
AI 코딩 에이전트가 승인하지 않은 HTTP 요청을 보냅니다. 에이전트 프라이버시에 관한 흔한 오해 5가지를 직접 검증했습니다.

매일 수십 통의 스캠 이메일이 옵니다. 내 실명이 들어간 채로요. 그런데 유출의 원인은 해킹당한 데이터베이스도 마케팅 리스트도 아닙니다. AI 코딩 에이전트가 승인한 적 없는 웹 요청에 붙여 보낸 User-Agent 헤더입니다. 개발자들이 스팸 물결을 추적하다가 Claude Code까지 거슬러 올라갔습니다. 웹 페치와 검색 과정에서 사용자의 계정 이메일 주소를 나가는 HTTP 요청에 찍어 넣고 있었던 겁니다. Anthropic의 설명은 버그 자체보다 더 아찔합니다. 그럴듯한 @author 태그를 쓰게 하려고 계정 이메일을 모델 컨텍스트에 넣었는데, 모델이 “도움이 되는 봇”답게 연락처를 묻는 사이트에 그 이메일을 알아서 내밀기 시작한 것입니다. 저는 수년간 개발자 머신에서 돌아가는 도구들의 네트워크 동작을 점검해 왔는데, 이번 사건은 교과서적인 사례에 가깝습니다. 그래서 에이전트 도구 프라이버시에 대해 가장 자주 듣는 다섯 가지 믿음을 꺼내, 실제로 벌어진 일에 비추어 하나씩 검증해 보겠습니다.
오해 1: “내 코딩 에이전트는 모델 제공사의 API하고만 통신한다”
거의 모든 사람이 이런 멘탈 모델에서 출발합니다. 에이전트는 터미널과 Anthropic(또는 OpenAI 등)의 서버 사이를 잇는 그럴듯한 파이프이고, 코드가 들어가면 토큰이 나오고, 중요한 네트워크 엔드포인트는 api.anthropic.com 하나뿐이라고 생각하죠.
틀린 생각입니다. 현대의 에이전트형 CLI는 언어 모델이 구동하는 범용 HTTP 클라이언트입니다. 임의의 URL을 가져오는 WebFetch 도구가 있고, 검색 인프라에 요청을 보내는 WebSearch 도구가 있습니다. 그리고 Bash 도구가 있죠. 즉 curl, wget, pip install, npm install, git clone 등 시스템에 있는 네트워크 가능한 바이너리 전부를 쓸 수 있다는 뜻입니다. 문서, 패키지, 변경 로그, SEC 공시가 필요하다고 판단하면 그게 있을 법한 곳 어디서든 가져옵니다. 그 요청들은 전부 여러분의 IP에서 출발하고, 사내 네트워크를 타고, 모델이 그날 아침 멋대로 써넣은 헤더를 달고 나갑니다.
게다가 모델은 꽤 창의적입니다. 이 이메일 사건이 알려진 뒤 한 엔지니어가 자기 웹 서버 로그를 확인했더니, 서브에이전트가 company-helm-research/1.0 (Claude Code agent run by [name], [company] platform team; docs lookup) 같은 User-Agent 문자열로 보낸 요청이 찍혀 있었습니다. 회사 이름과 작업 중이던 GitHub 저장소까지 적혀 있었죠. 에이전트가 설정값을 그대로 흘린 게 아니라, 맥락에서 식별 정보를 조합해서 만들어 낸 겁니다. 친절한 인턴이 콜드 메일마다 이름, 팀, 프로젝트를 전부 서명에 넣는 것과 비슷하죠. 이런 구조가 왜 이렇게 쉽게 문제를 일으키는지 더 자세히 알고 싶다면 에이전트형 코딩 CLI가 어떻게 만들어지는지를 다룬 글을 참고하세요. 요약하면, 루프와 컨텍스트와 도구 세트는 문제를 일으킬 만큼 강력하다는 것입니다.
올바른 멘탈 모델은 이렇습니다. 에이전트는 회사 노트북, 사내 네트워크 연결, 그리고 명함 한 묶음을 들고 다니는 신입 사원입니다. 컨텍스트에 있는 것은 무엇이든 가진 도구를 통해 건물 밖으로 나갈 수 있습니다.
오해 2: “User-Agent에 연락처 이메일을 넣는 건 그냥 봇 에티켓이다”
이 오해에는 일말의 진실이 들어 있어서 더 위험합니다. 잘 만들어진 크롤러가 자신을 밝히고 연락처를 남기는 것은 실제로 있는 관례입니다. 어떤 서비스는 이걸 엄격하게 강제하기도 하죠. 예를 들어 SEC의 EDGAR API는 일반적인 curl User-Agent로 온 요청을 가차 없이 거절하고, 밝힌 연락처를 요구합니다. 직접 확인하는 데 10초면 됩니다.
U='https://data.sec.gov/api/xbrl/companyconcept/CIK0000320193/us-gaap/Assets.json'
curl -s -o /dev/null -w '%{http_code} default UA\n' "$U"
# 403 default UA
curl -s -o /dev/null -w '%{http_code} declared contact\n' \
-A 'Acme Research admin@acme-research.example' "$U"
# 200 declared contact
그러니 “일부 API는 User-Agent에 연락처 주소를 원한다”는 걸 학습한 모델은 환각을 일으키는 게 아닙니다. 실제 인터넷 에티켓을 패턴으로 따라 하고 있을 뿐이죠. 그리고 그 모델의 컨텍스트에 여러분의 계정 이메일이 있다면, 제공할 수 있는 연락처는 딱 하나입니다. Anthropic에서 이 사건을 설명한 엔지니어도 그 비슷한 말을 했습니다. 일부 사이트가 에이전트에게 연락처를 요구하면, Claude가 가진 이메일을 내주곤 했다는 것입니다.
여기서 오해가 깨집니다. 관례에 따르면 연락처는 봇을 운영하는 쪽의 것이어야 합니다. 크롤러를 돌리는 주체가 누구인지 밝혀서, 불만이 있는 시스템 관리자가 책임질 사람에게 연락할 수 있게 하자는 것이죠. Anthropic의 크롤러는 Anthropic을, Google의 크롤러는 Google을 밝힙니다. 그런데 여러분의 에이전트가 페이지를 가져올 때 운영자 연락처는 도구 제공사의 지원 URL이나 여러분이 의도적으로 설정한 주소여야 합니다. 구독료를 결제할 때 쓴 개인 계정 이메일이어서는 안 되죠. RFC 9110의 User-Agent 지침도 불필요하게 상세한 식별 정보를 넣지 말라고 권하고 있고, 제가 아는 프라이버시 엔지니어들은 요청 헤더에 들어간 요청하지 않은 개인정보를 예외 없이 결함으로 봅니다. 봇 에티켓은 봇 뒤에 앉아 있는 사람을 신원 노출시키려고 만든 게 아닙니다.
피해 범위도 이론이 아닙니다. 검색하는 에이전트가 필연적으로 마주치게 되는 스캠투성이 웹 구석구석을 포함해, 임의의 제3자 사이트가 이제 실명이 붙은 검증된 이메일 주소를 현직 소프트웨어 엔지니어 한 명에 대해 갖고 있게 된 겁니다. 스피어 피싱의 씨앗을 선물 포장해 건넨 셈이죠. 여러 개발자가 갑자기 쏟아진 맞춤형 스팸을 정확히 이 동작까지 추적해 냈습니다. 스패머에게 신상이 털리게 만드는 “좋은 봇 시민의식”은 좋지도 않고 시민의식도 아닙니다.

오해 3: “권한 요청 창과 샌드박스가 내 신원을 지켜 준다”
모든 에이전트형 도구에는 어떤 형태로든 동의 UX가 있습니다. 명령을 실행하기 전에 묻고, 어떤 파일을 읽는지 보여 주고, 웹 접근을 도메인별 승인 뒤에 두기도 하죠. 이 때문에 강력한 인상이 생깁니다. 한 개발자는 그걸 “LLM은 프로젝트에 명시적으로 추가된 것에만 접근할 수 있다”는 느낌이라고 표현했습니다. 이건 틀린 인상이고, 이메일 사건이 두 가지 측면에서 그걸 증명합니다.
첫째, 권한 시스템이 제어하는 것은 어떤 도구가 실행되는지이지, 그 도구가 만드는 요청 안에 모델이 무엇을 써 넣는지가 아닙니다. “예, 이 URL을 가져오세요”라고 승인해도, 그 가져오기를 위해 모델이 조합한 헤더에 대해서는 아무것도 알려 주지 않습니다. curl을 실행하는 Bash 호출을 승인하는 경우에는 더 말할 것도 없습니다. 명령어 문자열이 휙 지나가고, 아무도 -A 플래그는 읽지 않으니까요. 둘째, 권한 UI는 동작 하나하나 단위로 작동하는데, 이번 유출은 컨텍스트의 속성입니다. 사용자는 본 적도 없고 거부할 수도 없었던 시스템 컨텍스트에 계정 이메일이 주입되는 순간, 그 이메일은 세션 내내 모든 도구 호출, 모든 서브에이전트, 모든 curl 한 줄짜리 명령에서 쓸 수 있게 됩니다. 샌드박스의 경계는 파일 시스템 주변에 그어져 있었지만, 실제 유출 경로는 모델 자신의 텍스트 생성이었던 겁니다.
이 부분은 솔직하게 짚고 싶습니다. 한 벤더의 버그를 넘어 일반화되는 이야기니까요. 에이전트의 컨텍스트에 있는 것은 그럴듯해 보이는 지시 하나만 있으면 내 머신 밖으로 나갈 수 있습니다. API 키, 내부 호스트명, 파일 내용, 이름, 회사, 이메일 모두 해당합니다. 모델 자체가 유출 통로가 되면 도구 계층의 격리는 도움이 되지 않습니다. 그래서 제가 이전에 AI 에이전트에 대해 격리와 모니터링은 서로 다른 문제를 해결한다고 주장했던 것이고, 지금 내가 어떤 것을 얻고 있는지 알아야 합니다. 권한 대화창은 통제처럼 꾸민 모니터링입니다. 행동은 보여 줄 수 있어도, 행동의 매개변수에 담긴 의도까지는 보여 줄 수 없습니다.
판정: 출하된 그대로의 샌드박스는 파일은 막아 주었지만, 신원은 아무것도 막지 못했습니다. 신원이 모델에게 원재료로 그대로 넘어갔기 때문입니다.
오해 4: “설정 하나만 바꾸면 된다. 토글만 끄면 안전하다”
문제가 커졌을 때 원래 제보자가 요구한 것은 구체적이었습니다. 이건 옵트아웃 설정이 되어서는 안 되고, 하네스에서 완전히 제거해야 한다는 것이었죠. 그 직관은 옳습니다. 그리고 수정이 실제로 어떻게 반영됐는지를 보면, 이런 종류의 문제에 설정이 왜 잘못된 수단인지 알 수 있습니다.
조치는 두 부분이었습니다. 첫째, 내장 플러그인 cc-plugin-privacy(v2.1.317부터 기본 활성화)가 이 동작을 결정론적으로 차단합니다. 모델에게 부탁하는 게 아니라 확실하게 검사하는 것입니다. 둘째, 더 중요한 것은 Anthropic이 계정 이메일을 모델 컨텍스트에서 아예 제거했다는 점입니다. 중요도의 순서를 주목하세요. 플러그인은 출력에 거는 필터이고, 컨텍스트에서 이메일을 빼는 것은 기능 자체를 없애는 것입니다. 필터는 놓칠 수 있습니다. 여러분의 이메일을 전혀 모르는 모델은, 헤더를 얼마나 창의적으로 조합하든 그걸 유출할 수 없습니다.
프롬프트로는 데이터 노출에서 빠져나올 수 없습니다. 모델이 볼 수 있다면, 모델은 그것을 내보낼 수 있습니다. 믿을 만한 유일한 마스킹은 빼는 것입니다.
이런 패턴은 에이전트 도구에서 계속 보입니다. 우리가 자격 증명 금고 역할을 겸하는 API 클라이언트 감사에서 다뤘던 것과 같은 맥락입니다. 민감한 정보가 가장 편리한 자리(컨텍스트, 환경 변수, 설정 파일)에 쑤셔 넣어집니다. 어떤 기능이 한 번 필요했기 때문이죠. 그리고 그 뒤로 그 정보는 어디에나 따라다닙니다. 텔레메트리 토글과 프라이버시 설정은 벤더가 무엇을 수집할지 결정한 것만 다룹니다. 모델이 건네받은 자료로 무엇을 즉흥적으로 할지에 대해서는 아무 말도 하지 않죠. 설정은 선호를 위한 것이고, 프라이버시는 결정론적 통제와 데이터 최소화로 지켜집니다. 벤더가 후자의 문제에 전자를 해결책으로 내놓는다면, 되물어야 합니다.
오해 5: “벤더가 패치했으니 이제 걱정할 필요 없다”
공은 공이니 인정하겠습니다. 이번 대응은 빨랐고, 엔지니어링 설명은 솔직했으며, 수정은 증상이 아니라 근본 원인을 건드렸습니다. 하지만 “패치됐다”는 특정 버전의 특정 동작에 대한 주장일 뿐입니다. 에이전트 도구가 식별 정보를 임의의 엔드포인트로 내보내는 문제 자체는 구조적인 것이라서, 이 도구에서든 다른 도구에서든 다시 나타날 겁니다. 여러 사용자가 지적했듯, 계정 신원이 허락 없이 Claude Code 컨텍스트에 나타난 것은 이번이 처음도 아니었습니다. 적어도 두 번째였죠.
그 아래에는 더 불편한 진실이 있습니다. 클라이언트 쪽에서는 유출이 없다는 것을 완전히 검증할 수 없습니다. 꼼꼼한 한 사용자는 수정된 버전에 중간자 프록시를 붙여 실행해 보고, WebFetch 도구를 통해 식별 정보가 기기 밖으로 나가지 않는다는 걸 확인했습니다. 좋은 작업이었고, 올바른 본능이었습니다. 하지만 그 사용자가 말했듯, 식별은 서버 쪽에서도 일어날 수 있습니다. 클라이언트는 익명 요청을 벤더 API로 보내지만, 벤더 쪽 인프라가 여러분의 정보를 붙여서 제3자에게 퍼뜨릴 수 있는 거죠. 그렇게 되면 아무리 로컬 패킷 검사를 해도 보이지 않습니다. 결국 벤더를 믿는 수밖에 없고, 이번 사건이 불편하게 증명한 바로 그 위치로 돌아가게 됩니다.
그래서 지속 가능한 자세는 “패치 적용, 사건 종결”이 아닙니다. 모든 에이전트형 도구를 영구적으로 의심스러운 네트워크 클라이언트로 보고, 주기적으로 감사하는 것입니다. 엔지니어 노트북에서 광범위한 권한을 가진 서드파티 소프트웨어를 다루듯이요. 이제 실제로 해볼 수 있는 부분으로 넘어가겠습니다.

에이전트의 네트워크 트래픽을 직접 감사하는 방법
이 중 어떤 것도 보안팀이 필요하지 않습니다. 오후 한나절과 기본적인 도구만 있으면, 어떤 개인정보 처리방침보다 에이전트의 동작을 더 잘 알게 됩니다.
1. 트래픽을 가로채세요. mitmproxy를 대상으로 에이전트를 실행하고, 실제 작업 세션을 돌려 보세요. Node 기반 CLI는 CA를 신뢰하게 만들면 보통 프록시 환경 변수를 따릅니다.
mitmdump --listen-port 8080 -w agent-flows.mitm &
export HTTPS_PROXY=http://127.0.0.1:8080
export NODE_EXTRA_CA_CERTS=~/.mitmproxy/mitmproxy-ca-cert.pem
# Now run your agent and do normal work.
# Afterwards, search every captured request for your identifiers:
mitmdump -nr agent-flows.mitm \
--flows \
| grep -iE 'you@company\.com|YourName|your-org'
이메일만 찾지 마세요. 이름, 회사, 조직의 GitHub 슬러그, 내부 호스트명, 저장소 이름도 검색하세요. 서브에이전트 로그를 떠올리세요. 모델은 식별자를 그대로 재현만 한 게 아니라 조합까지 했으니, 조각 단위로 검색해야 합니다.
2. 자신의 인프라 로그를 확인하세요. 웹 서비스를 운영하고 있다면, 액세스 로그에서 에이전트 User-Agent 문자열을 검색하세요. 앞서 오해 1에서 조합된 헤더를 찾아낸 방법이 바로 이것입니다. 비용도 들지 않고, 로컬 캡처가 놓치는 서브에이전트 트래픽을 종종 드러내 줍니다.
3. 아웃바운드 트래픽을 제한하세요. 가장 강력한 통제는 특정 종류의 유출을 아예 불가능하게 만드는 것입니다. 에이전트를 정당하게 필요한 엔드포인트만 허용하는 네트워크 정책을 가진 컨테이너나 VM 안에서 실행하세요. 모델 API, 패키지 레지스트리, 아마 GitHub 정도면 충분합니다. Docker를 쓴다면 커스텀 네트워크와 이그레스 방화벽을 조합하면 되고, Mac이라면 Little Snitch나 Lulu로 프로세스별 규칙을 걸 수 있습니다. 에이전트가 샌드박스에서 임의의 웹사이트에 접근할 수 없다면, 여러분의 신원을 임의의 웹사이트에 넘겨줄 수도 없습니다. 대신 무언가를 가져오려면 여러분에게 요청해야 하니 번거롭겠지만, 그 번거로움이 바로 목적입니다.
4. 도구가 아는 것을 최소화하세요. 도구 계정에는 주 업무용 주소가 아니라, 전용의 중요도 낮은 이메일을 쓰세요. 에이전트가 읽는 전역 설정 파일에서 식별 정보를 지우세요. 에이전트가 자주 읽어 가는 ~/.gitconfig가 대표적입니다. 도구가 지원한다면, 별도의 OS 사용자와 독립된 홈 디렉터리로 실행하세요. 빼는 것이 거르는 것보다 항상 낫습니다.
5. 조직 차원에서는 관리형 프록시로 경유시키세요. 회사가 엔지니어에게 에이전트 도구를 지급한다면, 트래픽을 로깅이 되는 이그레스 프록시로 강제 경유시키고, 파이프라인에 헤더 검사를 추가하세요. 에이전트가 수백 개의 낯선 도메인으로 퍼져 나가는 패턴만 해도 DNS 쿼리 로그로 잡아낼 수 있었을 겁니다. 이건 CI 러너나 빌드 머신에 적용하는 것과 같은 태도이고, 이 관점이 정확합니다. 에이전트는 의견을 가진 빌드 인프라입니다.
이메일이 User-Agent에 들어간 버그는 한 달 안에 릴리스 노트의 잡음 속에 묻힐 겁니다. 하지만 교훈까지 묻혀서는 안 됩니다. 에이전트형 코딩 도구는 우리 대부분이 돌리는 소프트웨어 중 가장 높은 권한을 가졌고, 네트워크를 가장 많이 쓰며, 감사를 가장 덜 받는 것들이고, 게다가 즉흥적으로 움직입니다. 그러니 그렇게 대하세요. 컨텍스트에 있는 것은 전부 공개되어 있다고 가정하고, 실제로 와이어에 무엇이 실리는지 검증하고, 필요해지기 전에 울타리를 세우세요. 스팸이 내 이름을 달고 날아온 뒤가 아니라요.


