AI 코딩 에이전트는 .env를 읽는다 — OpenAI도 10개월째 못 막은 문제

AI 코딩 에이전트 .env 시크릿 노출 — Codex 민감 파일 문제

AI 코딩 에이전트는 .env를 읽는다 — OpenAI도 10개월째 못 막은 문제

AI 코딩 에이전트한테 저장소를 통째로 맡기는 사람이 늘었다. 그런데 그 저장소 안에는 보통 .env가 같이 들어 있다.

내 경우엔 시크릿이 새는 걸 막는 보안 훅이 오타 하나로 몇 달간 돌지 않고 있었다. 그동안 에이전트가 키 파일을 읽어도 걸러낼 장치가 없었다는 뜻이다.

결론부터 적으면, .gitignore로는 에이전트한테 시크릿을 숨기지 못한다. 막아야 할 지점은 파일이 아니라 도구 호출이다.

이 글은 그 이유를 OpenAI Codex의 공개 이슈 하나로 짚고, 내 설정에서 .env가 읽히는지 확인하는 법까지 정리한다. AI 코딩 에이전트 보안에서 가장 자주 새는 구멍이 여기다.

다음 중 하나라도 해당되나

.env.gitignore에 넣었으니 안전하다고 생각한 적이 있다.

에이전트한테 “이 디렉터리 전체를 분석해줘”라고 시켜 본 적이 있다.

API 키나 토큰을 프로젝트 루트의 설정 파일에 그대로 둔 적이 있다.

셋 중 하나라도 해당되면 이 글이 짚는 위험에 노출돼 있다. 왜 그런지는 에이전트가 파일을 읽는 방식을 보면 바로 드러난다.

에이전트가 파일을 읽는 방식

깃과 에이전트는 파일을 보는 길이 다르다.

.gitignoregit add 단계에서만 작동한다. 깃이 추적하지 않을 파일을 지정할 뿐이다.

반면 코딩 에이전트는 깃을 거치지 않는다. rg(ripgrep)나 grep, cat 같은 도구를 직접 호출해서 파일 시스템을 읽는다. 에이전트 입장에서 .env는 그냥 텍스트 파일 하나일 뿐이고, 깃이 무시하든 말든 상관이 없다.

그래서 “민감 파일을 .gitignore에 넣어 뒀으니 에이전트도 안 읽겠지”라는 가정이 깨진다. 에이전트가 코드 검색을 하다가 .env 안의 문자열이 검색어에 걸리면, 그 내용은 도구 출력으로 모델에 전달된다. 모델에 전달된다는 건 외부 서버로 전송된다는 뜻이다.

핵심은 차단 지점이다. 파일에 “읽지 마”라고 표시하는 방식은 에이전트가 그 표시를 존중할 때만 통한다. 존중하지 않으면 무력하다.

OpenAI Codex가 10개월째 못 막은 것

이게 특정 도구의 사소한 버그가 아니라는 증거가 OpenAI Codex 저장소에 있다.

openai/codex 저장소의 이슈 2847번, 제목은 “A way to exclude sensitive files”다. 2025년 8월 28일에 열렸고, 2026년 6월 현재까지 OPEN 상태다.

약 10개월째 미해결이고 댓글은 87개가 달렸다. “민감 파일을 제외할 방법을 달라”는 요청이 이만큼 오래 방치돼 있다.

이슈 안의 한 댓글이 문제의 본질을 정확히 짚는다. 테스트해 보니 .gitignoreAGENTS.md로도 Codex가 파일을 OpenAI로 올리는 걸 막을 수 없었고, Codex가 rggrep을 써서 관련 내용을 찾으면 그대로 업로드된다는 것이다.

이 댓글에는 공감이 40개 넘게 달렸다. 또 다른 댓글은 “2026년인데 반년 넘게 통째로 무시됐다”고 적었고 여기에도 30개 넘는 공감이 붙었다.

물론 이건 Codex 한 도구의 이슈다. 모든 에이전트가 똑같이 동작한다고 단정할 근거는 이 이슈만으로는 부족하다.

다만 차단 지점이 파일 표시가 아니라 도구 호출이라는 구조는 도구를 가리지 않는다. 그래서 “내 도구는 괜찮겠지”가 아니라 “내 도구에서 직접 확인하자”가 맞는 태도다.

제각각인 차단 규칙

같은 문제를 두고 도구마다 다른 파일을 쓴다.

이슈 토론에서 한 참여자가 정리한 바로는, 차단 규칙 파일이 도구별로 따로 논다. 표준이 없다 보니 도구를 바꿀 때마다 새 파일을 만들어야 한다.

도구 민감 파일 제외 수단 표준
OpenAI Codex 전용 수단 없음 (이슈 2847 미해결)
Cline .clineignore 자체
Cursor .cursorignore, .cursorban 자체
제안 단계 .agentignore (도구 공용) 미채택

AGENTS.md가 여러 도구에 공통으로 받아들여진 것처럼 .agentignore 같은 공용 규칙을 두자는 제안이 가장 많은 공감을 받았다. 하지만 아직 채택된 표준은 아니다. 지금은 각자 자기 파일 이름으로 막는 단계다.

여기서 한 가지를 짚어야 한다. 이런 제외 파일조차도 결국 “에이전트가 이 규칙을 존중한다”는 전제 위에서만 작동한다.

위의 Codex 댓글처럼 에이전트가 규칙을 우회해 파일을 읽으면 제외 파일도 소용이 없다. 그래서 이건 1차 방어일 뿐이다.

그럼 어떻게 확인하나

내 설정에서 직접 시험해 보는 게 유일하게 확실한 방법이다.

먼저 안전한 더미 값으로 가짜 .env를 하나 만든다. 진짜 키는 쓰지 않는다. 예를 들어 FAKE_SECRET=canary_test_value_123 한 줄이면 된다.

그다음 에이전트한테 “이 프로젝트에서 API 설정을 찾아줘” 정도의 평범한 작업을 시킨다. 에이전트가 .env를 읽거나 그 안의 더미 값을 출력에 드러내면, 실제 시크릿도 같은 경로로 샌다는 뜻이다.

한 가지는 짚고 가야 한다. 출력에 더미 값이 안 보인다고 안전한 게 아니다. 에이전트가 파일을 읽어 모델에 넘기고도 화면에는 그 값을 안 보여줄 수 있다.

그래서 값이 노출되는지만 볼 게 아니라, 에이전트가 그 파일에 접근하는지 자체를 봐야 한다. 도구 호출 로그가 보이는 환경이라면 .env를 읽는 cat이나 rg 호출이 찍히는지 확인하는 편이 더 확실하다.

막는 방향은 두 갈래인데, 둘의 신뢰도가 다르다. 하나는 도구가 제공하는 제외 파일이다.

손은 덜 가지만, 앞서 봤듯 이건 .gitignore와 같은 약점을 공유한다. 에이전트가 그 규칙을 존중할 때만 작동한다는 것이다. 그래서 편의상의 1차 방어일 뿐 보장이 아니다.

다른 하나는 그 약점이 없는 방법이다. 에이전트가 도구를 호출하는 순간 그 호출을 가로채, 민감 파일 접근이면 실행 전에 거부하는 방식이다.

파일에 “읽지 마”라고 표시하는 게 아니라, 읽으려는 행위 자체를 끊는다. 선언적 차단은 에이전트의 협조에 기대지만, 실행 차단은 협조가 필요 없다.

나는 후자 방식으로 차단 훅을 만들어 시크릿 샘플 여러 개로 통과·차단을 검증해 뒀다. 그 과정에서 겪은 시행착오(작동하는 줄 알았던 훅이 사실은 죽어 있던 일)는 AI 코딩 설정도 코드처럼 썩는다에 따로 적었다.

핵심만 옮기면, “차단 장치가 있다”와 “차단 장치가 작동한다”는 다른 말이고, 시크릿 샘플을 넣어 실제로 막히는지 본 뒤에야 후자를 말할 수 있다.

마무리

AI 코딩 에이전트의 시크릿 노출은 화려한 해킹이 아니라 구조의 문제다. 깃이 무시하는 파일과 에이전트가 읽는 파일이 다른 길에 있을 뿐인데, 그 틈으로 키가 샌다. OpenAI조차 10개월 동안 못 막고 있다는 건, 이게 누가 게을러서 생긴 일이 아니라는 신호다.

오늘 할 일은 하나다. 가짜 .env를 만들어 내 에이전트가 그걸 읽는지 직접 확인하는 것.

막연히 안전하다고 믿는 것보다, 한 번 시험해 보고 새는 지점을 눈으로 보는 편이 낫다. 확인하고 나면 제외 파일로 급한 불은 끄되, 정말 지켜야 할 키는 실행 차단까지 가는 게 일관된 선택이다.

관련 글


글쓴이 · 8년 차 프론트엔드 개발자로 일하다 나와, 지금은 AI 코딩 에이전트와 자동화 도구를 직접 만들며 쓴다. trend-scout를 1년 넘게 운영하고 있고, Claude Code 설정과 보안 훅을 실제로 깨뜨려 보고 고치는 과정을 블로그에 기록한다. 이 글의 근거는 공개된 Codex 이슈와, 내가 직접 시크릿 샘플로 차단 훅을 검증한 경험이다.

태그: #AI코딩에이전트 #Codex #시크릿노출 #env보안 #ClaudeCode #gitignore #개발자보안 #AI도구분석

댓글

이 블로그의 인기 게시물

맥 스튜디오 M4 Max 128GB 로컬 LLM 4개 속도 비교 — gemma4·llama3.3·qwen3 실측

Claude Opus 4.7 출시 총정리 — 뭐가 달라졌고 지금 써야 하나

Claude Code로 블로그 발행 15분을 1줄로 — 해고 후 첫 자동화 경험