의 load_dotenv()는 인수를 지정하지 않았을 경우 스크립트가 있는 폴더부터 상위 계층으로 순차적으로 .env 파일을 검색하여, 가장 먼저 발견된 하나를 읽습니다. 따라서 프로젝트에
.env 파일이 없더라도, 상위 폴더에 위치한 다른 (2026-11-04, python-dotenv 1.2.4・Python 3.13.5, 더미 값으로 실기 확인)..env의 값이 os.environ에 로드되었습니다. 이는 Node.js의
node --env-file=.env와 다릅니다. Node.js는 지정된 경로만 읽고 상위 폴더를 검색하지 않았습니다 (Node.js v24.22.1). AI 에이전트에게 프로젝트 폴더만 전달하더라도, 그곳에서 실행되는 Python 스크립트는 상위 계층에 있는 경우가 있습니다. 상위 폴더에 .env 파일을 읽는 .env 파일의 존재 여부는 아래 한 줄로 확인할 수 있습니다.
본 기사는 'AI 에이전트와 비밀 정보' 검증 시리즈입니다. 새로운 검증 내용은 X (@supportapp3_lab)에서도 공지하고 있습니다.
프로젝트 폴더에서 실행하면, 그곳부터 /까지 각 계층에 있는 .env 파일의 경로만 출력합니다 (내용은 표시하지 않습니다).
d=$PWD; while [ "$d" != / ]; do ls -1 "$d"/.env 2>/dev/null; d=$(dirname "$d"); done
두 개 이상이 출력된다면, Python 스크립트의 위치에 따라 상위 .env 파일이 읽힐 수 있습니다.
python-dotenv의 README에는 load_dotenv()가 기본적으로 다음과 같이 작동한다고 쓰여 있습니다.
Look for a
.env file in the same directory as the Python script (or higher up the directory tree).
Not overrideexisting environment variables (override=False).
소스 코드의 find_dotenv() 설명 역시 "Search in increasingly higher folders for the given file"입니다. 기준은 현재 작업 디렉토리가 아니라 스크립트가 있는 위치입니다 (대화형 모드 등에서는 usecwd의 처리 방식이 달라집니다).
demo/
├── .env # DUMMY_PARENT_KEY=parent-dummy-0000
└── project/
...
run.py는 다음과 같습니다.
import os
from dotenv import load_dotenv, find_dotenv
print("find_dotenv():", find_dotenv(usecwd=False))
...
find_dotenv(): /tmp/demo/project/.env
load_dotenv(): True
DUMMY_PROJ_KEY = proj-dummy-1111
...
2개 계층 위의 project/.env가 발견되었고, 그곳에서 검색을 멈췄습니다. 더 상위의 demo/.env는 읽히지 않았습니다.
find_dotenv(): /tmp/demo/.env
load_dotenv(): True
DUMMY_PROJ_KEY = None
...
프로젝트 외부에 있는 demo/.env의 값이 로드되었습니다. 오류나 경고는 발생하지 않았습니다.
.env 파일이 없는 /tmp로 이동한 후 python /path/to/run.py로 실행해도, 1번과 마찬가지로 project/.env가 읽혔습니다. 검색 시작점은 스크립트의 위치입니다.
$ DUMMY_PROJ_KEY=from-shell python run.py
DUMMY_PROJ_KEY = from-shell
README대로, 기본값인 override=False에서는 셸(Shell) 측의 값이 우선되었습니다.
app/sub에서 load_dotenv(dotenv_path="./.env")를 실행하면 False가 반환되며, 어느 쪽 값도 로드되지 않았습니다. 이 경우에는 상위 계층을 검색하지 않습니다.
같은 app/sub에서 실행했을 때, --env-file은 지정된 경로만 확인하고, 찾지 못하면 오류가 발생했습니다. Node.js 공식 문서에도 환경 변수와 파일 양쪽에 모두 존재하는 변수는 환경 변수의 값이 우선된다고 쓰여 있습니다.
-
Claude Code 공식 문서(Permissions)에는 Read・Edit의 deny 규칙은 내장 파일 작업이나 Bash의 cat 등에는 적용되지만, 'Python이나 Node 스크립트가 직접 파일을 여는' 방식과 같은 간접적인 읽기에는 적용되지 않는다고 쓰여 있습니다. load_dotenv()가 상위 폴더의 .env를 열어가는 것은 이러한 형태이므로, deny 설정으로는 막히지 않을 것이라고 생각됩니다(추측. 이번에는 Claude Code를 통해 시도하지 않았습니다). 공식 문서는 모든 프로세스를 중단시키고 싶을 때 샌드박스(sandbox)를 안내하고 있습니다. 반면 Codex의 permission profile의 deny는 샌드박스 내에서 작동하기 때문에, 기사 7에서는 codex sandbox -- cat .env가 Permission denied가 되었습니다. 다만 deny 대상에 :workspace_roots 아래를 작성했을 경우, 그 바깥에 있는 상위 폴더의 .env는 대상에서 제외될 것이라고 생각됩니다(추측, 미확인). - 로드된 값은 해당 프로세스의 환경 변수가 되므로, 로그나 에러 출력으로 내보내면 화면에 표시됩니다(/proc/PID/environ 기사에서 확인했듯이, 환경 변수는 같은 사용자로부터 읽을 수 있습니다).
-
상위 폴더에 .env를 두는 방식(여러 프로젝트에서 공유하는 등)을 사용하고 있다면, 프로젝트 폴더만 점검해서는 놓치게 됩니다.
-
위 첫 줄에서 상위 폴더에 .env가 있는지 확인합니다. - Python에서는 읽을 .env의 경로를 지정하여 작성해야 합니다. 스크립트 위치를 기준으로 하려면 다음과 같이 합니다. 지정된 파일이 없으면 from pathlib import Path from dotenv import load_dotenv load_dotenv(dotenv_path=Path(__file__).resolve().parent / ".env")가 반환되므로, 상위 계층을 읽으러 가지 않습니다. - 공유용 .env를 홈 등 상위 계층에 두지 마십시오.
필자가 만든 읽기 전용 CLI ai-secret-check scan은 실행된 폴더보다 아래의 .env 계열 파일 이름을 찾습니다. 이번 demo/project에서 실행했을 때, project/.env는 감지했지만, 상위의 demo/.env는 대상이 아니었습니다. project/.env를 삭제한 상태에서는 '읽을 만한 파일을 찾지 못했습니다.'라고 나옵니다. 상위 폴더는 위 첫 줄에서 별도로 확인해 주십시오.
npx github:supportapp3-lab/ai-secret-check scan
리포지토리: https://github.com/supportapp3-lab/ai-secret-check (Node.js 20 이상, MIT. 값은 표시하지 않습니다)
- python-dotenv (README)
- python-dotenv
find_dotenv (src/dotenv/main.py) - Configure permissions – Claude Code Docs
- Node.js Command-line API (--env-file)
※ 2026-11-04에, Debian의 일회용 폴더와 더미 값으로 확인했습니다(python-dotenv 1.2.4, Python 3.13.5, Node.js v24.22.1). 출력 중인 /tmp/demo는 실제 경로를 대체한 것입니다.
업데이트 정보나 간단한 Tips는 X(@supportapp3_lab)에서 발신하고 있습니다.