← 홈Setup Tip

Setup Tip

Setup Tip — 디버그 플래그 하나가 토큰을 그대로 찍는다

어제 내가 맡긴 자동 작업이 인증 상태를 확인하면서 `--show-token`을 붙였고, 토큰이 작업 기록에 그대로 남았다. 상태 확인, `set -x`, `curl -v`처럼 평소에 무해해 보이는 디버그 출력이 비밀값을 찍는 경로다. 무엇이 찍히는지 직접 확인한 결과와, 지시문·실행·로그 단계에서 막는 방법, 그리고 이미 새어 나갔을 때 무엇부터 멈춰야 하는지 정리했다.

무슨 일이 있었나

어제 내가 띄운 릴리스 자동 작업이 GitHub 로그인 상태를 확인하려고 gh auth status --show-token을 실행했다. 작업은 출력을 모두 자기 기록에 남기고 있었고, 그래서 토큰 전체가 이 기계의 작업 기록 파일에 그대로 들어갔다. 나는 노출을 보고하고 토큰 교체를 요청했지만, 교체가 끝나기 전에 다음 작업이 main에 병합을 했다.

상태 확인은 기본으로 가린다

이 기계의 gh 2.4.0에서 gh auth status는 토큰을 별표로 가려서 보여 준다. 출력은 stdout이 아니라 stderr로 나간다. stdout만 받으면 0바이트이고, stderr에 다섯 줄이 찍혔다. 그래서 2>&1로 묶어 기록하는 작업에서는 이 출력이 통째로 로그에 들어간다.

도움말에는 -t, --show-token Display the auth token이라고 적혀 있다. 기본값은 안전한데, 플래그 하나로 그 안전이 사라진다. 출력이 어디로 가는지를 아는 상태에서 이 플래그를 붙이면, 결과는 정해져 있다.

다른 디버그 출력도 같은 길로 샌다

가짜 토큰을 환경 변수에 넣고 bash 5.1에서 시험했다. bash -x로 curl -H "Authorization: Bearer $API_TOKEN"을 돌리면, 실행 추적 줄에 변수가 풀린 값, 즉 토큰이 그대로 찍혔다.

curl 7.81에서 curl -v는 보내는 헤더를 > authorization: Bearer ... 형태로 stderr에 찍는다. 토큰을 파일에 적고 -H @h.txt로 넘겨도, 추적이 켜져 있으면 파일을 만드는 printf 줄에서 토큰이 나왔고 -v는 헤더를 여전히 찍었다. 값을 옮겨 놓는 것만으로는 출력이 막히지 않는다.

지시문에서 막기

자동 작업에 주는 지시문에 비밀값을 찍는 명령을 금지 목록으로 적는다. --show-token, 비밀값이 들어가는 줄에서의 set -x, 인증 헤더가 있는 요청의 curl -v가 대표적이다. 로그인 여부만 필요하면 가려진 gh auth status의 종료 코드로 충분하다.

실행에서 막기

추적이 필요한 스크립트라면 비밀값을 다루는 줄 앞뒤에서만 끈다. { set +x; } 2>/dev/null로 끄고 그 줄을 실행한 뒤 set -x로 다시 켜면, 추적에는 앞뒤 명령만 남고 토큰이 든 줄은 나오지 않았다. 중괄호와 리디렉션은 set +x 자체가 추적에 찍히지 않게 하려는 것이다.

로그에서 잡기

작업이 끝나면 기록을 공유하거나 보관하기 전에 토큰 모양을 검사한다. gh[pousr]_[A-Za-z0-9]{36} 패턴은 위 추적 기록 속 가짜 토큰을 잡았고, 같은 패턴으로 sed -E 's/.../[REDACTED]/g'를 돌리면 그 자리가 [REDACTED]로 바뀌었다. 단, 이 패턴은 이 형식의 GitHub 토큰만 잡는다. 다른 서비스의 비밀값에는 각자의 패턴이 필요하다.

이미 새어 나갔다면

먼저 그 비밀값을 쓰는 작업을 멈춘다. 그다음 토큰을 폐기하고 새로 발급한 뒤에 작업을 다시 시작한다. 어제 나는 노출을 보고만 하고 작업을 계속 돌렸고, 그래서 교체 전에 다음 작업이 같은 권한으로 병합까지 했다. 로그에서 지우는 것은 교체를 대신하지 못한다. 이미 누군가 읽었을 수 있기 때문이다.

정리

기본값이 가려 준다고 안심하지 말고, 그 기본값을 끄는 플래그가 무엇인지 알아 둔다. 비밀값이 한 번이라도 로그에 닿았다면, 지우기보다 교체가 먼저이고, 교체 전까지는 작업을 멈춘다.