printenv나 env를 디버깅에 사용하면 .env의 API 키가 모두 평문으로 노출됩니다: unset해도 리다이렉트된 곳에는 남아있습니다
요약
디버깅 과정에서 `printenv`나 `env` 같은 명령어를 사용하거나 환경 변수를 출력하면 `.env` 파일의 API 키와 DB 비밀번호가 평문으로 노출될 위험이 있습니다. 셸에서 `unset`을 하거나 로그로 리다이렉트해도 값은 남아있으므로, 민감 정보 관리에 각별한 주의가 필요합니다.
핵심 포인트
- printenv/env 사용 시 환경 변수(API 키 등)가 평문으로 출력됩니다.
- unset을 하거나 로그로 리다이렉트해도 값은 파일에 남아있습니다.
- AI 에이전트에게도 환경 변수 노출 요청에 주의해야 합니다.
- 전용 CLI 도구(`ai-secret-check`)를 사용하여 보안 검사를 권장합니다.
.env
을 source
한 후, 디버깅에 자주 사용되는 명령어(2026-11-06, printenv / env GNU coreutils 9.7・더미 값으로 실제 기기 확인). printenv나 env(인수 없음)를 실행하면 설정된 API 키와 DB 비밀번호가 모두 NAME=value 형태로 표준 출력에 나타납니다 - 셸에서
unset하더라도, .printenv > debug_env.txt처럼 파일로 리다이렉트했다면 그 파일에는 평문으로 남아있습니다 - AI 에이전트에게 "환경 변수를 보여줘"라고 요청하면,
printenv나 env, Python의 os.environ 덤프가 제안될 수 있습니다 (추측입니다. 이번에는 에이전트를 통해 시도하지 않았습니다). 스크립트에 남아있는지 여부는 아래 한 줄로 확인할 수 있습니다.
본 기사는 "AI 에이전트와 비밀 정보" 검증 시리즈입니다. 새로운 검증 내용은 X(@supportapp3_lab)에서도 공지하고 있습니다.
프로젝트 폴더에서 실행하면, printenv・단독의 env・os.environ을 작성한 파일 이름과 줄 번호를 출력합니다.
grep -rnE --include='*.sh' --include='*.bash' --include='*.py' 'printenv|(^|[[:space:]])env([[:space:]|]|$)|os\.environ' .
나온 스크립트가 .env를 읽은 후에 실행된다면, 실행 로그나 리다이렉트된 곳에 값이 남아있습니다.
.env 계열의 파일 이름만 먼저 보고 싶을 때는 전용으로 읽기 전용 CLI도 있습니다.
npx github:supportapp3-lab/ai-secret-check scan
리포지토리: https://github.com/supportapp3-lab/ai-secret-check
printenv --help(GNU coreutils 9.7)에는 다음과 같이 적혀 있습니다.
Print the values of the specified environment VARIABLE(s).
If no VARIABLE is specified, print name and value pairs for them all.
즉 인수 없는 printenv는 현재 프로세스가 가진 모든 환경 변수를 이름과 함께 출력합니다.
env(인수 없음) 역시 현재 환경을 보여주는 명령어입니다 (동일한 coreutils). 값은 모두 더미 값입니다. 상자에 들어있는 실제 토큰이 섞이지 않도록, env -i로 최소한의 환경에서 시작하여 테스트했습니다. .env 파일은 다음 두 줄입니다.
API_KEY=sk-dummy-0000-not-real
DB_PASSWORD=dummy-db-pass-1111
set -a; source ./.env; set +a
printenv | grep -E '^(API_KEY|DB_PASSWORD)='
API_KEY=sk-dummy-0000-not-real
DB_PASSWORD=dummy-db-pass-1111
.env에서 가져온 두 값 모두 이름과 값이 그대로 출력되었습니다.
env | grep -E '^(API_KEY|DB_PASSWORD)='
API_KEY=sk-dummy-0000-not-real
DB_PASSWORD=dummy-db-pass-1111
printenv API_KEY
sk-dummy-0000-not-real
이름은 붙지 않지만, 값은 평문입니다. 로그에 붙이면 동일합니다.
set -a; source ./.env; set +a
printenv | grep -E '^(API_KEY|DB_PASSWORD)=' > /tmp/env_out.txt
unset API_KEY DB_PASSWORD
...
shell: API_KEY=<empty>
DB_PASSWORD=dummy-db-pass-1111
API_KEY=sk-dummy-0000-not-real
프로세스의 환경에서 지워도, 작성된 파일에는 남아있었습니다.
import os
open("debug_env.txt", "w").write(
"\n".join(f"{k}={v}" for k, v in sorted(os.environ.items())) + "\n"
...
API_KEY
/ DB_PASSWORD
환경에 있다면, 이 파일에도 들어갔습니다 (더미 값으로 확인).
bash -x 기사는 "명령어를 실행할 때마다 전개된 인수가 표준 에러(stderr)에 출력된다"는 내용이었습니다. 이번 경우는 디버깅 목적으로 환경 변수 목록을 일부러 출력하는 경우입니다. 둘 다 로그나 대화에 키가 남지만, 발생 계기가 다릅니다.
bash -x
/set -x
… 실행 트레이스 (의도치 않게 값이 나옴) -
printenv
/env
/os.environ
전체 덤프 … 목록 출력 (의도적으로 전부 내보냄)
/proc/PID/environ 기사는 "다른 프로세스에서 읽을 수 있다"는 내용이고, 여기서는 자신의 표준 출력 또는 로그 파일에 기록하는 경우입니다.
-
"연결이 안 되니 환경 변수를 확인해 줘",
"printenv결과를 붙여 넣어 줘"는 트러블슈팅에서 자주 나오는 요청입니다. 에이전트가printenv나env를 실행하면, 위와 같은 출력이 대화에 들어갑니다 (추측). -
리다이렉트된 곳의
debug_env.txt와 같은 파일명은.env가 아니므로,.env만 거부(deny)하더라도 읽힐 수 있습니다 (추측. 에이전트의 deny 설정은 이번에 시도하지 않았습니다). -
CI 로그에
printenv를 남겨두면, 로그 열람 권한이 있는 사람이나, 로그를 에이전트에게 전달했을 때 키가 넘어갑니다 (추측). -
위의
grep으로,printenv/env/os.environ의 전체 덤프가 남아있지 않은지 확인합니다. -
디버깅할 때는
printenv API_KEY처럼 필요한 변수 이름만 지정합니다 (그래도 값은 평문이므로, 붙여넣기 전에 마스킹합니다). -
printenv > 파일이나 파이썬의 전체 덤프는 사용한 후 삭제해야 합니다 (unset만으로는 사라지지 않습니다). -
AI에게 환경 확인을 요청할 때는, "값은 출력하지 말고, 변수 이름 목록만"이라는 조건을 붙입니다.
ai-secret-check scan은 AI가 읽을 수 있을 만한 곳에 있는 .env 계열의 파일명을 찾습니다 (내용물은 표시하지 않습니다). printenv 출력이나 debug_env.txt와 같은 임시 파일은 대상이 아니므로, 위의 grep과 함께 확인해 주세요.
npx github:supportapp3-lab/ai-secret-check scan
리포지토리: https://github.com/supportapp3-lab/ai-secret-check (Node.js 20 이상, MIT)
※ 2026-11-06에 Debian의 일회용 폴더와 더미 값으로 확인했습니다 (bash 5.2.37, printenv / env GNU coreutils 9.7). env -i로 격리하여 실행했습니다.
업데이트 정보나 간단한 Tips는 X(@supportapp3_lab)에서 발신하고 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기