로컬에서 모델 돌리는데 무슨 전화를 하나 — huggingface_hub의 조용한 지문 수집
내 소중한 소스코드가 외부 클라우드로 유출되는 게 죽기보다 싫어서, 비싼 돈 들여 맥 스튜디오에 홈서버까지 맞추고 굳이 ‘로컬 LLM’을 돌리고 있었다. 그런데 가장 믿었던 도끼에 발등을 제대로 찍혔다(이건 배신이다). 오픈소스의 성지라는 허깅페이스의 huggingface_hub 라이브러리가 내 컴퓨터 환경변수를 몰래 훔쳐보며, 내가 Cursor를 쓰는지 Claude Code를 쓰는지 실시간으로 지문(Fingerprinting)을 떠서 자기네 서버로 보내고 있었다는 폭로가 터졌다.
어제 r/localllm에 올라온 이 고발 글을 읽고 진짜 뒤통수가 얼얼했다. 완벽한 로컬 환경인 줄 알고 안심하고 있었는데, 내 안방에서 스파이가 돌아가고 있었던 셈이다.
시작은 허가받지 않은 연결 하나
사건의 전말은 이렇다. 한 개발자가 외부 통신이 완벽히 차단된 로컬 환경에서 음성인식(Whisper)과 비전 모델을 돌리는 폐쇄망 프로젝트를 세팅하고 있었다. 혹시 모를 네트워크 누수를 막으려고 파이썬 레벨의 소켓 방화벽을 걸어두고 패킷 감사를 돌렸는데, 뜬금없이 huggingface.co로 튀어나가는 수상한 아웃바운드 HTTPS 연결이 덜컥 잡힌 것이다.
콜 스택을 까보니 어처구니가 없었다.
WhisperModel("base.en") → faster_whisper → huggingface_hub.snapshot_download → huggingface.co.
로컬 캐시에 모델이 이미 다 받아져 있는데도, 최신 버전 업데이트를 확인하겠답시고 허브 서버에 핑을 때리는 것까지는 백번 양보해서 이해해 줄 수 있었다. 진짜 문제는 그 HTTP 요청 헤더에 은밀하게 실려 나간 ‘페이로드’였다.
개발자가 허깅페이스 로컬 캐시 폴더(~/.cache/huggingface/)를 뒤지다 보니 듣도 보도 못한 수상한 파일이 하나 튀어나왔다. 바로 .agent_harnesses.json이라는 6KB짜리 JSON 파일이었다. 파일을 열어본 개발자는 경악을 금치 못했다.
{
"standardEnvVars": ["AI_AGENT", "AGENT"],
"harnesses": {
"cursor": {
"prettyLabel": "Cursor",
"envVars": {"CURSOR_TRACE_ID": "*"}
},
"claude-code": {
"prettyLabel": "Claude Code",
"envVars": {"CLAUDECODE": "*", "CLAUDE_CODE": "*"}
},
"github-copilot": {
"prettyLabel": "GitHub Copilot",
"envVars": {"COPILOT_MODEL": "*", "COPILOT_GITHUB_TOKEN": "*"}
}
}
}
Cursor, Claude Code, GitHub Copilot, Devin, Cline, Goose 등 전 세계 주요 AI 코딩 에이전트 26종의 이름과, 그 도구들이 실행될 때 시스템에 남기는 ‘환경변수 시그니처’가 친절하게 데이터베이스로 정리되어 있었던 것이다.
어떻게 동작하나
동작 원리는 더 가관이다. huggingface_hub 패키지 내부에는 _detect_agent.py라는 은밀한 모듈이 심어져 있었다.
- 허깅페이스 API 엔드포인트에서 최신 에이전트 레지스트리 목록을 다운받아 로컬 캐시에 24시간마다 갱신한다.
- 파이썬 코드가 허브 API를 찌를 때마다
detect_agent()함수가 몰래 실행되어, 현재 개발자의 OS 환경변수(Env)를 이 목록과 대조한다. - 만약 내가 Cursor 터미널에서 파이썬을 실행했다면
CURSOR_TRACE_ID가 걸릴 것이고, Claude Code 세션 안이라면CLAUDECODE변수가 감지된다. - 그렇게 알아낸 “이 개발자는 지금 무슨 에이전트 툴을 쓰고 있는가”라는 식별 태그를 HTTP 요청 헤더에 얹어서 허깅페이스 본서버로 쏴버린다.
이 수집된 데이터는 허깅페이스의 공식 ‘에이전트 사용 통계 랭킹’을 집계하는 데 쓰인다. faster-whisper든 transformers든, 허깅페이스 라이브러리를 거치는 코드를 돌리는 순간 내 작업 도구 현황이 실시간으로 본사로 생중계되고 있었던 거다(내 동의는 대체 어디로 갔나?).
당장 이 찝찝한 텔레메트리를 틀어막는 방법은 다음과 같다.
export HF_HUB_OFFLINE=1
export TRANSFORMERS_OFFLINE=1
export HF_HUB_DISABLE_TELEMETRY=1
앞의 두 환경변수는 허깅페이스의 모든 아웃바운드 네트워크 통신을 강제로 틀어막는 오프라인 모드다. 세 번째 변수는 텔레메트리를 끄는 옵션이지만, 에이전트 감지 헤더까지 완벽하게 차단하는지는 아직 미지수다.
가장 확실한 해결책은 코드에서 모델을 부를 때 WhisperModel("base.en")처럼 모델명을 던지지 말고, WhisperModel("/Users/.../models/whisper-base")처럼 ‘로컬 절대 경로’를 박아 넣는 것이다. 경로가 직접 들어가면 라이브러리가 허브 서버를 찌를 핑계 자체가 사라진다.
왜 주목할까
글쓴이도 짚었듯이 허깅페이스가 악성 멀웨어를 심은 건 아니다. 기업 입장에선 “요즘 개발자들이 어떤 에이전트 환경에서 우리 모델을 많이 다운받나” 집계하고 싶었을 거다. 깃허브 PR도 공개되어 있다.
하지만 문제는 ‘동의(Consent)’다.
사용자에게 “도구 분석 데이터를 수집해도 될까요?”라고 묻는 팝업 한 줄 띄운 적이 없다. pip install 한 번 쳤을 뿐인데 백그라운드에서 환경변수를 스캔해서 본사로 전송한다? 사내 기밀이나 개인 프라이버시 때문에 로컬 서빙을 고집해 온 엔지니어 입장에서는 배신감이 들 수밖에 없다.
로컬 모델을 돌린다고 해서 무조건 100% 안전하다는 생각은 거대한 착각이었다. 모델 가중치 자체는 오프라인일지 몰라도, 그 모델을 로드하고 서빙하는 수많은 파이썬 서드파티 라이브러리 계층이 내 등 뒤에서 무슨 짓을 하고 있는지 네트워크 레벨에서 감시하지 않으면 프라이버시는 허상이다.
정리
이번 사건은 로컬 AI 생태계에 꽤 묵직한 경종을 울렸다.
huggingface_hub는 사용자의 환경변수를 뒤져 AI 도구 지문을 몰래 수집하고 있었다.- 찝찝하다면
HF_HUB_OFFLINE=1을 걸고, 모델 로딩 시 반드시 ‘로컬 절대 경로’를 지정하라. - 진짜 보안이 생명인 로컬 환경이라면 파이썬 소켓 레벨에서 아웃바운드 IP를 감시하는 습관을 들이자.
알고 제공하는 텔레메트리와, 뒤통수 맞듯 털리는 텔레메트리는 차원이 다르다. 이 글을 읽은 분들은 지금 당장 터미널을 열고 ls -la ~/.cache/huggingface/를 쳐보자. 내 컴퓨터에도 그 소름 돋는 에이전트 족보 파일이 얌전히 들어앉아 있을 확률이 99%다(확인하고 조용히 지우자).