Skip to content
All fingerprint checks
Error subsystem

FontFace rejects bytes that are not a font, with a DOMException

Pim· Clearcote Research 3 min readCheck id fontface-rejects-invalid-font-data

Every load of the garbage bytes rejects, and every rejection is a DOMException (SyntaxError on every browser measured; NetworkError is also accepted). N/A where the FontFace API is not exposed or no load settles within three seconds (severity: warn).

What a detector infers

The CSS Font Loading API lets a page build a font face from bytes it already holds: new FontFace(family, buffer).load(). What happens to bytes that are not a font is fixed by the specification, not by the platform: the promise rejects with a SyntaxError DOMException and the face's status becomes "error". The family name plays no part in that; it is only the name the face would be registered under.

So this row hands the loader 256 bytes that parse as no font format, under a random family name and under four common system names, and reads two things: whether any of those loads succeeded, and whether every rejection was a DOMException.

Measured on 2026-09-24, Chrome, Edge and Brave 153 and Firefox 156 rejected every one with a SyntaxError DOMException, and Firefox did so in a private window, with resistFingerprinting, with fingerprinting protection on all targets, with page fonts or downloadable fonts switched off, with a system-font allowlist and at the lowest font-visibility level. Playwright's Firefox 144 did the same. Camoufox gates this path on the family name instead.

Under a name on its persona's font allowlist, such as Arial, the garbage is reported loaded without being parsed (an empty buffer, a 404 url() and a missing local() face also "load"). Under any other name the load is refused with NS_ERROR_FAILURE, an internal Gecko error code that genuine Firefox never passes to a page. The same gate refuses real fonts under names it does not know, which is why ordinary web fonts misbehave in it.

How to resolve it

Leave the web-font path alone. A font allowlist belongs on system-font lookup, meaning local() and the fonts a page can enumerate, not on faces the page supplies itself. A patched loader has to keep both specified outcomes: bytes that are not a font reject with a SyntaxError DOMException, and a real font loads under any family name.

Read in the wild by

Camoufox (measured)

Measured while establishing ground truth for this row, from a page script in the main world. Every persona tried either reports the garbage as a loaded font under Arial or leaks NS_ERROR_FAILURE under the random name, and all but one do both.

Camoufox 152.0.4-beta.30 (python package cloverlabs-camoufox 0.6.0): default, os=macos and NewContext macOS and Linux personas load the garbage under Arial (status "loaded") and reject the random name with NS_ERROR_FAILURE ([object Exception], not a DOMException). os=linux rejects both names with NS_ERROR_FAILURE. A 153.2-based fork behaves like the default. Twelve genuine configurations on the same machine: SyntaxError DOMException under both names.

camoufox.com

Camoufox issues

Traces FontFace status and loading through a single family-name helper, IsFontAllowed in FontFaceImpl.h, which consults the persona's font allowlist. The issue reads the local() half of that gate; this row reads what the same helper does to bytes the page supplies itself.

daijro/camoufox#759

Every attribution traces to a published artifact. See the sources and their limits.

Other checks in Error subsystem

Who builds this test

Clearcote is a browser built for fingerprint coherence

It is a Chromium fork, maintained by the same people who wrote this reference. It ships as a compiled browser rather than as a stealth script injected into someone else's — which is a description of how it is built, and is not an argument about how it behaves on this check.

This audit takes no position on how Clearcote scores on Error subsystem checks, on this one, or anywhere else. It has no baseline corpus of other people's fingerprints to rank you against and no vendor scoreboard — nearly every check is self-referential, asking one browser the same question through two independent APIs and reporting whether both answers can be true at once. It runs identically on any browser, including ours. Run it on yours and read the result yourself.

See the other checks in Error subsystem — the family fontface-rejects-invalid-font-data belongs to.