# Partial fingerprint spoofing detection: half a spoof

> Partial fingerprint spoofing detection is simple: ask one question two ways. We cut five spoofs that changed one route to a value and left the other.

Source: https://mosaicbrowser.com/blog/half-a-spoof

## Half a spoof is a contradiction

Partial fingerprint spoofing detection is simple: ask one question two ways. We cut five spoofs that changed one route to a value and left the other.

![Two routes to one value, and only one of them moved, beside a screenshot: mosaic settings showing the installed Tesseract Chrome engine and its version](https://mosaicbrowser.com/covers/half-a-spoof.webp)

Partial fingerprint spoofing detection works by asking one question two ways. If a browser changes the answer on one route and leaves the other alone, a page that asks both gets two answers, and no real browser disagrees with itself. We removed or cut back five spoofs in our engine for exactly this reason. Each one could cover only one of the routes a page uses to read the same fact.

## Fonts: listed one way, measured another

A page can ask whether a font is installed with `document.fonts.check`. It can also draw a string in that font and compare its width with the same string in a fallback font. If the widths differ, the font is there. That second way is how fingerprinting scripts actually enumerate fonts.

Our old patch answered `document.fonts.check` from the profile's generated font list and did nothing about measurement. A page asking both ways could find a font that reports absent and renders, or reports present and renders as the fallback. Either pairing is impossible on a real machine.

## Keyboard: the size and the type gave it away

`navigator.keyboard.getLayoutMap()` returns a map of keys to the characters they produce. Our patch returned six entries, the keys that differ between common layouts. A real one returns about fifty, so the size alone identified the browser. It also returned a plain `Map`, where the real API returns a `KeyboardLayoutMap`. The prototype said it a second time.

## Media codecs: a downgrade the hardware contradicts

Our codec table was consulted in both directions. So a Mac that decodes HEVC in hardware answered `"no"` when a page probed for H.265, while the hardware itself could play the file. The table now only ever upgrades: it can add a proprietary codec a Chromium build is missing, and never removes one the engine really supports.

Mosaic is a desktop app

Email yourself the link and open it on your computer.

[How it works: Its own Chromium](https://mosaicbrowser.com/features/engine)

## Speech voices: right on desktop, wrong on Android

The voice spoof was a fixed table of 45 macOS voice names. Thirteen were not installed on our build Mac, and a few, Fiona and Victoria among them, Apple had dropped years earlier. A voice set that matches no real install of the claimed system is the same mistake as claiming a browser version whose features are missing. We removed the table, and desktop profiles report the computer's own voices, which is the right answer when the profile claims the system the computer runs.

That reasoning missed one case. An Android profile and a macOS profile drawn on the same Mac both reported 180 voices, byte for byte the same, and the voices were Apple's: Albert, Alice, Alva, Amélie. No Android phone has reported `Amélie`, and `getVoices()` needs no permission. The engine already had a switch for voices. What it lacked was data about real phones, and one honest answer needs none: a device with no speech engine. Android profiles now send `--fingerprint-voices=none` and report zero voices. That is less common than a phone with voices, and it is possible, which the Mac's list on a phone was not.

## The camera: a filter can only remove

The camera spoof filtered the engine's device list by counts the generator drew. A filter can only take things out, so its one possible effect was to say "this machine has no camera", on a machine with one, while `getUserMedia` went on opening it. It also leaned the implausible way: a desktop with a webcam plugged in is ordinary, and a MacBook Pro without a camera does not exist. Our comparison against stock Chrome caught it intermittently, only when a draw landed on a cameraless desktop:

```
stock  audioinput,videoinput,audiooutput
ours   audioinput,audiooutput

```

![Settings showing the installed Tesseract Chrome engine](https://mosaicbrowser.com/shots/engine.png)
*The values that stay are changed in the engine, in C++*

## What partial spoofing detection teaches

Only spoof a surface if every route to it can be made to agree. Where that is not possible, report the machine's truth. Two profiles on one computer then share their fonts, keyboard and codecs, as they already share the TLS handshake and other values that come from the real machine. A shared truth gives a site less to object to than a private contradiction.

This is also why Tesseract Chrome changes values in C++ rather than in page JavaScript: a value changed inside the engine reaches every frame and worker, so the routes agree by construction. [C++, not JavaScript](https://mosaicbrowser.com/blog/cpp-not-javascript) has the case where a JavaScript spoof gave its own source away to an iframe, and [the engine page](https://mosaicbrowser.com/features/engine) lists what the patches cover. The same thinking retired three more invented values (the storage quota, `performance.memory` and `navigator.connection`), each of which a page could check by measuring the thing it described.

How detectors look for these contradictions in general is in [how sites detect anti-detect browsers](https://mosaicbrowser.com/guides/how-do-sites-detect-anti-detect-browsers). The values we found coming from the computer rather than the profile are in [the values every profile inherited from this Mac](https://mosaicbrowser.com/blog/values-inherited-from-the-host).

## Questions

### How do sites detect partial fingerprint spoofing?

By asking the same question two ways. A font list can be read from an API and measured by rendering text; a keyboard layout has a size and a type. If one route was changed and the other was not, the answers disagree, and no real browser disagrees with itself.

### Is it better to spoof a value or leave the real one?

If every route to the value can be made to agree, spoof it. If not, report the machine's real value. Two profiles on one computer then share it, as they already share many hardware values, and a shared truth is harder to object to than a private contradiction.

### Which surfaces did Mosaic stop spoofing?

Fonts, the keyboard layout map, media codec answers in the downgrade direction, desktop speech voices and the camera list. Each could only be changed on one of the routes a page uses to read it.

### Do Android profiles report speech voices?

They report none, as a phone with text-to-speech disabled would. Before that, they reported the Mac's own 180 voices, which no Android device has.

## Related

[Why we change fingerprints in C++, not JavaScript](https://mosaicbrowser.com/blog/cpp-not-javascript): A JavaScript spoof is one realm deep. An iframe read the real source of 33 of our patched functions; the same values changed in C++ agree everywhere.

[The values every profile inherited from this Mac](https://mosaicbrowser.com/blog/values-inherited-from-the-host): A browser fingerprint value inherited from the host is identical across two unrelated profiles and equal to the computer. That test found dark mode and more.

[An anti-detect browser with its own Chromium engine](https://mosaicbrowser.com/features/engine): Mosaic is an anti-detect browser with its own Chromium engine, Tesseract Chrome: stock source plus 64 patches that change fingerprint values in C++.

[Browser fingerprinting: how sites recognise a browser without cookies](https://mosaicbrowser.com/glossary/browser-fingerprinting): Browser fingerprinting is recognising a browser by reading its hardware, settings and rendering quirks instead of storing a cookie. How sites do it.

[How do sites detect anti-detect browsers?](https://mosaicbrowser.com/guides/how-do-sites-detect-anti-detect-browsers): Sites detect anti-detect browsers by contradictions: a page and its workers disagreeing, a GPU name the driver does not match, fonts from another OS.







## Mosaic, on your own computer

The browser this blog is about: its own Chromium, fingerprints from real machines and a proxy exit per profile. Free holds 3 profiles. Pro is $49 a month for any number.

Mosaic is a desktop app

Email yourself the link and open it on your computer.
