Onyx Digital Intelligence.

Replicating FROST on Mobile Brave: Methodology and a Negative Result.

In May 2026, researchers at Graz University of Technology published FROST, short for Fingerprinting Remotely using OPFS-based SSD Timing (due at DIMVA in July 2026). The attack lets a website work out which other sites and apps you have open by timing how a shared solid state drive responds to reads. No permissions, no clicks, no interaction. You visit a page, and the page measures the drive. Their reported numbers were strong on desktop Linux and macOS: an F1 score of 88.95 percent for website fingerprinting, 95.83 percent for application fingerprinting, and a covert channel of 661.63 bits per second.

I wanted the one thing the paper did not cover: does any of this survive on a phone. Nobody had published a mobile result. This is the full log of that attempt, including the dead ends and a bug of my own. The honest summary, up front: the machinery FROST needs is present on mobile Brave, a single drive read is just barely timeable, and the contention signal it depends on does not survive. On this device, in this browser, the channel is buried under the timer floor and the cache. That is a negative result, and the reason it comes out negative is Brave doing exactly what it is supposed to do.

The two preconditions

FROST stands on two legs, and either one missing kills it. Leg one is the primitive. The attack needs the Origin Private File System (OPFS), a storage scratchpad any website can create without asking, and it needs the fast synchronous read handle that lets code read from that file with precise timing. Without both, there is nothing to measure. Leg two is the eyesight. The attacker times reads and watches them slow down when other activity loads the drive. That only works if the browser clock is fine enough to see a single read. Browsers deliberately blur their clocks to defend against timing attacks, and Brave blurs harder than most as a deliberate anti-fingerprinting measure. So the resolution of the clock is the whole game. The question for mobile was simply whether both legs hold on Android, in the browser I actually use.

Setup

Hardware was a Samsung Galaxy A56 running Android, tested in Brave in its normal hardened state, not a factory reset. The point was to measure what a real privacy-minded Brave user is exposed to, not a stripped configuration nobody runs.

One Brave behaviour matters before the numbers. Brave randomises the values a page can read for hardwareConcurrency and deviceMemory on every session, a technique it calls farbling. So across my runs the same phone reported anywhere from 3 cores and 2 GB to 8 cores and 8 GB. That is not measurement error. It is Brave deliberately handing each session a different hardware fingerprint, and it is part of what an attacker is up against.

OPFS only works from a real secure web origin, so the test had to be served from an actual https address rather than a saved file or a sandboxed code playground. I hosted it as a static page on a free GitHub Pages origin. One consequence of that choice mattered later: GitHub Pages cannot send the headers that put a page into cross-origin isolation, and without isolation the browser clamps the timer to its coarse default. I will come back to why that matters.

The probe ran read timing inside a Web Worker using the synchronous access handle, measured the clock resolution directly, and forced reads down to real storage by making the test file far larger than the device cache. The contention test used two workers at once: one timing reads of its file, the other hammering a separate file with continuous writes and flushes to load the drive. Idle and loaded measurement blocks were interleaved inside a single run, so that any slow drift in the device (heat, memory pressure) would hit both conditions equally and only a genuine contention difference would show as a consistent gap.

I am holding the harness itself back for now. The clean number is still open, and I would rather publish working code next to a rigorous result than hand the recipe out ahead of it.

Results

Confirmed and solid: OPFS is present in mobile Brave, and it does hand out the synchronous access handle.

Leg one holds.

Drive reads are timeable above the clamped clock floor once the cache is starved. With a small file (64 MB) every read came back faster than the clock could measure, served from RAM, no signal at all. With a file large enough to defeat the cache (512 MB and up) real read latencies appeared, with a median of 100 microseconds, a p90 of 300, and a long tail past 3000. Leg two holds, with the caveats below.

The result: negative.

Under drive load, the typical read moved up by one clock bucket. Across the run the median of the loaded reads sat one step above idle (200 to 300 microseconds) and the p90 did the same (300 to 400). That is the direction contention would produce. But the size is exactly one quantum of a clamped clock, the smallest shift the timer can physically display. The mean barely moved at all, a delta of 16.2 microseconds, dragged flat by a heavy tail in the idle blocks that looks more like random spikes than signal. And it rests on a single run. The probe's own automated read of the data was blunt: no contention signal separable from noise. I agree with my tool. On this stack, the channel is buried under the timer floor and the cache. That is a real negative result, not a borderline one. What the clock did to the result The dominant limiter was timer resolution. On this setup the clock floor sat at 100 microseconds, partly from the standard browser defence against timing attacks and partly from Brave's own hardening, and because the hosting could not enable cross-origin isolation, I could not unlock the finer resolution that isolation grants. A 100 microsecond floor means anything faster reports as zero or as a single step, and the entire contention effect FROST hunts lives down near that floor. The clamp did not only add noise. It flattened the thing the attack needs to see, to the point where a real effect, if one exists here at all, cannot be told apart from drift.

Threats to validity

This is where an honest attempt earns its keep, so the limitations in full:

The clamped clock crushes any signal to the smallest measurable step, so even a perfect run could only ever show a one-step nudge. A negative result under a clamp is not proof the channel is absent, only that it sits below what this clock can see. The hosting could not enable cross-origin isolation, so the finer timer was never on the table.

Cache behaviour and run-to-run drift on a thermally and memory constrained phone add variance a desktop does not have, and Brave's per-session farbling of core count and memory adds more.

The two workers cooperate inside one page. That tests the underlying physics, whether drive contention is sensible through OPFS at all, and not the full attack, which is cross-origin, cross-tab, and cross-browser with a trained classifier on top.

I cannot fully separate drive contention from ordinary scheduler or memory contention in this design, so the load is best described as general system load biased toward disk.

A bug in my harness stalled an earlier contention run partway, on a repeated block, which I had to work around. That one is mine to fix. The result rests on a single complete run. One run is not a result on its own, and I will not treat it as more than it is.

Where this lands, and what comes next

I set out to find whether FROST replicates on mobile Brave. The honest answer is that the machinery is there and a single read is timeable, but the contention signal the attack depends on does not survive the browser clock. It comes back negative. Brave's anti-fingerprinting clamp is the main reason, and that is worth saying plainly: the thing that defeated this attack on my phone is Brave protecting its users, working as designed.

So the next pass is not about rescuing a positive out of this one. It is about taking the clamp out of the measurement to find out whether anything is hiding underneath it. I will fix the harness, host on an origin that can enable cross-origin isolation to unlock the finer timer, and run a controlled comparison of the channel with the clamp and without it. The interesting result was never going to be a flat yes or no on mobile. It is the size of the gap between clamped and unclamped, which is another way of saying how much Brave's hardening actually costs an attacker. A negative result under the clamp, set next to whatever shows up without it, is what makes that number mean something.

This post is the attempt and the negative. The next one measures what the clamp was hiding.

Sources:

• FROST: Fingerprinting Remotely using OPFS-based SSD Timing, Weissteiner et al., Graz University of Technology (DIMVA, July 2026): hannesweissteiner.com/pdfs/frost.pdf

Contact Author: X: @baximuscyber85

Email: onyxdigitalintelligence85@protonmail.com