.env
키를 커밋한 후에 지우는 것은 어렵습니다(이전 글). 커밋 직전에 막으려면, gitleaks를 pre-commit 훅에 넣는 것이 간편했습니다. 가짜 GitHub 토큰을 포함하는 .env 파일은 훅에서 커밋이 중단되었습니다(작성자 환경에서 확인).
다만,
gitleaks는 토큰 형태의 값만을 찾는 도구이며, .env라는 파일 자체는 막지 못합니다. DB_PASSWORD=...와 같은 평문 비밀번호만 있는 .env는 그대로 통과했습니다(작성자 환경에서 확인). 파일명 체크를 몇 줄 추가하니 막혔습니다.
(git 공식 문서 및 실기 모두 확인). AI 에이전트에게 커밋을 맡길 거라면, GitHub의 push protection도 함께 사용하는 것이 안전합니다. git commit --no-verify를 붙이면 훅은 건너뛰어집니다.
이 글은 AI 에이전트와 비밀 정보에 대한 이야기의 연속입니다. 에이전트에게 git add .과 git commit을 맡기면, .gitignore에 누락된 것이 그대로 히스토리에 남게 됩니다. 지난번에는 들어가 버린 후 찾는 방법과 지우는 방법을 확인했으므로, 이번에는 들어오기 전에 막는 쪽을 확인합니다.
- Debian 13 / git 2.47.3 / gitleaks 8.30.1 (GitHub Releases의 바이너리. checksums.txt에서 sha256 확인)
- 일회용 로컬 리포지토리만으로 테스트했습니다. GitHub로 push하지 않았습니다.
- 토큰은 임의로 만든 가짜이며, 비밀번호는 더미 문자열입니다. 출력 값은 gitleaks의
--redact로 가려두었습니다.
스테이징된 .env 파일에 가짜 GitHub 토큰(ghp_으로 시작하는 형태), 가짜 OpenAI 키(sk-proj-으로 시작하는 형태), DB_PASSWORD=dummy-not-a-secret을 작성하여 시도했습니다.
git add .env
gitleaks git --pre-commit --staged --redact -v .
echo "exit=$?"
결과 (발췌):
Finding: GITHUB_TOKEN=REDACTED
RuleID: github-pat
File: .env
...
- GitHub 토큰은 전용 규칙(
github-pat)으로, OpenAI 형태의 가짜 키는 범용 규칙(generic-api-key)으로 발견되었습니다. - 3번째 줄의 DB_PASSWORD=dummy-not-a-secret은 감지되지 않았습니다. - 발견되면 종료 코드가 1이 됩니다. 이를 훅에 사용합니다.
가장 간단한 방법은 .git/hooks/pre-commit에 직접 작성하는 것입니다.
#!/bin/sh
gitleaks git --pre-commit --staged --redact --no-banner . || {
echo "gitleaks: 비밀 정보로 추정되는 값이 발견되어 커밋을 중단했습니다" >&2; exit 1; }
chmod +x .git/hooks/pre-commit
git commit -m "add env"; echo "exit=$? HEAD=$(git log --oneline -1)"
WRN leaks found: 2
gitleaks: 비밀 정보로 추정되는 값이 발견되어 커밋을 중단했습니다
exit=1 HEAD=2332163 init
커밋은 생성되지 않았고, HEAD는 첫 번째 커밋 상태를 유지했습니다(작성자 환경에서 확인).
팀원들과 공유하고 싶다면, gitleaks의 README에 pre-commit 프레임워크용 설정 예시가 있습니다(repo: https://github.com/gitleaks/gitleaks, id: gitleaks). 또한, git config core.hooksPath <디렉토리>로 훅의 위치를 리포지토리 내 디렉토리로 변경할 수도 있습니다(git 공식 문서). 이 두 가지는 이번에는 시도하지 않았습니다.
다음으로, 토큰 형태가 아닌 값만 있는 .env 파일을 시도했습니다.
DB_PASSWORD=dummy-not-a-secret
SECRET_KEY=change-me-dummy
INF no leaks found
[main f652d7e] plain env
1 file changed, 2 insertions(+)
...
gitleaks의 후크가 있어도 커밋되었습니다(필자의 환경에서 확인). gitleaks는 값의 형태나 규칙으로 판별하기 때문에, .env라는 파일 이름만으로는 막을 수 없습니다. 실제 비밀번호가 더미와 같은 '형태 없는 문자열'이라면, 마찬가지로 통과할 가능성이 높습니다(추측).
.env와 .env.local 등은 파일 이름으로 거부하고, .env.example 같은 템플릿만 통과하도록 했습니다.
#!/bin/sh
if git diff --cached --name-only --diff-filter=ACMR \
| grep -E '(^|/)\.env($|\.)' \
...
.env
위의 .env 파일은 커밋하지 마세요(.gitignore에 추가해 주세요)
exit=1 HEAD=2332163 init
.env는 막혔고, 같은 내용의 .env.example은 커밋할 수 있었습니다(필자의 환경에서 확인). 만약 .env.example에 실제 값을 작성했다면, 이 파일 이름 체크로는 막을 수 없습니다. 토큰 형태라면 gitleaks 측에서 막힙니다.
후크는 로컬 메커니즘이므로, 건너뛸 수도 있습니다.
git commit -q --no-verify -m "add env (no-verify)"; echo "exit=$? HEAD=$(git log --oneline -1)"
exit=0 HEAD=7f6e444 add env (no-verify)
가짜 토큰이 들어간 .env가 그대로 커밋되었습니다(필자의 환경에서 확인). git 공식 문서에도 --no-verify는 pre-commit과 commit-msg 후크를 건너뛴다고 쓰여 있습니다. pre-commit 프레임워크 경유라면, SKIP=gitleaks로도 건너뛸 수 있습니다(gitleaks README).
AI 에이전트에게 커밋을 맡길 경우, 에이전트가 후크 실패를 보고 --no-verify를 추가할 수도 있습니다(추측. 이번에는 에이전트로 시도하지 않았습니다). 에이전트의 지시나 설정에서 --no-verify를 금지해 두는 것이 안전합니다.
GitHub에는 push 시점에서 비밀 정보를 막는 push protection 기능이 있습니다(GitHub 공식).
- 사용자 대상 push protection은 GitHub.com에서 기본적으로 활성화되어 있으며, 공개 리포지토리로의 secret push를 막습니다. -
리포지토리 대상 push protection은 기본적으로 비활성화되어 있으며, GitHub Secret Protection이 필요합니다. - 둘 다 이유를 지정하여 bypass(통과)할 수 있습니다.
후크는 로컬에서 건너뛸 수 있으므로, 서버 측의 이 메커니즘과 이중으로 설정해 두는 것이 좋을 것 같습니다. 다만, 둘 다 토큰 형태로 판별한다는 점은 같으므로, 평문 비밀번호나 .env 자체를 막고 싶다면, 4장의 파일 이름 체크와 .gitignore가 필요합니다(추측 포함).
gitleaks는 히스토리 전체도 조사할 수 있습니다. 토큰을 포함하는 파일을 커밋하고 다음 커밋에서 삭제한 리포지토리로 시도했습니다.
gitleaks git --redact .
gitleaks git --redact -r - -f csv . | cut -d, -f1-6
INF 3 commits scanned.
WRN leaks found: 1
RuleID,Commit,File,SymlinkFile,Secret,Match
...
지금은 이미 없는 파일이라도, 어느 커밋에 들어 있었는지 알 수 있었습니다(필자의 환경에서 확인). 발견된 경우, 먼저 키를 재발급한 후, 지난 글의 절차대로 히스토리에서 삭제해 주세요.
- gitleaks의 pre-commit hook에서 토큰 형식의 값을 포함하는 커밋은 중단되었다 (실제 환경).
- 평문 비밀번호만 있는
.env는 통과했다. 파일명 체크를 추가하니 중단되었다 (실제 환경). -
--no-verify로 hook은 건너뛴다 (실제 환경, git 공식).
GitHub의 push protection과 이중으로 적용한다 (공식).
AI 에이전트 측에서는 다음 설정도 함께 진행해 주세요.
- Claude Code: settings.json의 permissions.deny
- Codex CLI: permission profile의 deny
- 어떤 에이전트가
.env를 읽을 수 있는지 점검: 파일명만으로 점검하는 일본어 CLI
관련 기사:
- 과거에 커밋한 .env는 git 기록에서 읽을 수 있다: 찾는 방법과 git-filter-repo로 삭제하는 방법
- Codex CLI에 .env를 읽지 못하게 설정: 공식 예시의 "**/*.env"만으로는 .env.local 및 깊은 계층이 읽혔다
- Claude Code에 .env를 읽지 못하게 설정은 settings.json의 permissions.deny에 작성한다
참고 (공식):
- gitleaks (gitleaks/gitleaks)
- git-commit 문서 (--no-verify)
- githooks 문서 (core.hooksPath)
- Push protection – GitHub Docs
※ 사양은 2026-10-20 시점의 공식 문서를 기반으로 합니다. 검증은 git 2.47.3 / gitleaks 8.30.1로, Linux의 임시 환경에서만 진행했습니다.
업데이트 정보나 간단한 Tips는 X (@supportapp3_lab)에서 발신하고 있습니다.