- Al enviar un mensaje en ChatGPT, se ejecuta el programa Cloudflare Turnstile, que inspecciona no solo la huella del navegador sino también el estado de la aplicación React
- El programa descifrado recopila 55 propiedades y realiza un proceso de verificación dividido en 3 capas: navegador, red y aplicación
- Solo puede pasar en un entorno SPA real donde el renderizado de React se haya completado, por lo que los navegadores headless o las solicitudes simples de bots fallan
- La huella recopilada se cifra y se convierte en
OpenAI-Sentinel-Turnstile-Token, y además se ejecutan los módulos Signal Orchestrator y Proof of Work
- Solo los servidores de Cloudflare conocen la clave de descifrado, por lo que el límite de privacidad queda determinado por políticas y no por la tecnología
Análisis de cómo funciona Cloudflare Turnstile al enviar mensajes en ChatGPT
- Cada vez que se envía un mensaje en ChatGPT, el programa Cloudflare Turnstile se ejecuta automáticamente dentro del navegador
- Tras descifrar 377 programas de Turnstile a partir del tráfico de red, se observó que va más allá de la recopilación típica de huellas del navegador e inspecciona incluso el estado de la aplicación React
- Los bots que solo falsifican huellas de navegador no logran pasar; para superar la verificación es necesario renderizar por completo la SPA (aplicación de una sola página) de ChatGPT
Estructura del cifrado y proceso de descifrado
- El bytecode de Turnstile se entrega en el campo
turnstile.dx de la respuesta del servidor y está cifrado en una cadena base64 de 28,000 caracteres en cada solicitud
- La capa de cifrado externa puede descifrarse con una operación XOR usando el token
p, y ambos valores se intercambian dentro de la misma solicitud HTTP
- El resultado descifrado es un bytecode en formato JSON compuesto por 89 instrucciones de VM
- En el interior existe un blob cifrado adicional de 19 KB, cifrado con otra clave XOR
- La clave está incluida como un valor literal flotante (por ejemplo, 97.35) dentro del bytecode, generado por el servidor y enviado al navegador
- En las 50 solicitudes se confirmó el descifrado válido de JSON con el mismo método
- El proceso completo de descifrado consta de los siguientes 5 pasos
- Leer el token
p de la solicitud
- Leer
turnstile.dx de la respuesta
XOR(base64decode(dx), p) → genera el bytecode externo
- Extraer la última variable como clave desde la instrucción de 5 argumentos ubicada después del blob de 19 KB
XOR(base64decode(blob), str(key)) → descifra el programa interno (417~580 instrucciones)
Elementos que inspecciona el programa descifrado
- El programa interno se ejecuta en una VM personalizada con 28 instrucciones (opcode), y las direcciones de registros de coma flotante cambian aleatoriamente en cada solicitud
- Recopila un total de 55 propiedades, y las 377 muestras incluían exactamente los mismos elementos
-
Capa 1: huella del navegador
- 8 propiedades relacionadas con WebGL:
UNMASKED_VENDOR_WEBGL, UNMASKED_RENDERER_WEBGL, WEBGL_debug_renderer_info, etc.
- 8 datos de pantalla:
colorDepth, pixelDepth, width, height, availWidth, availHeight, availLeft, availTop
- 5 de hardware:
hardwareConcurrency, deviceMemory, maxTouchPoints, platform, vendor
- 4 de medición de fuentes: crea un div oculto y mide el tamaño renderizado con
fontFamily, fontSize, getBoundingClientRect, innerText
- 8 de recorrido del DOM:
createElement, appendChild, removeChild, style, position, visibility, ariaHidden, etc.
- 5 de almacenamiento:
storage, quota, estimate, setItem, usage
- Guarda el resultado en la clave
6f376b6560133c2c de localStorage para persistirlo entre recargas de página
-
Capa 2: red de Cloudflare
- 5 headers del edge:
cfIpCity, cfIpLatitude, cfIpLongitude, cfConnectingIp, userRegion
- Estos valores solo existen a través de la red de Cloudflare, por lo que los bots que acceden directamente al servidor de origen presentan valores faltantes o inconsistentes
-
Capa 3: estado de la aplicación
- 3 estructuras internas de React:
__reactRouterContext, loaderData, clientBootstrap
- Estos elementos solo existen cuando la aplicación React de ChatGPT se ha renderizado por completo y la hidratación SSR ha finalizado
- Los navegadores headless que solo cargan HTML o no ejecutan el bundle de JS, así como los frameworks de bots que no ejecutan React realmente, fallan
Proceso de generación del token
- Tras recopilar las 55 propiedades, el programa descifra un blob cifrado de 116 bytes y ejecuta 4 instrucciones finales
JSON.stringify(fingerprint) → store → XOR(json, key) → RESOLVE
- El resultado se convierte en el header
OpenAI-Sentinel-Turnstile-Token y se incluye en todas las solicitudes de conversación
Componentes adicionales de Sentinel
- Además de Turnstile, existen otros dos módulos de verificación
-
Signal Orchestrator
- Compuesto por 271 instrucciones
- Instala listeners para eventos
keydown, pointermove, click, scroll, paste, wheel
- Rastrea 36 propiedades
window.__oai_so_* para monitorear el timing de tecleo, la velocidad del mouse, los patrones de scroll, el tiempo de inactividad y los eventos de pegado
- Además de recopilar huellas, cumple la función de capa de biometría conductual
-
Proof of Work
- Basado en una huella de 25 campos + SHA-256 hashcash
- La dificultad es un número aleatorio uniforme en el rango de 400K~500K, y el 72% se resuelve en 5 ms o menos
- Incluye 7 flags binarios de detección:
ai, createPRNG, cache, solana, dump, InstallTrigger, data (todos fueron 0 en 100 muestras)
- Añade costo computacional, pero no es el principal mecanismo de defensa
Quién puede descifrar el token y su significado de seguridad
- Como la clave XOR del programa interno es generada por el servidor e incluida en el bytecode, solo el servidor que generó
turnstile.dx conoce la clave
- El límite de privacidad entre el usuario y el operador del sistema queda definido por decisiones de política, no por restricciones criptográficas
- El propósito de la ofuscación es
- ocultar del análisis estático qué elementos de huella se recopilan
- impedir que el operador del sitio web (OpenAI) lea directamente los valores crudos de la huella
- hacer único cada token para evitar la reutilización (replay)
- dificultar que desde fuera se detecten cambios en los elementos inspeccionados por Cloudflare
- Sin embargo, el cifrado usa una clave y una operación XOR dentro del mismo flujo de datos, por lo que no pasa de ser una ofuscación para dificultar el análisis
Estadísticas de recopilación y análisis
| Ítem |
Valor |
| Programas descifrados |
377/377 (100%) |
| Usuarios únicos observados |
32 |
| Número de propiedades por programa |
55 (todas idénticas) |
| Número de instrucciones |
417–580 (promedio 480) |
| Claves XOR (50 muestras) |
41 |
| Propiedades de Signal Orchestrator |
36 |
| Campos de Proof of Work |
25 |
| Tiempo de resolución de PoW |
72% en 5 ms o menos |
Metodología de análisis
- Se usó únicamente tráfico recopilado mediante procedimientos legítimos
- No se publicaron datos de usuarios individuales
- Todo el tráfico fue observado con el consentimiento de los participantes
- Se realizó desofuscación manual y descifrado offline del SDK de Sentinel (
sdk.js, 1,411 líneas)
- El descifrado se llevó a cabo en un entorno offline utilizando Python
1 comentarios
Comentarios en Hacker News
Hola, soy Nick y trabajo en el equipo de Integrity de OpenAI
Esta verificación forma parte de las medidas de protección para evitar el abuso de la plataforma, como bots, scraping y fraude
El objetivo es priorizar los recursos de GPU para usuarios reales y así seguir ofreciendo acceso a usuarios gratuitos y no autenticados
Estamos monitoreando tiempos de carga de página, tiempo hasta el primer token, tamaño del payload y otros indicadores, y nos enfocamos en minimizar el overhead de estas protecciones
Para la mayoría de los usuarios, el impacto es mínimo, y solo una fracción muy pequeña podría experimentar algo de latencia
También estamos evaluando continuamente mejoras de precisión para dificultar el abuso mientras reducimos la tasa de falsos positivos
Entiendo la explicación de Nick, pero me pregunto si vamos a seguir viviendo en un mundo donde haya que elegir entre privacidad y funcionalidad
Hay retraso al escribir, tirones al renderizar e incluso bloqueos completos
Me pasa igual en Safari de iPhone 16 y en Chrome de MacBook Pro M3
Incluso hay una sugerencia medio en broma de correr las herramientas invasivas de privacidad de Cloudflare y compartir el resultado
Soy suscriptor Pro y todo mi equipo gasta más de 2 mil dólares al mes
Pero cuando uso VPN (Mullvad), la interfaz de Chat suele fallar o expirar incluso estando conectado
Sería bueno que los usuarios de pago pudieran usarlo de forma estable sin importar si usan VPN o no
Hay quejas de que Cloudflare prácticamente vuelve imposible usar la web por marcar como ‘sospechosos’ ciertos navegadores o IP
Lo describen como caer en un infierno de captchas solo por usar Firefox
VPN, navegadores centrados en la privacidad, rangos de IP poco comunes: los usuarios que priorizan la privacidad terminan siendo los más afectados
Mientras tanto, los bots suelen evadir estos filtros con facilidad
Esa persona usa Firefox, pero dice que solo ve una cantidad normal de captchas
Tiene CGNAT desactivado y se pregunta si eso marca la diferencia
Dice que, después de que el banco ya verificó su identidad, cuesta entender que el sitio no pueda distinguir si es humano o no
Parece que OpenAI intenta proteger el ChatGPT gratuito para usuarios no autenticados, de modo que no se abuse como si fuera una API gratis
En la app de Android sí corre una verificación de Play Integrity, mientras que la app de Claude solo pide iniciar sesión y no hace este tipo de validación
Dice que se sorprendió al escribir una pregunta y recibir respuesta sin cookies ni cuenta
Frente a la API, el precio por suscripción es mucho más barato, así que hace falta prevenir abusos
Una simple verificación de carga de SPA no es una gran barrera, y quien sabe de esto ya tiene la capacidad técnica para saltársela
Otras empresas también están construyendo sus propios sistemas antibot
Resulta interesante que ciertas propiedades de la app de React de ChatGPT solo existan una vez que la aplicación está completamente renderizada
Eso implica una detección de bots en la capa de aplicación, no a nivel del navegador
Pensaba que la mayoría de los sistemas avanzados de detección funcionaban así, así que me pregunto qué tiene de especial este hallazgo
Hubiera sido mejor que el autor explicara con más claridad por qué este tema debería importarnos
Al final, todo se reduce a que OpenAI quiere que los usuarios usen la app oficial en React, y no queda claro por qué eso sería un problema
Desde un punto de vista técnico, es interesante
Según entiendo, Turnstile no suele tener configuración específica por sitio, así que da curiosidad cómo OpenAI combinó los datos de Turnstile con su propia API
Hay quien no entiende por qué los operadores de bots no simplemente corren Windows 11 VM + Chrome
Dice que, usando deduplicación de memoria, se pueden correr 50 VM al mismo tiempo y que en AWS cuesta alrededor de 1 centavo por cada 1000 cargas de página, así que sale muy barato
Hay opciones de rotación de IP, spoofing de ubicación, configuración de idioma, parser integrado y más, y el costo de cambiar de proveedor es bajo, así que hay poco incentivo para montarlo por cuenta propia
Es bastante más caro que los métodos más simples
Según esa sugerencia, usar contenedores Linux en vez de Windows sería mucho más ligero y eficiente
Crítica de que parece un artículo torpe escrito por ChatGPT
En 2023~2024 usaron una extensión llamada KeepChatGPT
Les parecía interesante porque funcionaba simulando ser un usuario, sin usar la API
Después dejaron de usarla por la llegada de Gemini y por errores frecuentes, aunque sí les gustaba la opción de mover el panel de IA hacia la derecha
Enlace de KeepChatGPT en GitHub
Ese método no activa en absoluto el sistema antibot de OpenAI
Preguntan si la integración entre Cloudflare y la app es una función personalizada que va más allá del Turnstile estándar, o si es algo exclusivo de Enterprise