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

## Veille

Engineering-Artikel, veröffentlicht am **12. Juli 2026** von **Scrapfly Engineering**, über einen wenig bekannten Browser-*Fingerprinting*-Kanal: **die letzten Bits einer Gleitkommazahl verraten das Betriebssystem**. **Der Mechanismus**: IEEE 754 legt fest, wie ein `double` gespeichert wird, verlangt aber **nicht**, dass `sin`, `cos`, `tanh` oder `exp` korrekt gerundet werden; jedes System liefert daher eine eigene **libm**, die einen Bruchteil eines ULP gegen Geschwindigkeit eintauscht, mit eigenen Minimax-Koeffizienten, Tabellen und Reduktionskonstanten. Dadurch liefert `Math.tanh(0.8)` **drei unterschiedliche Werte**, je nach glibc (Linux), libsystem_m (macOS) und UCRT (Windows) — „ein einziger tanh-Aufruf mit dem richtigen Eingabewert ist eine Signatur pro Betriebssystem. Wer macOS behauptet, aber Linux-Rechenbits zurückgibt, widerspricht dem eigenen User-Agent.“ **Das Erkennungsmerkmal ist neu und lässt sich genau datieren**: bis **Chrome 147** berechnete V8 `tanh` mit einem eingebetteten **fdlibm**-Port, überall identisch und ohne jedes Leck; der V8-Commit `c1486295ae5` ersetzte ihn durch `std::tanh`, ausgeliefert in V8 14.8.57, also **Chrome 148** — 148, 149 und 150 lecken, 147 und früher nicht. **Drei Oberflächen bündeln die Lecks**: `Math.tanh` (die **einzige** betroffene `Math.*`-Funktion, da V8 alle übrigen einbettet und statisch verlinkt), **sämtliche CSS-Trigonometriefunktionen** (Blink ruft direkt die libm des Hosts auf, nach einer gradbasierten Winkelreduktion, die keinen Code mit `Math.sin` teilt), und **Web Audio** (wo der Kompressor bei skalarer libsystem_m bleibt, während FFT- und Vektorstufen über **Accelerate** laufen). **Vier Fallen** erschweren die Gegenmaßnahme: Nur manche Funktionen lecken — daher **erzeugt das Fälschen der übrigen eine erkennbare Inkonsistenz**; JavaScript und CSS sind getrennte Codepfade; **macOS enthält zwei Mathematikbibliotheken, die voneinander abweichen** (skalar vs. Accelerate, je nach Funktion bei 10 bis 89 % der Eingabewerte: `cos(0)` liefert auf der einen Seite `1.0`, auf der anderen `0.9999999999999999`); und **auch die Architektur leckt** (FMA und die Vorzeichenweitergabe bei NaN unterscheiden sich zwischen ARM und x86). **Die verworfene und die gewählte Gegenmaßnahme**: Rauschen hinzuzufügen scheitert zweifach — der Wert stimmt mit **keinem** realen Betriebssystem überein, und die fehlende Determinismus pro Aufruf ist selbst ein Erkennungsmerkmal. Der einzige Weg ist die **bitgenaue Reproduktion**: die Koeffizienten der Ziel-libm extrahieren, sie **hexadezimal** transkribieren (eine dezimale Transkription würde anders runden), jede fused multiply-add-Operation explizit als `fma()` schreiben und mit `-ffp-contract=off` kompilieren, damit der Compiler keine davon erfindet oder wegoptimiert. **Bemerkenswerter Hinweis**: Der Herausgeber stellt vorab klar, dass „die Beiträge hier mit KI verfasst werden“, während Mechanismen, Zahlen und Code aus eigener Feder stammen.

## 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-Fingerabdruck, Anti-Bot, Automatisierungserkennung, IEEE 754, korrekte Rundung, 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-Trigonometriefunktionen, gradbasierte Winkelreduktion, Web Audio, DynamicsCompressor, Accelerate, vDSP, vvsin, vvtanh, FFT, Biquad, Apple Silicon, ARM vs. x86, FMA, fused multiply-add, NaN-Weitergabe, WASM, Minimax-Koeffizienten, Exponententabellen, Reduktionskonstanten, bitgenaue Reproduktion, hexadezimale Transkription, ffp-contract, Determinismus, Rauschen als Gegenmaßnahme, Fälschungsinkonsistenz, widersprüchlicher User-Agent, Erkennungsoberfläche, Browser-Agenten, 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

**Profil**: außerordentlich dichter Engineering-Artikel, im *Engineering-Blog*-Register eines Infrastrukturanbieters. Zwölf Minuten Lesezeit angekündigt, keine didaktischen Zugeständnisse: Er beginnt mit einem Konsolen-Snippet und endet mit C-Code und hexadezimalen Koeffizienten.

**Stil**: **Die Demonstration geht der Erklärung voraus.** Der Text öffnet mit drei Zeilen, die in eine Konsole eingefügt werden können — `Math.tanh(0.8)` und seine drei nach Betriebssystem annotierten Ausgaben — bevor erklärt wird, warum. Dann eine Tabelle realer Messungen auf drei physischen Maschinen, mit der Präzision, die eine Anekdote von einem Protokoll unterscheidet: „Gemessen über das DevTools-Protokoll auf Chrome 150: Linux (glibc), macOS 26 auf Apple Silicon (libsystem_m), Windows 11 (ucrtbase.dll).“

**Zwei methodische Merkmale**:

1. **Der Testeingabewert ist gewählt, nicht gefunden.** „tanh(0.5) ist einer der etwa drei von vier Eingabewerten, bei denen alle übereinstimmen, was genau der Grund ist, warum er eine nutzlose Sonde abgibt. tanh(0.8) ist einer, der alle drei auf einmal trennt.“ Der Text erklärt, **wie eine Sonde konstruiert wird**, nicht nur, dass es sie gibt.
2. **Mehrdeutigkeit wird experimentell aufgelöst, nicht durch Codelektüre.** Angesichts zweier konkurrierender Apple-Bibliotheken: „Wir haben das aufgelöst, indem wir einen echten Chrome auf einem echten Mac über das Debugging-Protokoll gesteuert und den exakten double-Wert ausgelesen haben.“

**Argumentatives Register**: das einer **geordneten Widerlegung**. Der Abschnitt „Vier Fallen“ zerlegt die naheliegenden Lösungen eine nach der anderen — „‚Einfach die Mac-Funktionen nachimplementieren‘ scheitert sofort, aus vier Gründen“ — und der folgende Abschnitt schließt die naheliegendste Gegenmaßnahme (Rauschen) aus, bevor er die eigene vorschlägt.

**Markante Formulierungen**: „Es gibt ein leiseres Signal, und es steckt in den letzten Bits einer Zahl“, „ein Detektor braucht keine Mathematik, nur eine Tabelle“, „macOS behaupten, aber Linux-Rechenbits zurückgeben, widerspricht dem eigenen User-Agent“, „die falsche Bibliothek für eine gegebene Aufrufstelle zu wählen, kostet bei den meisten Eingabewerten 1 ULP — schlimmer, als gar nicht zu fälschen“, „CSS ist überall ein Erkennungsmerkmal“.

## Pense-betes

- **Das Prinzip, in einem Satz**: IEEE 754 schreibt die **Speicherung** eines `double` vor, nicht die **korrekte Rundung** transzendenter Funktionen. Korrekte Rundung ist teuer, daher liefert jedes System seine eigene libm mit eigenen Minimax-Koeffizienten, Tabellen und Reduktionskonstanten. **Der Rundungsunterschied ist eine Signatur.**
- **Die Sonde, die man kennen sollte**: `Math.tanh(0.8)` liefert `0.6640367702678491` unter Linux (glibc), `0.664036770267849` unter macOS (libsystem_m) und `0.6640367702678489` unter Windows (UCRT) — **alle drei unterscheiden sich, um 2 ULP**. Linux und macOS weichen bei rund **einem Viertel aller Eingabewerte** voneinander ab, typischerweise um **1 ULP**; Windows weicht bei einigen Prozent von beiden ab. → „Ein Detektor braucht keine Mathematik, nur eine Tabelle.“
- **Das Erkennungsmerkmal ist bis auf den Commit genau datiert, und genau das macht den Artikel nützlich**: bis **Chrome 147** berechnete V8 `tanh` mit einem eingebetteten **fdlibm**-Port — überall dieselben Bits, **kein Leck**. Der V8-Commit **`c1486295ae5`** ersetzte ihn durch `std::tanh`, das die libm des Hosts liest; ausgeliefert in **V8 14.8.57 = Chrome 148**. **148, 149, 150 lecken. 147 und früher nicht.** → **Eine Datenschutzregression, ausgelöst durch eine unspektakuläre Implementierungsentscheidung**, und ein präzises Versionsfenster, um einen Fingerabdruck zu datieren.
- **Die Leck-Übersicht — der am besten wiederverwendbare Teil**: | Operation | `Math.*` (JS) | CSS `calc()` | Web Audio | |---|---|---|---| | `sin cos tan` | in V8 eingebettet | **libm des Hosts** | Accelerate (FFT), skalar im Kompressor | | `asin acos atan atan2` | in V8 eingebettet | **libm des Hosts** | nicht verwendet | | `tanh` | **libm des Hosts** | — | nicht verwendet | | `exp`, `log*`, `pow` | in V8 eingebettet | **libm des Hosts** | skalar im Kompressor | | Vektor, FFT | — | — | **Accelerate (vDSP)** auf dem Mac | | `sqrt`, Arithmetik | Hardware | Hardware | Hardware | → **V8 leitet fast alles über seine eigene eingebettete Mathematik: JavaScript leckt nur an einer einzigen Stelle, `Math.tanh`. CSS leckt überall. Web Audio berührt drei Bibliotheken innerhalb eines einzigen Graphen.**
- **WASM leckt nicht das Betriebssystem**: kein transzendenter Opcode, `sin` stammt aus der libm, die das Modul eingebettet hat, und Arithmetik (`f64.sqrt`, `f64.mul`) basiert auf Hardware. **Seine einzige Fingerprinting-Achse ist ARM vs. x86** (NaN-Kanonisierung, einige SIMD-Rundungsunterschiede).
- **Die vier Fallen — die eigentliche Design-Lektion, weit über dieses Thema hinaus übertragbar**: 1. **Nur manche Funktionen lecken.** Das Fälschen der Funktionen, die **nicht** lecken, erzeugt eine Inkonsistenz, und „diese Asymmetrie ist selbst überprüfbar.“ → **Überkorrektur ist ebenso erkennbar wie Unterkorrektur.** 2. **JS und CSS sind getrennte Codepfade.** CSS-Trigonometriefunktionen reduzieren den Winkel **in Grad** und rufen dann `std::sin` auf den reduzierten Wert auf — ein anderes Ergebnis als ein `sin()` in Radiant. Das Team reproduzierte „die Gradreduktion und den Schritt von Radiant zu Grad bitgenau, nicht nur die Blattfunktion.“ 3. **macOS hat zwei Mathematikbibliotheken, die sich widersprechen.** Die skalare `libsystem_m` und Accelerates Vektorroutinen weichen je nach Funktion bei **10 bis 89 %** der Eingabewerte voneinander ab. `cos(0)`: `1.0` skalar, `0.9999999999999999` mit Accelerate. → „‚Apples Mathematik nachbilden‘ ist so lange undefiniert, bis man weiß, welche Bibliothek der Browser an welcher Stelle aufruft.“ Experimentell ermittelte Antwort: skalar für `Math.tanh`, CSS-Trigonometrie und die Per-Sample-Transzendenten des Kompressors; Accelerate für Web-Audio-DSP (FFT, Vektormathematik, Biquad-Filter). **Die falsche Bibliothek zu wählen kostet bei den meisten Eingabewerten 1 ULP — schlimmer, als gar nichts zu tun.** 4. **Die Architektur leckt ebenfalls.** ARM und x86 unterscheiden sich bei fused multiply-add und bei der Vorzeichenweitergabe von NaN; eine auf dem Papier korrekte Reproduktion driftet, wenn der Compiler auf der einen Seite fusioniert und auf der anderen nicht.
- **Warum Rauschen nicht funktioniert — ein Argument, das sich auf jede Fingerprinting-Gegenmaßnahme verallgemeinern lässt**: „Die Ausgabe zu stören scheitert zweifach. Ein Referenzvergleich sieht einen Wert, der mit keinem realen Betriebssystem übereinstimmt, und die Zufälligkeit pro Aufruf bricht die Determinismus, was selbst ein Erkennungsmerkmal ist.“ → **Eine Verteidigung, die einen unmöglichen Wert erzeugt, ist genauso identifizierend wie ein echter.** Das Ziel ist nicht „Rauschen“, sondern **der exakte Wert des behaupteten Systems**.
- **Die gewählte Gegenmaßnahme und ihre drei Anforderungen**: (1) Minimax-Koeffizienten, Exponententabellen und Reduktionskonstanten der Ziel-libm **abrufen** und **in portablen C-Code übertragen**; (2) **die Bitmuster hexadezimal kopieren** — „eine dezimale Transkription würde anders runden“; (3) **jede Fusion als explizites `fma()`** schreiben und mit **`-ffp-contract=off`** kompilieren, damit die fusionierten Operationen genau die sind, die Apple fusioniert, und das Ergebnis auf CPUs mit und ohne FMA identisch ist, ebenso **zwischen der emulierten ARM-Maschine und der ausführenden x86-Flotte**. Wenn Reproduktion den Aufwand nicht wert ist: „das Original übernehmen“ — da Windows UCRT x86-64 und positionsunabhängig ist.
- **Was der Artikel für browsergesteuerte Agenten impliziert** — im Text nicht ausgesprochen, aber naheliegend: Ein Agent, der einen Browser steuert, um das Web zu lesen, durchläuft genau diese Prüfungen. Harnesses, die **auf den echten Browser des Nutzers eskalieren**, statt einen zu imitieren (vgl. den Browser-Pfad von [[skill-gibbs-hyperresearch-2026-08-03]], der den authentifizierten echten Chrome steuert und als harte Grenze festlegt, dass „CAPTCHAs, 2FA und Logins niemals automatisch gelöst werden“), umgehen das Problem konstruktionsbedingt: **Es gibt nichts zu fälschen, wenn der Browser tatsächlich das ist, was er vorgibt zu sein.** Zwei entgegengesetzte Strategien vor derselben Wand.
- **Einordnung der Nutzung**: Der Artikel dokumentiert eine Technik zur **Umgehung von Erkennung**, verfasst von einem Anbieter für Web-Scraping. Sie ist defensiv nutzbar (um zu verstehen, was das eigene Anti-Bot-System tatsächlich liest, und zu wissen, dass ein isoliertes `Math.tanh`-Signal den Browser ebenso datiert wie es das Betriebssystem identifiziert) wie auch zur Umgehung. **Der Text geht nicht auf die Einwilligung der gescrapten Websites ein**, ebenso wenig auf Nutzungsbedingungen — das liegt außerhalb seines erklärten Anspruchs.
- **KI-unterstütztes Verfassen, offengelegt**: „die Beiträge hier werden mit KI verfasst … Die Mechanismen, die Zahlen und der Code stammen von uns.“ Eine ehrliche und seltene Offenlegung, erwähnenswert, wenn der Text als Primärquelle zitiert wird. Die Messungen kommen mit ihrem Protokoll (DevTools-Protokoll, drei benannte Maschinen mit ihren Versionen), was sie unabhängig überprüfbar macht, unabhängig davon, wie der Fließtext entstanden ist.
- **Meta / verwandt**: zu browsersteuernden Agenten [[skill-gibbs-hyperresearch-2026-08-03]] (Browser-Pfad, Eskalation, CAPTCHA-Grenze); zur Angriffsfläche und Webinhalten als feindlich behandelten Daten [[valente-zalewski-beyond-zero-enterprise-security-ai-era-2026-07-20]]; zu KI-Browsern und Automatisierung [[mody-browser-company-arc-dia-ai-native-2025-11-23]], perplexity-chrome-integration-browser-ai-search-2025-10-22 und mcp-replaces-browser-logrocket-2025-09-15.

## RésuméDe400mots

Artikel von **Scrapfly Engineering** (12. Juli 2026) über einen *Fingerprinting*-Kanal, der **in den letzten Bits einer Zahl** sitzt.

**Der Mechanismus.** IEEE 754 legt fest, wie ein `double` gespeichert wird, verlangt aber **nicht** die korrekte Rundung transzendenter Funktionen. Da korrekte Rundung teuer ist, liefert jede Plattform eine eigene **libm** mit eigenen Minimax-Koeffizienten, Tabellen und Konstanten. Dadurch liefert `Math.tanh(0.8)` drei unterschiedliche Werte, je nach glibc, libsystem_m und UCRT. Linux und macOS weichen bei rund einem Viertel der Eingabewerte voneinander ab, typischerweise um **1 ULP**. „Ein Detektor braucht keine Mathematik, nur eine Tabelle.“ Und die Inkonsistenz ist unmittelbar ausnutzbar: macOS zu behaupten, aber Linux-Bits zurückzugeben, **widerspricht dem eigenen User-Agent**.

**Das Erkennungsmerkmal ist neu und datiert.** Bis **Chrome 147** berechnete V8 `tanh` mit einem eingebetteten fdlibm, überall identisch. Der Commit `c1486295ae5` ersetzte ihn durch `std::tanh`, das die libm des Hosts liest, ausgeliefert mit **Chrome 148**.

**Drei Oberflächen lecken.** `Math.tanh` ist die **einzige** betroffene `Math.*`-Funktion — V8 bettet alle übrigen ein und verlinkt sie statisch. Alle **sieben CSS-Trigonometriefunktionen** lecken, wobei Blink die libm des Hosts nach einer gradbasierten Winkelreduktion aufruft, die keinen Code mit `Math.sin` teilt. Und **Web Audio** berührt drei Bibliotheken innerhalb eines einzigen Graphen: Accelerate für FFT- und Vektorstufen, skalare libsystem_m für die transzendenten Funktionen des Kompressors. WASM dagegen leckt nicht das Betriebssystem — nur die Architektur.

**Vier Fallen** erschweren die Gegenmaßnahme: Nur manche Funktionen lecken, sodass **das Fälschen der übrigen eine erkennbare Asymmetrie erzeugt**; JavaScript und CSS sind getrennte Codepfade; **macOS enthält zwei Mathematikbibliotheken, die voneinander abweichen**, je nach Funktion um 10 bis 89 %, sodass „Apples Mathematik nachbilden“ erst dann Sinn ergibt, wenn klar ist, welche an welcher Stelle aufgerufen wird; und ARM und x86 unterscheiden sich bei fused multiply-add und der NaN-Weitergabe.

**Rauschen funktioniert nicht**: Es erzeugt einen Wert, der mit **keinem** realen Betriebssystem übereinstimmt, und sein fehlender Determinismus ist selbst ein Signal. Der einzige Weg ist die **bitgenaue Reproduktion** — Koeffizienten aus der Ziel-libm extrahiert und hexadezimal transkribiert, jede Fusion als explizites `fma()` geschrieben, kompiliert mit `-ffp-contract=off`.

Der Herausgeber gibt an, dass seine Beiträge **mit KI-Unterstützung verfasst** werden, während Mechanismen, Zahlen und Code aus eigener Feder stammen.

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