# scrapfly-browser-math-os-fingerprint-2026-07-12

## Veille

Artículo de ingeniería publicado el **12 de julio de 2026** por **Scrapfly Engineering**, sobre un canal de *fingerprinting* de navegador poco conocido: **los últimos bits de un número de coma flotante delatan el sistema operativo**. **El mecanismo**: IEEE 754 define cómo se almacena un `double`, pero **no exige** que `sin`, `cos`, `tanh` o `exp` estén correctamente redondeados; cada sistema distribuye por tanto una **libm** que sacrifica una fracción de ULP a cambio de velocidad, con sus propios coeficientes minimax, tablas y constantes de reducción. En consecuencia, `Math.tanh(0.8)` devuelve **tres valores distintos** según glibc (Linux), libsystem_m (macOS) y UCRT (Windows) — *« una sola llamada a tanh sobre la entrada correcta es una firma por sistema operativo. Afirma ser macOS, devuelve bits matemáticos de Linux, y te has contradicho con tu propio User-Agent. »* **El indicio es reciente y está fechado con precisión**: hasta **Chrome 147**, V8 calculaba `tanh` con un port de **fdlibm** embebido, idéntico en todas partes y sin fugas; el commit de V8 `c1486295ae5` lo sustituyó por `std::tanh`, publicado en V8 14.8.57, es decir **Chrome 148** — 148, 149 y 150 tienen fuga, 147 y anteriores no. **Tres superficies concentran las fugas**: `Math.tanh` (la **única** función `Math.*` afectada, ya que V8 embebe y enlaza estáticamente el resto), **todas las funciones trigonométricas de CSS** (Blink llama directamente a la libm del sistema anfitrión, tras una reducción de ángulo basada en grados que no comparte código con `Math.sin`), y **Web Audio** (donde el compresor permanece en libsystem_m escalar mientras que las etapas de FFT y vectoriales pasan por **Accelerate**). **Cuatro trampas** dificultan la contramedida: solo algunas funciones tienen fuga — de modo que **falsificar las demás crea una incoherencia detectable**; JavaScript y CSS son rutas de código distintas; **macOS embebe dos bibliotecas matemáticas que divergen entre sí** (escalar frente a Accelerate, del 10 al 89% de las entradas según la función: `cos(0)` devuelve `1.0` por un lado, `0.9999999999999999` por el otro); y **la arquitectura también deja fuga** (FMA y la propagación del signo de NaN difieren entre ARM y x86). **La contramedida rechazada y la elegida**: añadir ruido falla dos veces — el valor no coincide con **ningún** sistema operativo real, y la no determinación entre llamadas es en sí misma un indicio. El único camino es la **reproducción bit a bit**: extraer los coeficientes de la libm objetivo, transcribirlos **en hexadecimal** (una transcripción decimal redondearía de forma distinta), escribir cada multiplicación-suma fusionada explícitamente como `fma()`, y compilar con `-ffp-contract=off` para que el compilador no invente ni elimine ninguna. **Divulgación a señalar**: el editor declara de entrada que *« las publicaciones aquí se redactan con IA, »* mientras que los mecanismos, las cifras y el código siguen siendo propios.

## Titre Article

Your Browser Does Math Differently on Every OS, and Anti-Bot Systems Read the Bits

## Date

2026-07-12

## URL

https://scrapfly.dev/posts/browser-math-os-fingerprint/

## Keywords

fingerprinting, huella digital del navegador, anti-bot, detección de automatización, IEEE 754, redondeo correcto, ULP, unidad en el último lugar, libm, glibc, libsystem_m, UCRT, ucrtbase, fdlibm, llvm-libc, dbl-64, V8, Blink, Chrome 148, commit de V8, Math.tanh, funciones trigonométricas de CSS, reducción de ángulo en grados, Web Audio, DynamicsCompressor, Accelerate, vDSP, vvsin, vvtanh, FFT, biquad, Apple Silicon, ARM frente a x86, FMA, multiplicación-suma fusionada, propagación de NaN, WASM, coeficientes minimax, tablas de exponentes, constantes de reducción, reproducción bit a bit, transcripción hexadecimal, ffp-contract, determinación, ruido como contramedida, incoherencia de falsificación, User-Agent contradictorio, superficie de detección, agentes de navegación, Scrapfly

## Authors

**Scrapfly Engineering** — équipe d'ingénierie de **Scrapfly**, fournisseur d'infrastructure de collecte web. Le texte annonce sa position d'intérêt sans détour : *« Scrapfly ships a browser that has to match a real one across hundreds of signals, and math is one of the harder ones. »* On lit donc un **attaquant du problème de détection**, qui documente le canal parce qu'il doit le neutraliser.

**Divulgation éditoriale explicite**, à consigner parce qu'elle est rare : *« A note on how these are written: the posts here are drafted with AI. That lets our engineers put research and findings out quickly and spend their effort on the technical substance instead of the prose. The mechanisms, the numbers, and the code are ours. »* La rédaction est assistée, les mesures et le code sont revendiqués par l'équipe.

## Ton

**Perfil**: artículo de ingeniería extremadamente denso, en el registro de *engineering blog* de un proveedor de infraestructura. Doce minutos anunciados, sin concesiones pedagógicas: abre con un fragmento de consola y cierra con código C y coeficientes hexadecimales.

**Estilo**: **la demostración precede a la explicación**. El texto abre con tres líneas para pegar en una consola — `Math.tanh(0.8)` y sus tres salidas anotadas por sistema operativo — antes de explicar por qué. Luego una tabla de mediciones reales sobre tres máquinas físicas, con la precisión que separa una anécdota de un protocolo: *« Medido a través del protocolo DevTools en Chrome 150: Linux (glibc), macOS 26 en Apple Silicon (libsystem_m), Windows 11 (ucrtbase.dll). »*

**Dos rasgos metodológicos**:

1. **La entrada de prueba se elige, no se encuentra.** *« tanh(0.5) es una de las aproximadamente tres de cada cuatro entradas en las que todos coinciden, y precisamente por eso es una sonda inútil. tanh(0.8) es una que separa a los tres a la vez. »* El texto explica **cómo se construye una sonda**, no solo que exista.
2. **La ambigüedad se resuelve experimentalmente, no leyendo código.** Frente a dos bibliotecas de Apple en competencia: *« La resolvimos dirigiendo un Chrome real en un Mac real a través del protocolo de depuración y leyendo el double exacto. »*

**Registro argumentativo**: el de una **refutación ordenada**. La sección "Cuatro trampas" desmonta las soluciones evidentes una a una — *« "Solo hay que reimplementar las funciones de Mac" falla al primer contacto, por cuatro razones »* — y la sección siguiente descarta la contramedida más intuitiva (el ruido) antes de proponer la propia.

**Frases marcadoras**: *« Hay una señal más silenciosa, y vive en los últimos bits de un número »*, *« un detector no necesita matemáticas, solo una tabla »*, *« Afirma ser macOS, devuelve bits matemáticos de Linux, y te has contradicho con tu propio User-Agent »*, *« Elige la biblioteca equivocada para un punto de llamada dado y te desvías 1 ULP en la mayoría de las entradas, peor que no falsificar nada »*, *« CSS es un indicio en todas partes »*.

## Pense-betes

- **El principio, en una línea**: IEEE 754 exige el **almacenamiento** de un `double`, no el **redondeo correcto** de las funciones trascendentes. El redondeo correcto resulta costoso, así que cada sistema distribuye su propia libm con sus coeficientes minimax, tablas y constantes de reducción. **La diferencia de redondeo es una firma.**
- **La sonda, digna de conocerse**: `Math.tanh(0.8)` devuelve `0.6640367702678491` en Linux (glibc), `0.664036770267849` en macOS (libsystem_m) y `0.6640367702678489` en Windows (UCRT) — **los tres difieren, en 2 ULP**. Linux y macOS divergen en aproximadamente **una cuarta parte de todas las entradas**, típicamente en **1 ULP**; Windows diverge de ambos en unos pocos puntos porcentuales. → *« Un detector no necesita matemáticas, solo una tabla. »*
- **El indicio está fechado hasta el commit, y esto es lo que hace útil el artículo**: hasta **Chrome 147**, V8 calculaba `tanh` con un port de **fdlibm** embebido — mismos bits en todas partes, **sin fuga**. El commit de V8 **`c1486295ae5`** lo sustituyó por `std::tanh`, que lee la libm del sistema anfitrión; publicado en **V8 14.8.57 = Chrome 148**. **148, 149, 150 tienen fuga. 147 y anteriores no.** → **Una regresión de privacidad introducida por una elección de implementación mundana**, y una ventana de versión precisa para fechar una huella.
- **El mapa de fugas — la parte más reutilizable**: | Operación | `Math.*` (JS) | CSS `calc()` | Web Audio | |---|---|---|---| | `sin cos tan` | embebido en V8 | **libm del sistema anfitrión** | Accelerate (FFT), escalar en el compresor | | `asin acos atan atan2` | embebido en V8 | **libm del sistema anfitrión** | no se usa | | `tanh` | **libm del sistema anfitrión** | — | no se usa | | `exp`, `log*`, `pow` | embebido en V8 | **libm del sistema anfitrión** | escalar en el compresor | | vectorial, FFT | — | — | **Accelerate (vDSP)** en Mac | | `sqrt`, aritmética | hardware | hardware | hardware | → **V8 enruta casi todo a través de sus propias matemáticas embebidas: JavaScript solo tiene fuga en un punto, `Math.tanh`. CSS tiene fuga en todas partes. Web Audio toca tres bibliotecas dentro de un mismo grafo.**
- **WASM no delata el sistema operativo**: no hay opcode trascendente, `sin` proviene de la libm que el módulo haya embebido, y la aritmética (`f64.sqrt`, `f64.mul`) es de hardware. **Su único eje de fingerprinting es ARM frente a x86** (canonicalización de NaN, algunas diferencias de redondeo SIMD).
- **Las cuatro trampas — la verdadera lección de diseño, transponible mucho más allá de este tema**: 1. **Solo algunas funciones tienen fuga.** Falsificar las funciones que **no** tienen fuga crea una incoherencia, y *« esa asimetría es en sí misma comprobable. »* → **Sobrecorregir es tan detectable como subcorregir.** 2. **JS y CSS son rutas de código distintas.** Las funciones trigonométricas de CSS reducen el ángulo **en grados** y luego llaman a `std::sin` sobre el valor reducido — un resultado distinto al de un `sin()` en radianes. El equipo reprodujo *« la reducción en grados y el paso de radianes a grados bit a bit, no solo la función final. »* 3. **macOS tiene dos bibliotecas matemáticas que se contradicen entre sí.** El `libsystem_m` escalar y las rutinas vectoriales de Accelerate divergen en un **10 a 89%** de las entradas según la función. `cos(0)`: `1.0` en escalar, `0.9999999999999999` en Accelerate. → *« "Reproducir las matemáticas de Apple" carece de definición hasta saber qué biblioteca llama el navegador, y en qué punto. »* Respuesta establecida experimentalmente: escalar para `Math.tanh`, la trigonometría de CSS y las funciones trascendentes por muestra del compresor; Accelerate para el DSP de Web Audio (FFT, matemáticas vectoriales, filtros biquad). **Elegir la biblioteca equivocada cuesta 1 ULP en la mayoría de las entradas — peor que no hacer nada.** 4. **La arquitectura también tiene fuga.** ARM y x86 difieren en la multiplicación-suma fusionada y en la propagación del signo de NaN; una reproducción correcta sobre el papel se desvía si el compilador fusiona en un lado y no en el otro.
- **Por qué el ruido no funciona — un argumento generalizable a cualquier contramedida de fingerprinting**: *« Perturbar la salida falla dos veces. Una comparación de referencia ve un valor que no coincide con ningún sistema operativo real, y la aleatoriedad entre llamadas rompe la determinación, lo cual es en sí mismo un indicio. »* → **Una defensa que produce un valor imposible resulta tan identificable como un valor verdadero.** El objetivo no es "ruido", es **el valor exacto del sistema reclamado**.
- **La contramedida elegida, y sus tres requisitos**: (1) **recuperar** los coeficientes minimax, las tablas de exponentes y las constantes de reducción de la libm objetivo y **transcribirlas en C portable**; (2) **copiar los patrones de bits en hexadecimal** — *« una transcripción decimal redondearía de forma distinta »*; (3) **escribir cada fusión como `fma()`** explícito y compilar con **`-ffp-contract=off`**, de modo que las operaciones fusionadas sean exactamente las que fusiona Apple y el resultado sea idéntico en CPU con y sin FMA, y **entre la máquina ARM emulada y la flota x86 que ejecuta**. Cuando la reproducción no vale el esfuerzo: *« tomar el original »* — puesto que Windows UCRT es x86-64 y código independiente de la posición.
- **Lo que el artículo implica para los agentes de navegación** — no se afirma en el texto, pero es directo: un agente que dirige un navegador para leer la web se enfrenta exactamente a estas comprobaciones. Los harnesses que **escalan al navegador real del usuario** en lugar de imitar uno (cf. la ruta de navegador de [[skill-gibbs-hyperresearch-2026-08-03]], que dirige el Chrome real autenticado y establece como límite absoluto que *« los CAPTCHA, el 2FA y los inicios de sesión nunca se resuelven automáticamente »*) esquivan el problema por construcción: **no hay nada que falsificar cuando el navegador realmente es lo que afirma ser.** Dos estrategias opuestas frente al mismo muro.
- **Encuadre de uso**: el artículo documenta una técnica de **evasión de detección**, escrita por un proveedor de web scraping. Es utilizable de forma defensiva (comprender qué lee realmente el propio sistema antibot, y saber que una señal aislada de `Math.tanh` fecha el navegador tanto como identifica el sistema operativo) y también para la evasión. **El texto no aborda el consentimiento de los sitios raspados**, ni las condiciones de servicio — eso queda fuera de su alcance declarado.
- **Redacción asistida por IA, divulgada**: *« las publicaciones aquí se redactan con IA… Los mecanismos, las cifras y el código son nuestros. »* Una divulgación honesta y poco frecuente, digna de mención al citar el texto como fuente primaria. Las mediciones vienen acompañadas de su protocolo (protocolo DevTools, tres máquinas nombradas con sus versiones), lo que las hace verificables de forma independiente sin importar cómo se haya producido la prosa.
- **Meta / relacionados**: sobre agentes que dirigen navegadores, [[skill-gibbs-hyperresearch-2026-08-03]] (ruta de navegador, escalado, límite de CAPTCHA); sobre superficie de ataque y contenido web tratado como dato hostil, [[valente-zalewski-beyond-zero-enterprise-security-ai-era-2026-07-20]]; sobre navegadores de IA y automatización, [[mody-browser-company-arc-dia-ai-native-2025-11-23]], perplexity-chrome-integration-browser-ai-search-2025-10-22, y mcp-replaces-browser-logrocket-2025-09-15.

## RésuméDe400mots

Artículo de **Scrapfly Engineering** (12 de julio de 2026) sobre un canal de *fingerprinting* alojado **en los últimos bits de un número**.

**El mecanismo.** IEEE 754 define cómo se almacena un `double`, pero **no exige** el redondeo correcto de las funciones trascendentes. Como el redondeo correcto resulta costoso, cada plataforma distribuye una **libm** con sus propios coeficientes minimax, tablas y constantes. En consecuencia, `Math.tanh(0.8)` devuelve tres valores distintos según glibc, libsystem_m y UCRT. Linux y macOS divergen en aproximadamente una cuarta parte de las entradas, típicamente en **1 ULP**. *« Un detector no necesita matemáticas, solo una tabla. »* Y la incoherencia es inmediatamente explotable: afirmar ser macOS mientras se devuelven bits de Linux **contradice su propio User-Agent**.

**El indicio es reciente y está fechado.** Hasta **Chrome 147**, V8 calculaba `tanh` con un fdlibm embebido, idéntico en todas partes. El commit `c1486295ae5` lo sustituyó por `std::tanh`, que lee la libm del sistema anfitrión, publicado con **Chrome 148**.

**Tres superficies tienen fuga.** `Math.tanh` es la **única** función `Math.*` afectada — V8 embebe y enlaza estáticamente todo lo demás. Las **siete funciones trigonométricas de CSS** tienen fuga, con Blink llamando a la libm del sistema anfitrión tras una reducción de ángulo basada en grados que no comparte código con `Math.sin`. Y **Web Audio** toca tres bibliotecas dentro de un mismo grafo: Accelerate para las etapas de FFT y vectoriales, libsystem_m escalar para las funciones trascendentes del compresor. WASM, por su parte, no delata el sistema operativo — solo la arquitectura.

**Cuatro trampas** dificultan la contramedida: solo algunas funciones tienen fuga, de modo que **falsificar las demás crea una asimetría detectable**; JavaScript y CSS son rutas de código separadas; **macOS embebe dos bibliotecas matemáticas que divergen entre sí** entre un 10 y un 89% según la función, de modo que "reproducir las matemáticas de Apple" carece de sentido hasta saber cuál se llama en cada punto; y ARM y x86 difieren en la multiplicación-suma fusionada y en la propagación de NaN.

**El ruido no funciona**: produce un valor que no coincide con **ningún** sistema operativo real, y su no determinación es en sí misma una señal. El único camino es la **reproducción bit a bit** — coeficientes extraídos de la libm objetivo y transcritos en hexadecimal, cada fusión escrita como `fma()` explícito, compilada con `-ffp-contract=off`.

El editor declara que sus publicaciones se **redactan con asistencia de IA**, mientras que los mecanismos, las cifras y el código siguen siendo propios.

## GrapheDeConnaissance

- Scrapfly —publie→ Your Browser Does Math Differently on Every OS (DOCUMENT, 0.97)
- IEEE 754 —s_applique_à→ le stockage d'un double, sans exiger l'arrondi correct des fonctions transcendantes (AFFIRMATION, 0.96)
- libm de plateforme —permet→ d'identifier le système d'exploitation d'un navigateur par la différence d'arrondi d'une fonction transcendante (AFFIRMATION, 0.96)
- Math.tanh —mesure→ trois valeurs distinctes sur glibc, libsystem_m et UCRT pour l'entrée 0.8 (MESURE, 0.95)
- Chrome 148 —remplace→ le calcul embarqué de tanh par un appel à la libm hôte, introduisant la fuite (AFFIRMATION, 0.94)
- fonctions trigonométriques CSS —s_oppose_à→ les fonctions Math de JavaScript, dont elles ne partagent pas le chemin de code (AFFIRMATION, 0.93)
- Web Audio —utilise→ trois bibliothèques mathématiques distinctes dans un même graphe audio sur macOS (AFFIRMATION, 0.9)
- Accelerate —s_oppose_à→ libsystem_m scalaire, les deux divergeant sur 10 à 89 % des entrées selon la fonction (MESURE, 0.92)
- spoofing partiel d'une empreinte —s_oppose_à→ la cohérence de l'empreinte, l'asymétrie créée étant elle-même vérifiable (AFFIRMATION, 0.94)
- ajout de bruit —s_oppose_à→ la dissimulation d'une empreinte, en produisant une valeur ne correspondant à aucun système réel (AFFIRMATION, 0.95)
- Scrapfly —recommande→ de reproduire bit à bit l'algorithme de la libm cible plutôt que de perturber sa sortie (AFFIRMATION, 0.94)
- transcription hexadécimale des coefficients —résout→ l'erreur d'arrondi qu'introduirait une transcription décimale (AFFIRMATION, 0.93)
- option de compilation ffp-contract=off —permet→ de rendre déterministes les fusions multiplication-addition entre architectures (AFFIRMATION, 0.92)
- WebAssembly —réduit→ la surface d'empreinte, n'exposant que la distinction ARM contre x86 (AFFIRMATION, 0.9)
- Scrapfly —affirme_que→ ses billets sont rédigés avec l'aide de l'IA, les mécanismes, chiffres et code restant les siens (CITATION, 0.95)

---
Canonical: https://www.thekb.eu/es/fiches/scrapfly-browser-math-os-fingerprint-2026-07-12/
