- 쉘 스크립트를
bash -x (또는 set -x)로 실행하면, 변수가 전개된 후의 명령어가 표준 에러에 출력됩니다. source .env를 통해 로드한 값이나, curl -H "Authorization: Bearer $API_KEY"와 같은 키도 그대로 표시되었습니다 (2026-11-05, bash 5.2.37, 더미 값을 이용해 실기 확인).
- 또한, 헤더를 파일에서 읽어오는
curl -H @headers.txt의 경우, bash -x 출력은 파일 이름만 되었습니다. 다만 (curl 8.14.1 기준), curl -v 옵션을 추가하면 파일에서 읽은 헤더도 > Authorization: Bearer ...와 같이 표시되었습니다.
- AI 에이전트에게 스크립트 디버깅을 맡길 경우,
bash -x의 출력이 그대로 대화에 포함될 수 있습니다 (추측입니다. 이번에는 에이전트를 통해 시도하지 않았습니다). 스크립트에 set -x가 남아있지 않은지는 아래 한 줄로 확인할 수 있습니다.
본 기사는 'AI 에이전트와 비밀 정보' 검증 시리즈의 일부입니다. 새로운 검증 내용은 X (@supportapp3_lab)에서도 공지하고 있습니다.
프로젝트 폴더에서 실행하면, set -x・set -o xtrace・bash -x를 작성한 줄의 파일명과 라인 번호를 출력합니다.
grep -rnE --include='*.sh' 'set -x|set -o xtrace|bash -x' .
출력된 스크립트에서 .env를 읽거나, 키를 명령어에 전달하는 부분이 있다면 실행 로그에 값이 노출됩니다.
bash 내장 명령어인 help set (bash 5.2.37)에는 다음과 같이 적혀 있습니다.
-x Print commands and their arguments as they are executed.
Using + rather than - causes these flags to be turned off.
curl의 공식 매뉴얼에 있는 -H, --header 옵션은 @filename 형태로 전달할 경우 'adds a header for each line in the input file'라고 설명되어 있습니다.
모든 값은 더미입니다. .env는 API_KEY=sk-dummy-0000-not-real의 한 줄이며, 전송 목적지는 로컬의 python3 -m http.server (127.0.0.1)입니다.
set -a; source ./.env; set +a
curl -s -o /dev/null -H "Authorization: Bearer $API_KEY" http://127.0.0.1:18765/
bash -x a.sh의 출력입니다.
+ set -a
+ source ./.env
++ API_KEY=sk-dummy-0000-not-real
...
.env 내부의 할당 줄과, 전개된 curl 인자 모두에 키가 노출되었습니다.
API_KEY=$(cat ./.env | cut -d= -f2)
export API_KEY
++ cut -d= -f2
++ cat ./.env
+ API_KEY=sk-dummy-0000-not-real
...
명령어 치환의 결과도 할당 줄에서 값이 노출되었습니다.
headers.txt에 Authorization: Bearer sk-dummy-0000-not-real를 작성하고, chmod 600을 적용했습니다.
curl -s -o /dev/null -H @headers.txt http://127.0.0.1:18765/
+ curl -s -o /dev/null -H @headers.txt http://127.0.0.1:18765/
bash -x에는 파일 이름만 출력되었습니다.
$ curl -sv -o /dev/null -H @headers.txt http://127.0.0.1:18765/ 2>&1 | grep -i authorization
> Authorization: Bearer sk-dummy-0000-not-real
-H
직접 작성한 경우와 파일에서 읽어온 경우 모두 -v 표시에는 전송된 헤더가 그대로 출력되었습니다 (curl 8.14.1).
set -a; source ./.env; set +a
{ set +x; } 2>/dev/null
curl -s -o /dev/null -H "Authorization: Bearer $API_KEY" http://127.0.0.1:18765/
...
+ set -a
+ source ./.env
++ API_KEY=sk-dummy-0000-not-real
...
{ set +x; } 2>/dev/null 이후의 curl은 출력되지 않았습니다. 하지만 출력을 중지하기 전의 source ./.env는 여전히 출력됩니다. 따라서 출력을 막으려면 .env를 읽기 전에 중지해야 합니다.
AI 에이전트는 명령어의 표준 출력(stdout)과 표준 오류(stderr)를 읽어 다음 행동을 결정합니다.
bash -x로 실행하면 위의 출력이 그대로 대화에 포함되어 로그나 클라우드 측의 대화 기록에도 남을 수 있습니다 (추측). 대화 기록의 저장 위치는 Claude Code의 대화 기록 관련 글에서 확인했습니다. 일반적으로 "작동하지 않으니 bash -x로 봐달라"고 요청하는 경우가 많기 때문에, .env를 읽는 스크립트에서는 특히 주의가 필요합니다 (추측).
- 위의 1행에서
set -x가 남아있지 않은지 확인하세요.
- 디버깅 시
set -x를 사용할 때는, .env를 읽기 전과 키를 전달하는 명령어 직전에 { set +x; } 2>/dev/null로 출력을 중단시키세요.
- curl의 헤더는
-H @파일 방식으로 전달하세요 (bash -x에는 출력되지 않습니다). 단, -v 플래그는 사용하지 마세요.
- AI에게
bash -x 출력을 붙여넣을 때는 키가 포함되어 있지 않은지 미리 확인하는 것이 좋습니다.
제가 만든 읽기 전용 CLI 도구인 ai-secret-check scan은 AI가 읽을 수 있는 위치에 있는 .env 계열의 파일 이름을 찾습니다 (내용은 표시하지 않습니다). 이번과 같은 '실행 로그에 출력되는' 경우는 발견되지 않았으므로, 위의 grep 명령어로 별도로 확인해 주시기 바랍니다.
npx github:supportapp3-lab/ai-secret-check scan
리포지토리: https://github.com/supportapp3-lab/ai-secret-check (Node.js 20 이상, MIT)
※ 2026-11-05에 Debian의 임시 폴더와 더미 값으로 테스트했습니다 (bash 5.2.37, curl 8.14.1).
업데이트 정보나 간단한 팁은 X(@supportapp3_lab)에서 발신하고 있습니다.