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

## Veille

Articolo tecnico pubblicato il **12 luglio 2026** da **Scrapfly Engineering**, su un canale di *fingerprinting* del browser poco conosciuto: **gli ultimi bit di un numero in virgola mobile tradiscono il sistema operativo**. **Il meccanismo**: lo standard IEEE 754 definisce come viene memorizzato un `double`, ma **non impone** che `sin`, `cos`, `tanh` o `exp` siano correttamente arrotondati; ogni sistema distribuisce quindi una **libm** che scambia una frazione di ULP contro la velocità, con i propri coefficienti minimax, tabelle e costanti di riduzione. Ne risulta che `Math.tanh(0.8)` restituisce **tre valori diversi** a seconda di glibc (Linux), libsystem_m (macOS) e UCRT (Windows) — *« una singola chiamata a tanh sull'input giusto è una firma per-OS. Dichiara macOS, restituisci bit matematici di Linux, e hai contraddetto il tuo stesso User-Agent. »* **L'indizio è recente e datato con precisione**: fino a **Chrome 147**, V8 calcolava `tanh` con una porta **fdlibm** integrata, identica ovunque e senza alcuna fuga; il commit V8 `c1486295ae5` l'ha sostituita con `std::tanh`, distribuito in V8 14.8.57, ossia **Chrome 148** — 148, 149 e 150 presentano la fuga, 147 e le versioni precedenti no. **Tre superfici concentrano le fughe**: `Math.tanh` (l'**unica** funzione `Math.*` interessata, poiché V8 integra e collega staticamente il resto), **tutte le funzioni trigonometriche CSS** (Blink chiama direttamente la libm dell'host, dopo una riduzione dell'angolo in gradi che non condivide codice con `Math.sin`), e **Web Audio** (dove il compressore resta sulla libsystem_m scalare mentre le fasi FFT e vettoriali passano attraverso **Accelerate**). **Quattro trappole** rendono difficile la contromisura: solo alcune funzioni presentano la fuga — quindi **falsificare le altre crea un'incoerenza rilevabile**; JavaScript e CSS sono percorsi di codice distinti; **macOS integra due librerie matematiche che divergono tra loro** (scalare vs. Accelerate, dal 10 all'89% degli input a seconda della funzione: `cos(0)` restituisce `1.0` da un lato, `0.9999999999999999` dall'altro); e **anche l'architettura presenta una fuga** (la propagazione FMA e del segno di NaN differisce tra ARM e x86). **La contromisura scartata e quella scelta**: aggiungere rumore fallisce due volte — il valore non corrisponde a **nessun** OS reale, e il non-determinismo a ogni chiamata è a sua volta un indizio. L'unica via è la **riproduzione bit a bit**: estrarre i coefficienti della libm target, trascriverli **in esadecimale** (una trascrizione decimale arrotonderebbe in modo diverso), scrivere ogni fused multiply-add esplicitamente come `fma()`, e compilare con `-ffp-contract=off` affinché il compilatore non ne inventi né ne ometta alcuno. **Nota sulla trasparenza**: l'editore dichiara fin dall'inizio che *« i post qui presenti sono redatti con l'IA, »* mentre i meccanismi, i dati e il codice restano propri.

## 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, browser fingerprint, anti-bot, automation detection, IEEE 754, correct rounding, ULP, unit in the last place, libm, glibc, libsystem_m, UCRT, ucrtbase, fdlibm, llvm-libc, dbl-64, V8, Blink, Chrome 148, V8 commit, Math.tanh, CSS trigonometric functions, degree-based angle reduction, Web Audio, DynamicsCompressor, Accelerate, vDSP, vvsin, vvtanh, FFT, biquad, Apple Silicon, ARM vs x86, FMA, fused multiply-add, NaN propagation, WASM, minimax coefficients, exponent tables, reduction constants, bit-for-bit reproduction, hexadecimal transcription, ffp-contract, determinism, noise as a countermeasure, spoofing inconsistency, contradictory User-Agent, detection surface, browser agents, 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

**Profilo**: articolo tecnico estremamente denso, nel registro dell'*engineering blog* di un fornitore di infrastrutture. Dodici minuti annunciati, nessuna concessione pedagogica: si apre con uno snippet da console e si chiude con codice C e coefficienti esadecimali.

**Stile**: **la dimostrazione precede la spiegazione**. Il testo si apre con tre righe da incollare in una console — `Math.tanh(0.8)` e i suoi tre output annotati per OS — prima di spiegarne il motivo. Poi una tabella di misurazioni reali su tre macchine fisiche, con la precisione che separa un aneddoto da un protocollo: *« Misurato tramite il protocollo DevTools su Chrome 150: Linux (glibc), macOS 26 su Apple Silicon (libsystem_m), Windows 11 (ucrtbase.dll). »*

**Due tratti metodologici**:

1. **L'input di test è scelto, non trovato.** *« tanh(0.5) è uno dei circa tre input su quattro su cui tutti concordano, ed è esattamente per questo che costituisce una sonda inutile. tanh(0.8) è uno che separa tutti e tre contemporaneamente. »* Il testo spiega **come si costruisce una sonda**, non semplicemente che ne esiste una.
2. **L'ambiguità è risolta sperimentalmente, non leggendo il codice.** Di fronte a due librerie Apple concorrenti: *« L'abbiamo risolta guidando Chrome reale su un Mac reale tramite il protocollo di debug e leggendo il double esatto. »*

**Registro argomentativo**: quello di una **confutazione ordinata**. La sezione "Quattro trappole" smonta una a una le soluzioni ovvie — *« "Basta reimplementare le funzioni Mac" si rompe al primo contatto, per quattro motivi »* — e la sezione seguente scarta la contromisura più intuitiva (il rumore) prima di proporre la propria.

**Frasi caratteristiche**: *« C'è un segnale più silenzioso, e vive negli ultimi bit di un numero »*, *« un rilevatore non ha bisogno di matematica, solo di una tabella »*, *« Dichiara macOS, restituisci bit matematici di Linux, e hai contraddetto il tuo stesso User-Agent »*, *« Scegli la libreria sbagliata per un dato punto di chiamata e finisci a 1 ULP di distanza sulla maggior parte degli input, peggio che non falsificare nulla »*, *« Il CSS è un indizio ovunque »*.

## Pense-betes

- **Il principio, in una riga**: IEEE 754 impone la **memorizzazione** di un `double`, non l'**arrotondamento corretto** delle funzioni trascendenti. L'arrotondamento corretto è costoso, quindi ogni sistema distribuisce la propria libm con i propri coefficienti minimax, tabelle e costanti di riduzione. **La differenza di arrotondamento è una firma.**
- **La sonda, utile da conoscere**: `Math.tanh(0.8)` restituisce `0.6640367702678491` su Linux (glibc), `0.664036770267849` su macOS (libsystem_m) e `0.6640367702678489` su Windows (UCRT) — **tutti e tre differiscono, di 2 ULP**. Linux e macOS divergono su circa **un quarto di tutti gli input**, tipicamente di **1 ULP**; Windows diverge da entrambi su qualche punto percentuale. → *« Un rilevatore non ha bisogno di matematica, solo di una tabella. »*
- **L'indizio è datato fino al commit, ed è ciò che rende l'articolo utile**: fino a **Chrome 147**, V8 calcolava `tanh` con una porta **fdlibm** integrata — stessi bit ovunque, **nessuna fuga**. Il commit V8 **`c1486295ae5`** l'ha sostituita con `std::tanh`, che legge la libm dell'host; distribuito in **V8 14.8.57 = Chrome 148**. **148, 149, 150 presentano la fuga. 147 e le versioni precedenti no.** → **Una regressione della privacy introdotta da una scelta di implementazione ordinaria**, e una finestra di versioni precisa per datare un'impronta.
- **La mappa delle fughe — la parte più riutilizzabile**: | Operazione | `Math.*` (JS) | CSS `calc()` | Web Audio | |---|---|---|---| | `sin cos tan` | V8 integrata | **libm dell'host** | Accelerate (FFT), scalare nel compressore | | `asin acos atan atan2` | V8 integrata | **libm dell'host** | non utilizzata | | `tanh` | **libm dell'host** | — | non utilizzata | | `exp`, `log*`, `pow` | V8 integrata | **libm dell'host** | scalare nel compressore | | vettoriale, FFT | — | — | **Accelerate (vDSP)** su Mac | | `sqrt`, aritmetica | hardware | hardware | hardware | → **V8 instrada quasi tutto attraverso la propria matematica integrata: JavaScript presenta una fuga in un solo punto, `Math.tanh`. Il CSS presenta fughe ovunque. Web Audio coinvolge tre librerie all'interno di un singolo grafo.**
- **WASM non presenta fughe relative al sistema operativo**: nessun opcode trascendente, `sin` proviene da qualunque libm il modulo abbia integrato, e l'aritmetica (`f64.sqrt`, `f64.mul`) è basata sull'hardware. **Il suo unico asse di fingerprinting è ARM contro x86** (canonicalizzazione di NaN, alcune differenze di arrotondamento SIMD).
- **Le quattro trappole — la vera lezione di progettazione, trasferibile ben oltre questo argomento**: 1. **Solo alcune funzioni presentano la fuga.** Falsificare le funzioni che **non** presentano la fuga crea un'incoerenza, e *« quell'asimmetria è essa stessa verificabile. »* → **Sovracorreggere è rilevabile quanto sottocorreggere.** 2. **JS e CSS sono percorsi di codice distinti.** Le funzioni trigonometriche CSS riducono l'angolo **in gradi** poi chiamano `std::sin` sul valore ridotto — un risultato diverso da un `sin()` in radianti. Il team ha riprodotto *« la riduzione in gradi e il passaggio da radianti a gradi bit a bit, non solo la funzione foglia. »* 3. **macOS ha due librerie matematiche che si contraddicono a vicenda.** La `libsystem_m` scalare e le routine vettoriali di Accelerate divergono dal **10 all'89%** degli input a seconda della funzione. `cos(0)`: `1.0` in scalare, `0.9999999999999999` in Accelerate. → *« "Riprodurre la matematica di Apple" resta indefinito finché non si sa quale libreria il browser chiami, e in quale punto. »* Risposta stabilita sperimentalmente: scalare per `Math.tanh`, trigonometria CSS e le funzioni trascendenti per-campione del compressore; Accelerate per il DSP di Web Audio (FFT, matematica vettoriale, filtri biquad). **Scegliere la libreria sbagliata costa 1 ULP sulla maggior parte degli input — peggio che non fare nulla.** 4. **Anche l'architettura presenta una fuga.** ARM e x86 differiscono sul fused multiply-add e sulla propagazione del segno di NaN; una riproduzione corretta sulla carta va alla deriva se il compilatore fonde le operazioni da un lato e non dall'altro.
- **Perché il rumore non funziona — un argomento generalizzabile a qualunque contromisura di fingerprinting**: *« Perturbare l'output fallisce due volte. Un confronto di riferimento vede un valore che non corrisponde a nessun OS reale, e la casualità a ogni chiamata rompe il determinismo, che è essa stessa un indizio. »* → **Una difesa che produce un valore impossibile è identificativa tanto quanto un valore vero.** L'obiettivo non è "il rumore", è **il valore esatto del sistema dichiarato**.
- **La contromisura scelta, e i suoi tre requisiti**: (1) **recuperare** i coefficienti minimax, le tabelle degli esponenti e le costanti di riduzione della libm target e **trascriverli in C portabile**; (2) **copiare i pattern di bit in esadecimale** — *« una trascrizione decimale arrotonderebbe in modo diverso »*; (3) **scrivere ogni fusione come `fma()` esplicito** e compilare con **`-ffp-contract=off`**, affinché le operazioni fuse siano esattamente quelle che Apple fonde e il risultato sia identico su CPU con e senza FMA, e **tra la macchina ARM emulata e la flotta x86 che esegue l'operazione**. Quando la riproduzione non vale lo sforzo: *« riprendere l'originale »* — poiché Windows UCRT è x86-64 e a codice indipendente dalla posizione.
- **Ciò che l'articolo implica per gli agenti che navigano** — non dichiarato nel testo, ma diretto: un agente che guida un browser per leggere il web attraversa esattamente questi controlli. Gli harness che **escalano al browser reale dell'utente** invece di imitarne uno (cfr. il percorso browser di [[skill-gibbs-hyperresearch-2026-08-03]], che guida il vero Chrome autenticato e pone come confine rigido che *« CAPTCHA, 2FA e login non vengono mai risolti automaticamente »*) aggirano il problema per costruzione: **non c'è nulla da falsificare quando il browser è realmente ciò che dichiara di essere.** Due strategie opposte di fronte allo stesso muro.
- **Inquadramento d'uso**: l'articolo documenta una tecnica di **elusione del rilevamento**, scritta da un fornitore di web scraping. È utilizzabile in modo difensivo (capire cosa legga realmente il proprio sistema anti-bot, e sapere che un singolo segnale `Math.tanh` isolato data il browser tanto quanto identifica l'OS) così come per l'elusione. **Il testo non affronta il consenso dei siti sottoposti a scraping**, né i termini di servizio — ciò esula dal suo ambito dichiarato.
- **Redazione assistita dall'IA, dichiarata**: *« i post qui presenti sono redatti con l'IA… I meccanismi, i dati e il codice sono nostri. »* Una dichiarazione onesta e rara, degna di nota quando si cita il testo come fonte primaria. Le misurazioni sono accompagnate dal loro protocollo (protocollo DevTools, tre macchine nominate con le rispettive versioni), il che le rende verificabili in modo indipendente a prescindere da come sia stata prodotta la prosa.
- **Meta / correlati**: sugli agenti che guidano il browser, [[skill-gibbs-hyperresearch-2026-08-03]] (percorso browser, escalation, confine CAPTCHA); sulla superficie d'attacco e i contenuti web trattati come dati ostili, [[valente-zalewski-beyond-zero-enterprise-security-ai-era-2026-07-20]]; sui browser IA e l'automazione, [[mody-browser-company-arc-dia-ai-native-2025-11-23]], perplexity-chrome-integration-browser-ai-search-2025-10-22, e mcp-replaces-browser-logrocket-2025-09-15.

## RésuméDe400mots

Articolo di **Scrapfly Engineering** (12 luglio 2026) su un canale di *fingerprinting* annidato **negli ultimi bit di un numero**.

**Il meccanismo.** Lo standard IEEE 754 definisce come viene memorizzato un `double` ma **non impone** l'arrotondamento corretto delle funzioni trascendenti. Poiché l'arrotondamento corretto è costoso, ogni piattaforma distribuisce una **libm** con i propri coefficienti minimax, tabelle e costanti. Ne risulta che `Math.tanh(0.8)` restituisce tre valori distinti a seconda di glibc, libsystem_m e UCRT. Linux e macOS divergono su circa un quarto degli input, tipicamente di **1 ULP**. *« Un rilevatore non ha bisogno di matematica, solo di una tabella. »* E l'incoerenza è immediatamente sfruttabile: dichiarare macOS restituendo bit di Linux **contraddice il proprio User-Agent**.

**L'indizio è recente e datato.** Fino a **Chrome 147**, V8 calcolava `tanh` con una fdlibm integrata, identica ovunque. Il commit `c1486295ae5` l'ha sostituita con `std::tanh`, che legge la libm dell'host, distribuito con **Chrome 148**.

**Tre superfici presentano fughe.** `Math.tanh` è l'**unica** funzione `Math.*` interessata — V8 integra e collega staticamente tutto il resto. Tutte le **sette funzioni trigonometriche CSS** presentano fughe, con Blink che chiama la libm dell'host dopo una riduzione dell'angolo in gradi che non condivide codice con `Math.sin`. E **Web Audio** coinvolge tre librerie all'interno di un singolo grafo: Accelerate per le fasi FFT e vettoriali, libsystem_m scalare per le funzioni trascendenti del compressore. WASM, invece, non presenta fughe relative al sistema operativo — solo all'architettura.

**Quattro trappole** rendono difficile la contromisura: solo alcune funzioni presentano la fuga, quindi **falsificare le altre crea un'asimmetria rilevabile**; JavaScript e CSS sono percorsi di codice separati; **macOS integra due librerie matematiche che divergono tra loro** dal 10 all'89% a seconda della funzione, per cui "riprodurre la matematica di Apple" non ha senso finché non si sa quale venga chiamata in quale punto; e ARM e x86 differiscono su fused multiply-add e propagazione di NaN.

**Il rumore non funziona**: produce un valore che non corrisponde a **nessun** OS reale, e il suo non-determinismo è a sua volta un segnale. L'unica via è la **riproduzione bit a bit** — coefficienti estratti dalla libm target e trascritti in esadecimale, ogni fusione scritta come `fma()` esplicito, compilata con `-ffp-contract=off`.

L'editore dichiara che i propri post sono **redatti con l'assistenza dell'IA**, mentre i meccanismi, i dati e il codice restano propri.

## 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/it/fiches/scrapfly-browser-math-os-fingerprint-2026-07-12/
