demo · v148
Incognito Fingerprint Sandbox
A reproduction of the privacy attack this change closes. The same fingerprinting heuristic that worked pre-Chrome-148 — "quota under ~120 MB ⇒ incognito" — now produces an unreliable result. Run it in a regular tab and an incognito tab and see the verdict line up where it used to diverge.
The attack: incognito mode allocated a small fixed storage quota, very different
from the dynamically-computed quota of a normal profile. Pages could call
navigator.storage.estimate() and infer the user's mode from the magnitude of the
number alone. Chrome 148 stops reporting the true quota delta to unprivileged origins, so the
heuristic loses its signal — even though the underlying storage behaviour is unchanged.
navigator.storage.estimate()
Heuristic signal
Run the probe
Click "Probe quota" below to compute the fingerprint. Try the same page in an incognito tab and compare verdicts.
probe history
| time | quota (MB) | usage (MB) | signal | verdict |
|---|---|---|---|---|
| No probes yet. | ||||
the code (the attack)
// What every fingerprinting library did before Chrome 148:
const { quota } = await navigator.storage.estimate();
const incognitoLikely = quota < 200 * 1024 * 1024; // < 200 MB ⇒ probably incognito
if (incognitoLikely) {
fetch("/fingerprint", { method: "POST", body: JSON.stringify({ mode: "incognito" }) });
}
// In Chrome 148+, quota is no longer the dramatically-smaller incognito-only value
// for unprivileged origins. The heuristic gives a near-identical answer in both modes.
see also
- Predictable reported storage quota — feature index
- Quota Inspector — sibling concept
- MDN: StorageManager.estimate()
- ChromeStatus entry
implementation reference
Need the exact API surface, compatibility boundaries, errors, lifecycle, and source links? Read the matching gendn reference ↗