코딩 에이전트가 올린 내 코드를 내가 못 여는 구조
ZCode 역공학 보고에서 중요한 건 업로드 용량이 아니라 개인키가 클라우드에만 있다는 점이다. 페이로드의 90% 가까이가 .git이었다. 설치 첫날 30분짜리 점검 절차.
코딩 에이전트를 평가할 때 물어야 할 질문은 "데이터를 서버로 보내는가"가 아니다. 그건 대부분 보낸다. 물어야 할 건 "보낸 것을 내가 열어볼 수 있는가" 다.
ZCode 역공학 보고에서 가장 중요한 한 줄은 업로드 용량이 아니라 키의 위치였다. 암호화에 쓰이는 공개키는 서버가 그때그때 내려주고, 개인키는 클라우드에만 있다. 내 디스크에 내가 못 읽는 내 코드의 암호문이 쌓이는 구조다.
출처: blog.ferstar.org — ZCode Silent Workspace Snapshot Upload
확인된 것 (보고 기준)
아래는 원문 보고에 적힌 내용이다. 내가 재현한 게 아니라는 점을 먼저 밝힌다.
-
로그인 상태에서 작업 공간 전체가 패키징되어 업로드된다. 관찰된 사례는 345MB 작업 공간에서 42,411개 파일, 313MB 암호화 아카이브.
-
그 페이로드의 대부분이
.git이다. 보고의 소제목이 "Nearly 90% Is .git"이고, 내역은.git/lfs/56.8%,.git/objects/29.6%. -
포함될 수 있는 것: 커밋 이력, 푸시하지 않은 브랜치 이름, 삭제한 자격증명, 전역 설정.
-
암호화는 AES-256-CTR에 RSA-OAEP-SHA256 키 래핑. 문제는 방식이 아니라 키의 소재다.
the RSA public key used for encryption is delivered on-the-fly by the server, while the private key lives exclusively in the cloud
-
전송 경로는 클라이언트가
zcode.z.ai에서 자격증명을 받아 Aliyun OSS로 직접 POST하고, OSS가 백엔드로 콜백하는 구조다. 앱 서버를 우회한다. -
설정 토글 두 개가 이 동작을 끄지 못한다. "경험 개선"은 학습 사용 승인 여부만 제어하고, "저장소 스냅샷 인덱싱"은 서버 인덱싱만 끈다.
Local packaging and upload continue uninterrupted
업로드 사이드카는 시작 시
is instantiated unconditionally at startup— 사용자 설정을 보는 게이트가 없다는 것이 보고의 서술이다. -
아카이브를 지우면 다시 만들어진다. 저자가 수동 삭제 후 실패 업로드 카운터가 564에서 565로 오르는 것을 관찰했다.
-
조사 방법:
~/.zcode구조와 메타데이터 JSON, 애플리케이션 로그의 업로드 URL,app.asar디컴파일, 활성 소켓 확인, UI 토글과 코드 대조.
판단
1. 감사 불가능한 전송은 양의 문제가 아니다
텔레메트리를 보내는 개발 도구는 흔하다. 크래시 리포트, 사용 통계, 인덱싱용 임베딩. 그 자체로 사건이 되진 않는다.
여기서 선을 넘는 지점은 내가 보낸 것을 내가 확인할 수 없다는 구조다. 로컬에 남은 암호문을 열어볼 방법이 없으니, 무엇이 올라갔는지 사후에 검증할 수 없다. "우리는 코드를 학습에 쓰지 않습니다"라는 약속이 참인지 거짓인지 판별할 수단이 사용자 쪽에 전혀 없다는 뜻이다.
그래서 도구 평가 항목을 하나 바꾸는 게 맞다. "무엇을 보내나" 대신 "보낸 걸 내가 열어볼 수 있나." 앞쪽은 문서에 적힌 대로 믿는 수밖에 없고, 뒤쪽은 확인 가능하다.
2. .git을 보내는 것과 워킹트리를 보내는 것은 다른 사건이다
이 보고에서 실질적 피해 규모를 결정하는 숫자는 313MB가 아니라 90% 가까이가 .git이었다는 쪽이다.
워킹트리에는 지금 상태만 있다. .git에는 지웠다고 믿은 것들이 있다. 코드에서 삭제한 API 키는 그 키를 커밋했던 시점의 오브젝트에 그대로 남아 있고, 리베이스로 정리했다고 생각한 히스토리도 참조가 남아 있으면 살아 있다. 아직 푸시하지 않은 브랜치 이름은 진행 중인 계획을 그대로 드러낸다.
여기서 나오는 실행 항목은 둘이다. 첫째, 에이전트의 워크스페이스 접근을 .git 포함 여부로 나눠서 본다. 대부분의 도구 설명은 "프로젝트 폴더에 접근합니다"라고만 쓰는데, 그 한 줄 안에 저장소 전체 이력이 들어 있다.
둘째, 한 번이라도 커밋에 들어간 키는 회전하는 것 말고 답이 없다. 이건 이 사건과 무관하게 늘 참이던 원칙인데, 이 사건이 그게 왜 참인지를 보여준다. 내 저장소가 내 기계 밖으로 나가는 경로는 내가 아는 것보다 많다.
3. 토글이 있다는 것과 토글이 그것을 끈다는 것은 다르다
보고가 지적하는 두 설정은 거짓 라벨이라기보다 이름이 실제 제어 범위보다 넓게 읽히는 경우다. "경험 개선을 끄면 데이터를 안 보내겠지"는 합리적인 추론이지만, 실제로 꺼지는 건 학습 사용 승인이었다.
이건 어느 한 회사의 문제로 좁힐 일이 아니다. 프라이버시 토글의 이름과 실제 코드 경로가 일치하는지 검증할 방법이 사용자에게 없다는 게 일반적인 상황이다.
그래서 규칙 하나. 새 코딩 에이전트를 처음 설치한 날, 토글을 다 끈 상태에서 나가는 연결을 한 번 본다. lsof -i로 충분하고, 더 보고 싶으면 아웃바운드 방화벽(Little Snitch, LuLu 같은 것)을 며칠 걸어두면 된다. 30분이면 끝나는 작업이고, 설치 직후가 그걸 할 동기가 생기는 유일한 시점이다. 한 달 지나면 아무도 안 본다.
4. 이 보고 자체의 한계도 같이 봐야 한다
반대 방향으로도 정직하게 쓴다. 이 글은 단일 저자의 역공학 보고이고, 나는 재현하지 않았다.
- 저자가 ZCode 버전 번호와 조사 기간을 명시하지 않았다. 어느 빌드에서 관찰된 동작인지 알 수 없다.
- 토론에서 한 사용자는 자기 설치본에서 수집·업로드 로그를 찾지 못했다고 보고했다. 즉 모든 설치본에서 동일하게 일어난다는 확정이 아니다.
- 분석이
git log와 저장소 자체를 혼동했다는 기술적 비판도 나왔다.
그러니 이 사건에서 확정적으로 가져갈 것은 특정 회사 이름이 아니라 점검 절차다. 이름만 기억하면 다음에 설치하는 도구에서 같은 일을 당한다. 위 3번의 30분짜리 확인은 어느 도구에나 쓸 수 있고, 그게 이 보고의 실제 효용이다.
모르는 것
- 직접 확인하지 않았다. ZCode를 설치해 패킷을 뜨거나
~/.zcode를 열어보지 않았다. 위 사실은 전부 원문 보고에 기댄 것이다. - 벤더 대응을 원문에서 확인하지 못했다. 토론에서는 기술적 반박 없이 사과성 응답이 있었다고 전해지지만, 나는 그 원문을 보지 못했다. 공식 입장문의 존재 여부를 확인하지 못한 상태다.
- 영향을 받는 버전 범위, 지역, 계정 유형을 모른다.
- 업로드된 데이터의 보존 기간과 삭제 요청 경로를 모른다. 보고에 없었다.
- 비로그인 상태나 오프라인에서의 동작은 범위 밖이다.
댓글
불러오는 중...