Claude Code가 실행한 명령의 비밀번호가 ps에 그대로 남는다

V2EX2026-11-03

AI 코딩 에이전트에 데이터베이스 접속을 맡길 때 자격 증명이 어디까지 노출되는지를 직접 확인한 사례가 공유됐다. 요지는 curl 자체가 아니라 그 명령을 감싸서 실행하는 바깥 셸이다. curl은 자신의 인자에서 비밀번호를 지우지만, Claude Code가 띄운 상위 셸 프로세스에는 명령 전문이 그대로 남는다.

작성자는 Mac에서 Claude Code 2.1.317로 가짜 비밀번호가 들어간 curl 명령을 실행하고 다른 프로세스에서 ps를 캡처했다. 결과는 두 줄이었다. 하나는 `source ~/.claude/shell-snapshots/… && eval 'curl … -u demo:FAKEPASS123 …'` 형태의 zsh 프로세스로 비밀번호가 그대로 보였고, 다른 하나는 curl 자신으로 해당 자리가 공백으로 지워져 있었다. 사용자가 `bash -c 'curl …'`처럼 단일 명령만 직접 실행하면 bash가 exec로 curl이 되어 이 층이 생기지 않지만, Claude Code는 스냅샷 로드와 eval을 엮은 복합 명령을 쓰기 때문에 셸이 자식 프로세스를 기다리며 계속 남는다.

노출 경로는 ps만이 아니다. 실행된 명령은 `~/.claude/projects/` 아래 jsonl 세션 기록에도 원문 그대로 저장된다. 작성자는 자신의 세션 기록 253개 중 16개에서 `mysql -p 비밀번호`, `curl -u 사용자:비밀번호` 같은 형태를 찾았고 셸 히스토리에서도 8줄이 걸렸다고 밝혔다. 다만 사용한 정규식이 거칠어 누락과 오탐이 모두 가능하다고 스스로 전제했다.

공용 개발 서버나 점프 호스트에서 문제가 커진다. Linux 기본 마운트 옵션에서 proc(5)는 모든 /proc/pid 디렉터리에 누구나 접근할 수 있다고 설명하며, 같은 머신의 다른 사용자가 명령줄을 읽을 수 있다. 반면 `/proc/pid/environ`은 ptrace 권한 검사를 통과해야 읽힌다. 각 도구도 이미 이 위험을 문서에 적어 두었다. MySQL은 명령줄의 `-p 비밀번호`를 편하지만 안전하지 않다고 보고 MYSQL_PWD를 매우 안전하지 않은 방식으로 규정했으며 8.4에서 폐기를 예고했다. PostgreSQL은 PGPASSWORD 대신 `~/.pgpass`를 쓰도록 하고 파일 권한이 0600보다 넓으면 읽지 않는다. curl의 `-u`도 가릴 수 있는 곳은 가리지만 같은 머신의 다른 사용자까지 막지는 못한다고 매뉴얼이 밝힌다.

실무 대응은 두 갈래다. `~/.my.cnf`와 `~/.pgpass`를 각각 설정하고 권한을 600으로 두는 것이 첫째다. 둘째는 에이전트 지침 파일인 CLAUDE.md나 AGENTS.md에 비밀번호를 명령 인자에 넣지 말고 클라이언트 설정 파일을 쓰라는 규칙을 명시하는 것이다. 이미 세션에 들어간 비밀번호는 교체해야 한다. jsonl을 지워도 해당 내용은 이미 모델로 전송된 뒤다.

작성자가 쓰는 별도 실행 도구는 비밀 값을 자식 프로세스의 환경변수로만 넘겨 ps와 세션 기록에는 항목 이름만 남긴다. 그러나 이것도 은탄환이 아니라고 선을 긋는다. 같은 사용자 권한으로 도는 악성 프로그램은 환경변수와 파일을 여전히 읽을 수 있고, MySQL이 공식적으로 더 권하는 것은 0600 설정 파일이다. 환경변수도 프로세스 시작 직후 해제하지 않으면 읽힐 수 있고, 바깥에 셸을 한 겹 더 씌우는 방식으로는 명령줄 노출이 그대로 유지된다.

댓글에서는 에이전트와 미들웨어 사이에 경계를 두자는 제안이 나왔다. Go로 MCP 서버를 만들어 AI가 요청한 조작을 사람이 확인한 뒤 실행하게 하거나, 에이전트가 DB 같은 미들웨어에 직접 붙지 못하도록 MCP나 CLI 프록시를 앞단에 두는 구성이다.