관찰된 패턴 · 2026년 8월 8일 · 7분
배포하자마자 봇이 찾는 것 — 서버 로그로 본 .env 노출
바이브코딩으로 만든 앱을 배포하면, 유명하지 않아도 봇이 옵니다. 하루치 접근 로그에서 봇이 .env 변형 10종을 찾던 기록과, .gitignore 한 글자로 막는 법.
요약
- 공개 주소가 생기는 순간 봇이 옵니다. 유명한 사이트가 아니어도, 하루에 없는 경로로 들어온 요청이 수백 건이었습니다.
- 봇이 찾는
.env변형 목록은 프레임워크가 만드는 파일이 아니라 사람이 흘리는 파일들입니다 — 백업본, 편집기 임시 파일, 축약 이름. .gitignore에.env만 적으면 그 이름 하나만 막힙니다..env*로 바꾸면 변형까지 함께 막힙니다.
바이브코딩으로 앱을 만들어 배포하면, 아직 아무에게도 알리지 않았는데도 방문자가 생깁니다. 사람이 아니라 봇입니다. 이 글은 Preflight을 운영하는 서버의 하루치 접근 로그를 열어, 그 봇들이 정확히 무엇을 찾고 있는지 그대로 보여줍니다.
결론부터 적으면 — 봇이 찾는 파일 목록은 공격 기법의 목록이 아니라 사람이 실수하는 지점의 목록입니다. 누군가 실제로 그렇게 흘렸으니 목록에 올라 있습니다.
하루치 로그에서 본 것
어느 하루, 자정부터 저녁까지 약 20시간 동안 launchpreflight.com의 접근 로그에서 존재하지 않는 경로로 들어온 요청이 377건 있었습니다. 출처 IP는 20곳. 이 사이트는 검색 유입이 거의 없는 작은 사이트입니다. 공개된 주소라는 것만으로 이만큼 옵니다.
그중 PHP 파일을 찾는 요청이 258건이었습니다. 이 사이트에는 PHP가 한 줄도 없습니다. 봇은 이게 무엇으로 만들어졌는지 모르고, 알 필요도 없습니다. 그냥 흔한 이름을 전부 두드려볼 뿐입니다.
가장 눈에 띈 건 이겁니다. 이른 아침, 한 봇이 같은 1초 안에 .env의 변형 10가지를 순서대로 요청했습니다.
.env 변형 요청 10종 (2026-08-03, KST · IP 마지막 옥텟 마스킹)열 줄의 시각이 전부 같은 초입니다. 사람이 손으로 칠 수 없는 속도고, 목록은 미리 준비돼 있습니다. 그리고 모두 404 — 이 서버는 그 파일들을 갖고 있지 않거나, 갖고 있어도 웹으로 내주지 않습니다.
봇의 목록은 사람의 습관 목록이다
이 10개를 출처별로 나눠 보면 흥미로운 게 드러납니다. 프레임워크가 실제로 읽는 규약 이름은 4개뿐이고, 나머지 6개는 어떤 프레임워크도 만들지 않는 이름입니다.
.env.bak, .env.old, .env.backup — 이건 고치기 전에 원본을 복사해두는 습관에서 나옵니다. 날리고 후회하는 것보다 낫다는, 오히려 신중한 동작이죠.
.env.save는 조금 다릅니다. 터미널에서 nano로 파일을 편집하다 SSH 연결이 끊기면(SIGHUP), 편집기가 버퍼를 잃지 않으려고 현재 파일명에 .save를 붙여 비상 저장합니다. 사람이 만들려고 만든 게 아니라, 사람이 작업하던 흔적이 남은 겁니다.
.env.prod·.env.dev도 규약이 아닙니다. 프레임워크는 .env.production, .env.development처럼 전체 철자를 씁니다. 줄여 쓰는 건 사람입니다.
그래서 봇의 요청 목록은 공격 사전이라기보다 개발자들이 어디서 흘리는지에 대한 통계에 가깝습니다. 누군가가 실제로 그 이름으로 흘렸기 때문에, 봇이 그걸 찾는 가치가 생긴 겁니다.
문은 두 개다 — 서버와 저장소
위 로그의 봇들은 서버가 .env를 그대로 내주는지 확인하는 중입니다. 정적 호스팅이나 문서 루트 설정 실수로 .env가 웹에서 열리는 경우가 있어서요. 다행히 Next.js·Vite 같은 프레임워크로 만든 앱은 .env가 서빙 디렉터리 밖에 있어 대부분 404입니다. 위 로그도 전부 404였습니다.
그런데 같은 파일이 새는 통로가 하나 더 있습니다. 공개된 깃 저장소입니다. .env가 커밋된 채로 GitHub 공개 저장소에 올라가 있으면, 봇은 사이트를 두드릴 필요도 없습니다. 그냥 저장소를 보면 되니까요. 그리고 이쪽은 프레임워크가 막아주지 않습니다.
그걸 막는 게 .gitignore입니다. 그런데 여기에 함정이 하나 있습니다.
.env 한 줄과 .env* 한 글자의 차이
.gitignore에 .env라고만 적으면, git은 정확히 그 이름의 파일 하나만 무시합니다. 앞에서 본 .env.bak, .env.old는 다른 이름이라 무시 대상이 아닙니다. 즉 원본은 안 올라가는데 사본은 올라갈 수 있습니다.
.gitignore의 .env 패턴은 정확히 그 이름 하나만 막습니다..env는 무시되지만 사본은 추적 대상으로 남아, 다음 커밋에 같이 올라갈 수 있습니다..env.bak, .env.old 같은 변형까지 함께 무시됩니다.해결은 .env를 .env*로 바꾸는 것입니다. 별표 하나가 .env.bak·.env.save· .env.production 같은 변형까지 함께 막습니다. 봇이 10가지 변형을 찾는 이유가 사람들이 그 변형들을 흘리기 때문이라면, 방어도 그 변형 전체를 덮어야 맞습니다.
확인은 10초면 됩니다. 프로젝트 폴더에서:
touch .env.bak으로 사본을 하나 만들어 본 뒤git status.env.bak이 목록에 뜨면.gitignore의.env를.env*로 바꿉니다.
한 가지 주의할 점. .gitignore는 앞으로 추적하지 않겠다는 규칙이지, 이미 커밋된 파일을 지우지는 않습니다. 이미 .env가 커밋 이력에 들어가 있다면, 그건 별도의 정리 작업이고 — 더 중요하게는, 이미 노출된 키는 파일을 지우는 것으로 안전해지지 않습니다. 키를 새로 발급해야 합니다. 이력·다른 사람의 clone·webhook 페이로드 어딘가에 옛 키가 그대로 살아 있기 때문입니다.
Preflight에서 이걸 어떻게 봐 왔는가
Preflight은 보안 감사를 대체하지 않습니다. 여기 적은 내용도 새로운 발견은 아니고, 보안을 다뤄본 사람에겐 익숙한 이야기입니다. 다만 배포 직전에 바이브코딩으로 만든 앱을 처음 점검할 때, .env 계열 노출이 가장 먼저 우선순위 위로 올라오는 경우가 많다는 게 관찰된 결과입니다.
이 글은 그 관찰의 한 조각을 서버 로그로 확인한 것뿐입니다. 자기 프로젝트가 어디까지 노출돼 있는지 궁금하다면, 점검을 한 번 돌려 보는 편이 빠릅니다. 봇보다 먼저 보는 게 핵심이니까요.