Seven Cloudflare Settings That Quietly Turned Away Paying Agents
돈 내는 AI 에이전트를 조용히 돌려보낸 Cloudflare 설정 일곱 가지
x402 기반 유료 API를 운영하던 팀이 Cloudflare 기본 설정 때문에 Python·Perl 기반 AI 에이전트에게 402 대신 403을 반환하고 있었다는 사실을 외부 에이전트의 제보로 발견한 사례입니다. Browser Integrity Check부터 Pages SPA 폴백까지, 기계 고객을 차단하는 설정 일곱 가지와 매일 아침 돌리는 외부 프로브 체크리스트를 공유합니다.
- 주제
본문
Cloudflare가 AI 크롤러 기본값을 변경한 다음 날, Forgemesh 팀은 Coppice라는 AI 에이전트의 이메일을 받았습니다. 자사 notary 엔드포인트가 curl과 Node에는 402와 가격을 반환하지만, Python 표준 라이브러리와 Perl에는 403만 반환한다는 내용이었습니다. 두 명령어로 재현해 보니 한 엔드포인트가 아니라 세 개 zone의 모든 유료 호스트가 그 상태였고, zone이 존재한 이래로 계속 그랬습니다.
1. Browser Integrity Check — 402보다 먼저 도착하는 403
zone 단위 토글인 Browser Integrity Check는 기본적으로 켜져 있으며, 내부 어뷰즈 목록의 User-Agent를 거부합니다. 그 목록에 Python-urllib과 libwww-perl이 포함되어 있어, User-Agent를 설정하지 않은 Python 스크립트는 403과 error code: 1010 본문을 받고 origin에는 요청이 도달하지도 않습니다. 결제 전에 403을 받은 구매자는 지불할 가격도, 보고할 오류도 없이 그냥 고객이 되지 못합니다. 팀은 세 도메인에서 즉시 이 검사를 껐고, 13개 유료 호스트가 정상적인 402 또는 200을 반환하게 됐습니다. 사람 대상 사이트에서 유지하려면 API 호스트네임에만 끄는 Configuration Rule을 적용하고, 두 User-Agent를 프로브에 추가하라고 권합니다.
2. Bot Fight Mode — 기계가 통과할 수 없는 챌린지들
Bot Fight Mode, Super Bot Fight Mode의 definitely automated 액션, Under Attack 보안 레벨, WAF의 managed challenge, JavaScript 챌린지는 모두 클라이언트가 페이지를 렌더링해야 통과합니다. 요청당 결제하는 에이전트는 페이지를 렌더링하지 않으므로 챌린지와 차단은 동일하며, 오히려 200처럼 보이는 인터스티셜이라 더 나쁩니다. 이제 이 팀의 규칙은 API 호스트네임에는 어떤 챌린지도 두지 않고, 어뷰즈 제어는 429를 반환하는 레이트 리밋과 애플리케이션 계층에서 처리하는 것입니다. 또한 AI Crawl Control이 Search, Training, Agent 카테고리로 분리됐으니 구매자가 에이전트라면 Agent 카테고리를 확인해야 합니다.
3. robots.txt와 Content-signal
모든 호스트가 search, AI input, AI training을 opt-in하는 Content-signal 라인을 담은 robots.txt를 제공해야 하는데, 26개 호스트네임을 프로브하니 4개에 파일이 없었습니다. 파일은 템플릿이 아니라 호스트네임별로 외부에서 확인해야 한다는 교훈입니다.
4. 존재하지 않는 Tunnel 호스트네임
warn.forgemesh.io는 서비스가 10주간 건강했고 실제 결제도 받았지만, 별칭은 모든 경로에서 server: cloudflare 헤더의 404를 반환했습니다. Public Hostname 규칙이 없는 Cloudflare Tunnel의 전형적 증상으로, 7월 초 tunnel 마이그레이션에서 호스트네임이 유실됐던 것입니다. health가 404인데 로컬 포트는 정상이라면 애플리케이션 코드가 아니라 Tunnel 설정을 봐야 합니다.
5. Error 526과 리로드되지 않은 인증서
Full (strict) 모드에서 origin이 만료된 TLS 인증서를 제시할 때 발생하는 526은 Cloudflare가 아니라 origin 문제입니다. Let's Encrypt 갱신은 됐지만 웹 서버가 리로드되지 않은 사례였고, tunnel 뒤에 있으면 이류의 장애 자체가 존재하지 않습니다.
6. 프록시 뒤의 클라이언트 IP, 프로토콜, 가격 URL
Cloudflare 뒤에서는 req.protocol이 https 요청에도 http를 보고해 402 봉투의 리소스 URL이 http://로 시작하고, Coinbase Bazaar 인덱스가 어긋납니다. X-Forwarded-For 기반 레이트 리밋은 클라이언트가 헤더를 앞에 추가할 수 있으므로 CF-Connecting-IP를 키로 쓰고 정확히 한 hop만 신뢰해야 합니다. 보안 판단에 쓰는 헤더는 Cloudflare가 설정한 것이어야 합니다.
7. 모든 경로에 200을 반환하는 Pages 폴백
SPA가 인식 못 하는 경로에 index.html을 200으로 반환하는 탓에, 게시한 적 없는 /.well-known/oauth-authorization-server 같은 경로가 깨진 매니페스트로 읽혀 스캐너 점수가 깎였습니다. Pages worker에서 기계 경로가 HTML로 조회되면 JSON 404를 반환하도록 고쳤고, agent-readiness 점수가 69에서 79로 올랐습니다.
매일 아침의 5분 외부 프로브
이 문제들은 모두 대시보드가 아니라 외부에서 발견됐습니다. 판매하는 모든 호스트네임에 대해 중립 User-Agent와 Python-urllib/3.12, libwww-perl/6.68로 health를 조회해 403이나 error code: 10 포함 여부를 확인하고, robots.txt의 Content-signal, 결제 없는 유료 경로의 402, 엣지와 origin 응답 비교, 미게시 well-known 경로의 404, Tunnel 호스트네임과 DNS 대조를 점검합니다. 첫 실행에서 18개 대상, 차단 0건이었습니다. 문제를 알려준 에이전트는 대가를 요구하지 않았고, 이 팀은 최고의 보안 리뷰를 고객이 되지 못한 고객에게서 받았다고 마무리합니다.
원문: dev.to / 번역·요약: Trawling