Non-destructive browser cache detection via abortable fetch()

In the past, many timing techniques have been shown to allow the querying of the browser cache. This has long been known to leak information about the user's activities, including potentially deanonymizing the user or revealing sensitive data.

A (small) practical obstacle to conducting such attacks has been the fact that cache probing is destructive -- checking for the presence of a resource by timing its load will result in the cache being primed with the response. This reduces detection accuracy because the attacker has a single shot at measuring the timing information.

Techniques to work around this limitation have been known since @lcamtuf's cachetime which relied on calling window.stop() to abort the request and dealing with browser-specific quirks to get accurate non-destructive readings. This PoC makes a (small) improvement to these techniques by using the newer, but universally supported AbortController API.

In this PoC we do the following:
  1. Establish a baseline time for reading cached resources from memory/disk.
  2. Pick a threshold timeout that falls between the expected cached load and expected load from the network.
  3. Load cross-origin resources in no-cors mode.
  4. Call AbortController().abort() on each fetch after timeout milliseconds, when we're reasonably sure that the resource wasn't present in the cache -- this avoids polluting the cache.
This demo is prone to false negatives because it sets a conservative timeout threshold, and uses cacheable URLs that may have since been changed by site owners. An attacker could easily make this more accurate by detecting the same resource multiple times, progressively increasing the timeout threshold, taking into account resource sizes, etc.

Note: This has been currently tested for Chrome desktop, it may fail on other browsers.

Click on some of the links above and