API 클라이언트는 자격 증명 금고다: 지금 감사하라
API 클라이언트의 보안 상태를 점검하세요. 데스크톱 개발 도구의 무음 플러그인 설치, 텔레메트리, 데이터 유출을 감사하는 방법을 알아봅니다.

개발자가 Mac에서 HTTP 클라이언트를 엽니다. 그게 전부입니다. 클릭도, 동의 창도, “AI 기능 사용” 체크박스도 없습니다. 다음 날 그들의 코딩 에이전트는 설정한 적 없는 원격 MCP 서버에 인증하지 못하고, 설치한 적 없는 스킬로 API 작업을 라우팅하며, 승인한 적 없는 암호학적으로 신뢰된 시작 훅을 달고 다닙니다. 가상의 이야기가 아닙니다. 최근 아주 꼼꼼하게 문서화된 버그 리포트의 증거가 보여주는 Postman 데스크톱 앱의 실제 동작입니다. Codex와 Claude Code에 플러그인을 자동 설치하고, 전역 에이전트 설정 파일에 쓰고, 자체 세션 훅을 신뢰 상태로 표시하려고 시도했습니다. API 클라이언트 보안에 신경 쓰신다면, 이 사건은 여러분 컴퓨터의 모든 데스크톱 개발 도구를 바라보는 방식을 바꿔놓아야 합니다.
Postman 데스크톱 앱이 실제로 한 일
분노는 잠시 접고 증거를 들여다봅시다. 리포터는 우리 대부분이 하지 않는 그 작업을 직접 했습니다. Postman 자체 로그 파일에는 auto-existing-upgrade 이벤트가 기록되어 있었습니다. 로그인된 기존 데스크톱 설치본에서 스크립트가 실행되었고, claude-code:installed,codex:installed라고 보고했습니다. 묻는 절차는 없었습니다. 사용자의 전역 Codex 설정에는 Postman git 저장소를 가리키는 새 마켓플레이스, 활성화된 플러그인, 훅 신뢰 기록이 추가되었습니다. Claude Code 설정에는 활성화된 플러그인과 같은 시간대의 타임스탬프가 찍힌 설치 기록이 생겼습니다. ~/.local/bin에는 Postman CLI 바이너리가 나타났고, 원격 MCP 연결은 Postman 서버를 가리키도록 설정되었습니다. 그 연결은 인증에 실패하며 에러를 쏟아냈는데, 사용자가 이 모든 것을 알아챈 유일한 이유가 바로 그것이었습니다.
두 가지 세부 사항은 두 번 읽을 가치가 있습니다. 첫째, 설치된 세션 시작 훅은 에이전트에게 디자인, 테스트, 모킹, 문서화, 배포 등 사소하지 않은 API 엔지니어링 작업을 하기 전에 Postman 스킬을 로드하라고 지시합니다. 이건 요청에 따른 연동이 아닙니다. 한 애플리케이션이 다른 벤더 애플리케이션의 기본 동작을 다시 쓰는 것입니다. 둘째, 설치 프로그램의 소스 코드에는 훅의 해시를 가져와 에이전트의 신뢰 훅 상태에 upsert하는 코드가 명시적으로 들어 있습니다. 신뢰 메커니즘은 사용자가 훅을 승인하도록 만들어진 것입니다. 설치 프로그램이 자기 훅을 스스로 승인하는 것은 소프트웨어 버전으로 자기 권한 신청서에 직접 서명하는 것과 같습니다.
리포터는 신중했습니다. 신뢰 기록만으로는 누가 만들었는지 증명할 수 없다고 명시했고, 데이터 유출에 대한 주장도 하지 않았습니다. 그 절제 덕분에 리포트는 오히려 더 신뢰할 만합니다. 리포트가 증명하는 것만으로도 충분합니다. 관련 없는 도구의 무음 변경, 에이전트 세션 시작에 주입된 광범위한 행동 지시, 그리고 사용자 동의 장치를 우회하려는 시도입니다. 제가 해본 보안 검토에서 이 조합이 나왔다면, 그 제품은 조사가 끝날 때까지 전사 배포에서 즉시 제외됐을 겁니다.
API 클라이언트가 자격 증명 금고인 이유
많은 팀이 꾸준히 과소평가하는 부분입니다. API 클라이언트는 전송 버튼이 달린 텍스트 편집기가 아닙니다. 베어러 토큰, 세션 쿠키, mTLS 클라이언트 인증서, OAuth 클라이언트 시크릿, 서명된 요청 헤더가 모두 여기 있습니다. 데이터베이스 URL과 서드파티 키가 담긴 환경 변수도 여기에 붙여 넣어집니다. {{api_secret}} 같은 템플릿 문법을 쓰면, 해석된 값이 매 요청마다 앱을 거칩니다. 벤더의 텔레메트리 설계에 따라서는 그 값이 로깅 파이프라인까지 흘러갈 수도 있습니다. HIPAA 규정 준수를 조사하던 한 실무자는 바로 그런 사례를 보고했습니다. 아웃바운드 로깅 트래픽에서 해석된 시크릿 값을 발견했고, 그 엔드포인트를 차단하자 앱이 제대로 동작하지 않았다고 합니다. 모든 세부 사항을 독립적으로 검증할 수는 없지만, “유용한” 데스크톱 도구에서 제가 봐 온 패턴과 일치합니다. 기능이라는 이름으로 완전한 요청 로그를 전송하는 방식입니다.
이제 에이전트 관점을 더해봅시다. 도구가 코딩 에이전트에 플러그인을 설치하고 세션 훅을 등록하면, 그 도구의 지시문은 코드베이스를 읽고 셸 명령을 실행하며 자체 자격 증명까지 쥐고 있는 프로세스의 컨텍스트에 들어갑니다. 피해 범위는 더 이상 “내 API 컬렉션이 새는 것”이 아닙니다. “에이전트 환경에서 접근 가능한 모든 시크릿이, 나쁜 프롬프트 하나나 손상된 스킬 하나만큼만 잘못된 엔드포인트에 가까워진다”는 것입니다. 이전에 백그라운드 데몬을 설치하는 CLI 도구가 어떻게 조용히 공격 표면을 넓히는지 다룬 적이 있는데, 이것은 더 똑똑한 페이로드를 쓰는 같은 패턴입니다. ps에서 보이는 데몬은 다른 벤더의 신뢰 저장소 안에 숨어 있는 지시 훅에 비하면 오히려 예의 바른 편입니다.
위협 모델을 솔직하게 들여다보면 결론은 불편합니다. 데스크톱 API 클라이언트는 시크릿, 네트워크 접근, 그리고 점점 더 에이전트 제어 플레인이 교차하는 지점에 있습니다. 비밀번호 관리자나 CI 러너와 같은 수준의 검토를 받아야 합니다. 그런데 그런 검토를 받는 경우는 거의 없습니다. 이 사건이 악용한 빈틈이 바로 그것이고, 대응이 감정적이기만 해서는 안 되고 절차적이어야 하는 이유입니다.
벤더 옵트아웃과 설정 토글이 실패하는 이유
이런 사건 후 가장 먼저 드는 생각은 앱 환경설정에서 텔레메트리 토글을 찾아 끄고 넘어가자는 것입니다. 저는 실제로 팀 전체가 그렇게 하고 이것을 조치라고 부르는 것을 봤습니다. 세 가지 이유로 그것은 쇼입니다.
- 동의는 버전에 따라 달라질 수 있습니다. Postman 설치는 로그인된 기존 계정의 기능 플래그에 의해 트리거되었습니다. 지금 있는 토글이 내일 어떤 플래그가 배포될지 알려주지 않으며, 자동 업데이터 때문에 내일은 묻지도 않고 찾아옵니다.
- 토글은 가능한 것이 아니라 문서화된 것을 다스립니다. 개인정보 설정은 벤더가 노출하기로 한 코드 경로만 제어합니다. 플러그인 설치 프로그램은 문서화된 환경 설정이 아니라 스크립트로 된 업그레이드 경로였습니다. 보이지 않는 스위치는 끌 수 없습니다.
- 신뢰 결정은 앱 바깥에서 이뤄집니다. 훅 승인 시도는 Postman이 아니라 Codex의 설정 안에서 일어났습니다. 원본 앱의 설정 패널이 아무리 완벽해도 이것을 드러내지 못했을 것입니다.
더 깊은 실패는 구조적입니다. 옵트아웃은 경계 의식의 부담을 가장 적은 정보를 가진 쪽에 떠넘깁니다. 벤더는 업데이터가 무엇을 할 수 있는지 알지만, 여러분은 모릅니다. 벤더는 앱이 어떤 엔드포인트로 연결되는지 알지만, 여러분은 추측해야 합니다. 정보가 적은 쪽이 정보가 많은 쪽을 계속 앞질러 조사해야 하는 통제는 결국 실패합니다. 이것이 IDE 플러그인 마켓플레이스의 신뢰 문제가 계속 사람들을 무는 이유이기도 합니다. 여러분이 관리한다고 생각하는 보안 경계가 실제로 넘어가고 있는 경계가 아닌 것입니다.
벤더 신뢰가 무의미한 것은 아닙니다. 다만 통제 수단이 될 수는 없습니다. 무엇을 설치할지 결정할 때 고려하는 요소이지, 설치된 소프트웨어를 정직하게 유지하는 장치가 아닙니다. 이것을 내면화하면 감사 전략은 저절로 정해집니다. 벤더가 통제하지 않는 도구로, 바깥에서 행동을 지속적으로 검증하는 것입니다.
일회성 보안 감사도 실패하는 이유
두 번째 실패한 시도는 더 그럴듯해 보입니다. 바로 시점 감사입니다. 보안팀이 도구를 검토하고, 네트워크 호출을 확인하고, 개인정보 처리방침을 읽고, 승인을 내리고, 보고서를 보관합니다. 끝입니다. 자동 업데이터가 돌기 전까지는요. 데스크톱 개발 도구는 이제 주간, 심지어 일간 주기로 배포되고, 기능 플래그 때문에 같은 버전 번호를 쓰는 두 사용자가 실제로는 상당히 다른 코드를 실행할 수 있습니다. 이번 사건의 동작은 서버 측 플래그와 “기존 사용자” 조건 뒤에 숨어 있었습니다. 즉 보안팀이 검토한 깨끗한 신규 설치본은 완벽해 보이는데, 오래 쓰던 사용자는 플러그인 세례를 받을 수 있다는 뜻입니다.
저도 정확히 이 빈틈에 데인 적이 있습니다. 몇 년 전 철저한 검토 끝에 동기화 클라이언트를 승인했습니다. 트래픽 캡처도 깨끗했고, 권한도 합리적이었고, 지속성 메커니즘도 없었습니다. 6개월 뒤 업데이트에서 LaunchAgent와 소켓 리스너가 추가되었습니다. 발견한 계기는 불안정한 VPN을 쓰던 노트북의 방화벽 로그에 이상한 연결 재시도가 계속 찍혔기 때문이었습니다. 아무도 다시 검토하지 않았습니다. 다시 검토하라고 알려주는 프로세스가 없었으니까요. 승인은 스냅샷이었고, 소프트웨어는 영화였습니다.
그래서 두 가지 값싼 해법은 모두 실패합니다. 벤더의 설정을 믿는 것은 흥미로운 동작이 설정에 없기 때문에 실패하고, 일회성 감사는 흥미로운 동작이 감사 이후에 배포되기 때문에 실패합니다. 효과가 있는 방법은 자신의 컴퓨터 상태를 진실의 원천으로 삼고 그 변화를 지켜보는 것입니다. 조달 검토보다 덜 화려하지만, 의도가 아니라 현실을 포착합니다.

데스크톱 개발 도구를 제대로 감사하는 방법
실용적인 접근법은 세 가지 축으로 이뤄집니다. 중요한 상태를 스냅샷으로 남기고, 네트워크를 지켜보고, 완전히 검증할 수 없는 것은 격리하는 것입니다. 엔터프라이즈급 도구는 필요 없습니다. 필요한 것은 규율과 한 시간 정도의 설정 작업입니다.
설정 스냅샷으로 무음 플러그인 설치 탐지하기
여러분 컴퓨터의 모든 코딩 에이전트와 개발 도구에는 동작을 정의하는 작은 파일 묶음이 있습니다. ~/.codex/config.toml, ~/.claude/settings.json과 플러그인 디렉터리, MCP 설정, 셸 rc 파일, ~/Library/LaunchAgents, ~/.local/bin 등입니다. 이 파일들이 바로 동의의 경계입니다. 묻지 않고 이 파일들을 바꾸는 무엇이든 여러분이 잡으려는 대상입니다. 그러니 매일 해시를 떠서 비교하세요.
#!/usr/bin/env bash
# snapshot-agent-configs.sh — hash every file your agents and shells read,
# then diff against yesterday. Run from cron or launchd.
set -euo pipefail
SNAP_DIR="$HOME/.config-audit"
mkdir -p "$SNAP_DIR"
TODAY="$SNAP_DIR/$(date +%F).txt"
find \
"$HOME/.codex" \
"$HOME/.claude" \
"$HOME/.config" \
"$HOME/.local/bin" \
"$HOME/Library/LaunchAgents" \
-type f 2>/dev/null \
| sort \
| xargs shasum -a 256 > "$TODAY"
PREV=$(ls -t "$SNAP_DIR"/*.txt 2>/dev/null | sed -n '2p' || true)
if [ -n "${PREV:-}" ]; then
if ! diff -u "$PREV" "$TODAY" > "$SNAP_DIR/latest.diff"; then
echo "config drift detected — see $SNAP_DIR/latest.diff" \
| mail -s "agent config drift" you@example.com || \
cat "$SNAP_DIR/latest.diff"
fi
fi
투박하지만 괜찮습니다. 리포터의 컴퓨터에서 이것이 돌고 있었다면, 다음 날 아침 하나의 diff에서 Codex config.toml 변경, 새 Claude 플러그인 기록, ~/.local/bin의 CLI 바이너리가 모두 드러났을 겁니다. 이 디렉터리들은 평소에 조용하기 때문에 신호 대 잡음비가 아주 좋습니다. 합법적인 변경은 여러분 자신의 수정뿐이고, 언제 수정했는지도 알고 있으니까요. 같은 스냅샷에 launchctl list | grep -v com.apple 출력을 함께 넣으면, 지속성 메커니즘이 나타나는 날 바로 잡아낼 수 있습니다.
파일만이 아니라 네트워크 송신도 지켜보기
파일 무결성은 디스크에서 무엇이 바뀌었는지 알려주지만, 무엇이 밖으로 나갔는지는 알려주지 않습니다. 송신을 보려면 애플리케이션별 가시성이 필요합니다. macOS에서는 Little Snitch나 오픈소스 방화벽 LuLu가 프로세스별 새 아웃바운드 연결을 알려줍니다. Postman 업데이터나 새 CLI 바이너리가 낯선 호스트에 처음 접근할 때 기정사실이 아니라 확인 창을 띄울 것입니다. 리눅스에서는 opensnitch가 같은 역할을 합니다. 수다스러운 앱이 지금 무엇을 하는지 수동으로 확인하고 싶다면:
# Every established outbound connection, grouped by process
sudo lsof -iTCP -sTCP:ESTABLISHED -P -n | awk '{print $1, $9}' | sort | uniq -c | sort -rn
# Watch one vendor's traffic live (find the process name first)
sudo tcpdump -i any -n host mcp.postman.com
확인할 것은 두 가지입니다. 도구의 명시된 기능과 전혀 관계없는 목적지, 그리고 앱이 유휴 상태일 때도 유지되는 연결입니다. HTTP 클라이언트는 전송 버튼을 누르지 않을 때 조용해야 합니다. 텔레메트리 엔드포인트 자체가 자동으로 유죄는 아닙니다. 하지만 앞서 소개한 HIPAA 조사 사례가 보여주듯 중요한 것은 페이로드입니다. 클라이언트가 {{secrets}}를 클라이언트 측에서 해석하고 서버 측에 전체 요청 세부 정보를 기록한다면, “익명 사용 데이터”는 익명이 아닙니다. 알아내는 유일한 방법은 캡처해서 읽는 것입니다. 가능하면 카나리 토큰, 즉 고유한 가짜 자격 증명을 환경 변수에 의도적으로 넣고, 그것이 가면 안 되는 곳으로 이동하는지 지켜보세요. 카나리 토큰은 “그럴지도 모른다”를 “그랬다는 걸 안다”로 바꿔 줍니다.
완전히 신뢰할 수 없는 것은 격리하기
마지막 축은 모든 것을 잡아낼 수 없다는 전제를 받아들입니다. 그래서 피해 범위를 제한해야 합니다. 자격 증명을 많이 쓰는 도구는 전용 OS 사용자 계정이나 가벼운 VM에서 실행해서 파일 시스템 접근이 샌드박스 경계에서 멈추게 하세요. macOS와 리눅스 모두 두 번째 사용자 계정을 만드는 것은 쉽고, 리눅스에서는 firejail 같은 도구로 애플리케이션별로 디렉터리 트리 전체를 차단할 수 있습니다. 실제 운영 시크릿은 데스크톱 도구에 아예 두지 마세요. 수명이 짧은 토큰, 범위가 제한된 서비스 계정, 만료되는 요청 서명을 사용하세요. 도구가 쓸모 있으려면 장기 운영 자격 증명을 요구한다면, 그 요구 자체가 하나의 발견입니다. 실패의 비용이 클 때는 모니터링보다 격리가 낫다는 얘기는 이미 여러 번 한 적이 있습니다. 에이전트와 에이전트를 설정하는 도구에게 격리는, 모니터링에 사각지대가 생기는 날에도 여전히 작동하는 계층입니다.
도구 사고를 위한 롤백 플레이북
무언가를 발견했을 때, 문제 앱을 지우는 것은 약 여섯 단계 중 첫 번째일 뿐입니다. Postman 리포터의 제거 체크리스트는 올바른 형태이니, 필요해지기 전에 익혀 두세요.
- 증거를 먼저 보존하세요. 제거 전에 로그, 설정, 버전 번호를 안전한 곳에 복사하세요. 이번 건에서 Postman 자체의 main.log가 결정적 증거였습니다. 제거 스크립트는 이런 파일을 지우기를 좋아합니다.
- 앱과 헬퍼를 제거하세요. 앱 번들과,
~/.local/bin, Application Support, 캐시에 떨어뜨린 모든 파일을 지우세요. - 에이전트 설정을 정리하세요. 가장 눈에 띄는 호스트만이 아니라 모든 에이전트 호스트에서 마켓플레이스 항목, 활성화된 플러그인 블록, MCP 서버 정의, 캐시된 플러그인 디렉터리를 제거하세요.
- 신뢰 기록을 취소하세요. 승인하지 않은 훅의
trusted_hash항목을 삭제하세요. 그런 다음 같은 파일의 다른 훅도 감사하세요. 하나가 몰래 들어왔다면 나머지도 확인해야 합니다. - 지속성을 확인하세요. LaunchAgent, LaunchDaemon, 로그인 항목, cron 항목, 셸 rc 추가 내용을 살피세요.
- 그것을 거쳐 간 자격 증명을 교체하세요. 도구의 환경이나 컬렉션에 있던 자격 증명은 모두 노출된 것으로 간주하세요. 교체는 귀찮지만, 사고 대응은 더 귀찮습니다.
- 제거가 확실한지 검증하세요. 스냅샷 스크립트를 몇 주 동안 계속 돌리세요. 다른 플래그로 재설치하는 것은 알려진 패턴입니다.
목록에 없는 것도 있습니다. 티켓을 올리고 기다리는 것입니다. 그것도 하세요. 공개적이고 증거가 충분한 리포트가 나머지 사람들이 사실을 알게 되는 방법입니다. 하지만 여러분의 기본 위생이 벤더의 로드맵에 달려 있으면 안 됩니다.

개발자 도구 보안에 대한 더 큰 교훈
이 이야기를 한 회사의 행보에 관한 것으로만 만들고 싶은 유혹이 있습니다. 가볍고 사랑받던 도구가 수억 달러를 투자받고, 많은 인력을 고용하고, 이제는 로그인, 구독, 그리고 모든 것에 붙은 AI로 수십억 달러 규모의 기업가치를 정당화해야 하는 상황입니다. 그 서사는 만족스럽고 대체로 사실이지만, 나머지 우리를 너무 쉽게 면책해 줍니다. 같은 인센티브 구조가 이제 여러분 컴퓨터의 절반 가까운 도구 밑에 깔려 있습니다. AI 이야기를 가진 모든 벤더는 자신의 플러그인을 여러분의 에이전트에, 자신의 MCP 서버를 여러분의 설정에, 자신의 훅을 여러분의 세션 시작에 넣고 싶어 합니다. 일부는 물어볼 것입니다. 증거는 적어도 한 곳이 묻는 것을 선택 사항으로 여겼다고 말합니다.
시장의 반응은 이미 보이고, 그것은 교훈적입니다. Bruno, Kreya, Yaak 같은 오프라인 우선, Git 기반 API 클라이언트가 주목받고 있습니다. 신뢰 모델이 명확하기 때문입니다. 저장소 안의 파일, 여러분의 컴퓨터에서 나가는 요청, 계정 불필요. 도구의 저장 형식이 텍스트 파일 폴더라면, 감사는 git diff입니다. 이건 향수가 아니라 보안 아키텍처입니다. LiteLLM 공급망 사고도 패키지 레지스트리 쪽에서 같은 교훈을 줬습니다. 검사할 수 있고 고정할 수 있는 산출물만이 방어할 수 있습니다.
기능 플래그에 머무는 동의는 동의가 아닙니다. 도구가 버전 번호를 바꾸지 않고도 동작을 바꿀 수 있다면, 그 도구에 대한 여러분의 승인은 아무 의미가 없습니다.
그래서 제가 옹호할 입장은 이것입니다. 데스크톱 개발 도구를 기능으로 평가하는 것을 멈추고, 되돌릴 수 있는지로 평가하기 시작하세요. 도구가 무엇을 쓰는지 볼 수 있나요? 설정을 diff할 수 있나요? 계정 없이, 오프라인으로, 로그를 남기는 방화벽 뒤에서 실행할 수 있나요? 자기 디렉터리 밖에 건드린 것까지 포함해 완전히 제거할 수 있나요? 이 질문을 통과하는 도구는 대체로 평범합니다. 그리고 여러분의 자격 증명과 네트워크 사이에 서 있어야 하는 것이 바로 평범함입니다. 이 질문에 실패하는 도구는, 자동완성이 아무리 좋아도 샌드박스 안이나 머신 밖에 있어야 합니다. API 클라이언트는 자격 증명 금고입니다. 이제 그렇게 다루기 시작하세요. 벤더들은 이미 그렇게 하고 있으니까요. 다만 여러분이 바라는 방식은 아닐 뿐입니다.


