전체 글
위협6분 읽기

가짜 AI 크롤러가 .env 파일을 노리고 있습니다. 내 앱을 확인하는 방법

Line of friendly-looking robots walking past server racks while one shines a light on a locked folder with a key

최근 액세스 로그에서 ‘ClaudeBot’이나 ‘ChatGPT’ 트래픽이 많이 보였다면, AI 회사들이 사이트를 색인하고 있다고 생각했을지도 모릅니다. 일부는 아마 그랬을 겁니다. 하지만 그렇지 않은 트래픽이 점점 늘고 있습니다. AI 크롤러의 이름표를 단 자격 증명 스캐너가 특정 파일 하나를 요청하고 있는 것입니다. 바로 여러분의 .env입니다.

이번 주 봇 관리 업체 Cequence는 약 32개의 AI 봇 신원을 번갈아 사용한 단일 공격자에 대한 연구를 발표했습니다. 여기에는 OpenAI, Anthropic, Meta, Perplexity의 이름도 포함됐습니다. 10월의 어느 하루에는 AI 봇 트래픽을 조금이라도 받은 Cequence 보호 대상 조직의 48%에 도달했습니다. 콘텐츠를 크롤링한 것이 아닙니다. 시크릿이 있을 법한 약 90개의 파일 경로를 요청했습니다. .env 파일, 클라우드 자격 증명 파일, SSH 개인 키, 서버 환경 데이터 같은 것들입니다.

그 요청은 거의 모두 차단되거나 실패했고, 보고된 침해도 없습니다. Cequence 고객에게는 좋은 소식입니다. 여러분에게 던질 질문은 더 단순합니다. 오늘 이 봇이 여러분의 앱을 찾아온다면, 받게 될 것은 404일까요, 아니면 Stripe 키일까요?

무슨 일이 벌어지고 있나

최근 몇 달 사이에 나온 세 개의 별도 보고서가 같은 방향을 가리킵니다.

  • Cequence(10월 28일 발표): 하나의 스캐너가 약 32개의 가짜 AI 신원을 사용했고, 최소 9월 말부터 10월 말까지 활동했습니다. 각 클라우드 주소는 약 8초 동안 50~190개의 요청을 몰아서 보낸 뒤 다음으로 넘어갔습니다. 하루에 300개가 넘는 주소를 사용했고, 9월 말의 주소는 한 달 뒤 단 하나도 다시 나타나지 않았습니다. CSO Online은 이런 로테이션 때문에 고정 IP 차단 목록의 효과가 크게 떨어진다고 지적합니다.
  • GreyNoise(8월): 다른 클러스터가 824개의 주소에서 13개의 AI 크롤러를 사칭했으며, 그중 어느 주소도 각 회사가 공개한 IP 범위에 속하지 않았습니다. 가장 많이 요청된 경로는 프레임워크가 시크릿을 남길 만한 모든 곳의 체크리스트처럼 보였습니다: /.env, /app/.env, /api/.env, /backend/.env, /.env.local, /.env.production, /.env.bak, /.aws/credentials. 가짜 봇은 /robots.txt를 단 한 번도 요청하지 않았습니다. Anthropic의 진짜 크롤러는 요청했고, 자격 증명 파일은 한 번도 요청하지 않았습니다.
  • Symantec(Help Net Security 보도, 10월 23일): 보호되지 않은 AI 서비스로 위장한 허니팟이 공격자의 자율 에이전트가 작동하는 모습을 포착했습니다. 그 탈옥 프롬프트는 .env 파일, API 키, 데이터베이스 스키마를 읽는 것이 평범한 개발 작업이라고 모델에게 말했습니다. 허니팟이 기록한 12만 7,000건 이상의 요청 대부분은 정찰, 훔친 키 시도, 노출된 설정 파일 탐색이었습니다.

패턴은 분명합니다. 공격자들은 사이트 운영자들이 AI 크롤러를 허용 목록에 넣기 시작했다는 것을 알기에 그 이름을 빌립니다. 그리고 AI 키가 실제 돈이 된다는 것도 압니다. 유출된 OpenAI, Anthropic, Gemini 키는 알아차리기 전에 큰 청구서를 만들 수 있습니다.

빠르게 출시하는 개발자가 신경 써야 하는 이유

사용자 에이전트 문자열은 방문자가 자기 자신에 대해 적어 보내는 헤더일 뿐입니다. 아무것도 증명하지 않습니다. 호스팅 설정, CDN 규칙, WAF가 ‘알려진 AI 봇’을 통과시키고 있다면, 바로 이런 트래픽에 문을 열어 준 셈일 수 있습니다.

더 중요한 것은, 노림수가 빠르게 출시된 앱에서 흔히 나오는 실수라는 점입니다. 빌드가 프로젝트 폴더 전체를 복사하는 바람에 .env 파일이 웹 루트에 들어갑니다. 늦은 밤 수정 후 .env.production.bak이 남겨집니다. Docker 이미지가 /app을 정적 파일로 제공합니다. 어느 것도 교묘한 익스플로잇이 필요 없습니다. GET 요청 하나면 되고, 봇에게는 그것이 첫 번째 요청이든 아흔 번째 요청이든 상관없습니다.

노출된 .env 파일: 공격자에게 이 파일이 그토록 가치 있는 이유

내 앱을 확인하는 방법

스캐너가 실제로 요청하는 경로부터 시작하세요. 아래 루프를 내 도메인으로 바꿔 터미널에서 실행합니다.

모든 줄이 404 또는 403이어야 합니다. 200은 문제지만, 당황하기 전에 본문을 확인하세요. 많은 싱글 페이지 앱은 알 수 없는 경로에 대해 index.html을 200으로 반환합니다. curl -s https://yourapp.com/.env | head -5 를 실행해 무엇이 돌아오는지 보세요. KEY=value 형태의 줄이 보인다면 그 파일의 모든 시크릿이 유출된 것으로 간주하세요.

for p in .env .env.local .env.production .env.bak .env.old \
         app/.env api/.env backend/.env .aws/credentials .git/config; do
  code=$(curl -s -o /dev/null -w "%{http_code}" "https://yourapp.com/$p")
  echo "$code  /$p"
done

이왕 하는 김에, 같은 시크릿을 다른 경로로 내주는 관련 유출도 확인하세요:

  • 접근 가능한 .git 디렉터리가 있으면 누구나 소스를 재구성할 수 있습니다. 한 번이라도 커밋된 .env도 포함해서요.
  • JavaScript 번들 안의 키는 스캐너조차 필요 없습니다. DevTools를 열고 번들에서 sk-, AIza, key를 검색해 보세요.
  • 프로덕션의 소스 맵은 주석까지 포함한 원본 소스를 그대로 내보낼 수 있습니다.
노출된 .git 디렉터리: 공격자가 소스를 재구성하는 방법

그다음 로그를 확인하세요. /.env 나 /.aws/credentials 에 대한 요청을 검색합니다. 그중 하나라도 200을 반환했다면, 그때가 사고의 시작 시점입니다.

해결 방법

1. 시크릿을 웹 루트 밖으로 빼세요. 진짜 해결책은 제공할 파일 자체가 없는 것입니다. 환경 변수는 정적 자산과 함께 배포되는 파일이 아니라 호스트 설정(Vercel, Netlify, Railway, Fly 등 모두 지원합니다)에 있어야 합니다. .env* 가 .gitignore 와 .dockerignore 모두에 포함되어 있는지 확인하세요.

2. 안전장치로 서버에서 닷파일을 차단하세요. nginx의 경우:

# Deny all hidden files except the ACME challenge path
location ~ /\.(?!well-known) {
    deny all;
    return 404;
}

Apache(.htaccess)의 경우:

<FilesMatch "^\.">
    Require all denied
</FilesMatch>

정적 파일을 제공하는 Express 앱이라면 express.static 은 기본적으로 닷파일을 무시합니다. dotfiles: 'allow' 로 덮어쓰지 마세요.

3. 노출된 것은 모두 교체하세요. 파일을 지운다고 유출된 키가 되돌아오지는 않습니다. 한 번이라도 접근 가능했던 시크릿은 모두 교체하세요. 결제, 데이터베이스, AI 제공업체 키부터 시작하세요. Railway 침해에 관한 글에서 다운타임 없이 앱 시크릿을 교체하는 방법을 단계별로 설명합니다.

4. 사용자 에이전트를 믿지 마세요. 방화벽이나 속도 제한에서 AI 크롤러를 통과시킨다면, 이름으로 비교하지 말고 각 회사가 공개한 IP 범위로 검증하세요. GreyNoise는 보고서에서 Anthropic, OpenAI, Google, Perplexity의 공식 JSON 파일을 안내합니다. Cequence의 조언도 같습니다. 서명된 요청, 공개된 주소 범위, 또는 직접 연동으로 검증하라는 것입니다.

5. 노출된 개발 도구는 패치하세요. GreyNoise는 이 스캐너들이 Vite 파일 읽기 버그 CVE-2025-30208을 시도하는 것도 확인했습니다. Vite 개발 서버가 인터넷에서 접근될 가능성이 있다면 6.2.3, 6.1.2, 6.0.12, 5.4.15 또는 4.5.10 이상으로 업그레이드하고, 애초에 개발 서버를 공개하지 마세요.

6. AI 키에 지출 한도를 설정하세요. 대부분의 AI 제공업체는 월 지출 상한을 두거나 키를 특정 프로젝트로 제한할 수 있게 해 줍니다. 유출을 막지는 못하지만, 수천 달러짜리 깜짝 청구서를 작은 금액으로 줄여 줍니다.

빠른 체크리스트

터미널을 닫기 전에 다음을 확인하세요:

  • 위 curl 루프의 모든 경로가 파일이 아니라 404/403을 반환한다.
  • .env* 가 .gitignore 와 .dockerignore 에 포함되어 있다.
  • 서버나 호스트가 닷파일을 거부한다.
  • JS 번들이나 소스 맵에 시크릿 키가 없다.
  • 한 번이라도 접근 가능했던 키는 모두 교체했다.
  • AI 크롤러 허용 목록이 사용자 에이전트만이 아니라 IP 범위를 확인한다.
  • AI 제공업체 키에 지출 한도가 설정되어 있다.

봇보다 먼저 확인하세요

이 스캐너들은 수백 개의 주소를 번갈아 쓰고, 한 번의 버스트에 약 8초를 씁니다. 로그를 지켜보는 것으로는 이길 수 없습니다. 이기는 방법은 그들이 문을 두드렸을 때 아무것도 없게 만드는 것입니다.

AppSafe는 바로 이 봇들이 찾아다니는 유출을 검사합니다. 접근 가능한 .env 파일, 노출된 .git 디렉터리, 데이터베이스 덤프, 프런트엔드 번들 속 API 키 등이 포함되며, 모든 발견 항목에는 AI 코딩 도구에 그대로 붙여 넣을 수 있는 수정 프롬프트가 함께 제공됩니다. 아직 출시 전이라면 AI로 만든 앱을 위한 체크리스트도 함께 읽어 보세요. 무료 스캔을 실행해 봇에게 무엇이 보이는지 확인해 보세요.

이 체크리스트를 자동으로 실행하세요

한 번의 무료 스캔으로 이 모든 문제를 점검하고, 각 발견 항목마다 AI 수정 프롬프트를 드립니다.

내 앱 무료 스캔