SecurityWeb

Cloudflare's trust is the vulnerability

Updated

Two unrelated abuse cases - pirated video hidden as .woff2 fonts, and phishing pages hosted on r2.dev - share the same root cause: attackers exploiting inherited trust rather than breaking anything.

I’ve been looking at two abuse patterns that seem unrelated at first: pirated movies disguised as font files and phishing pages hosted on Cloudflare R2’s default subdomain. After digging into both, I found the same weakness underneath: Cloudflare’s infrastructure grants trust based on where content lives and what it is called, not what it actually is.

Case 1: video pretending to be fonts

In the first case, I found piracy operators renaming MPEG-TS video segments with a .woff2 extension and serving them through Cloudflare. The technique works because two systems disagree about what matters:

  • Cloudflare’s cache decides what to cache by file extension, not by the actual MIME type returned. .woff2 is on the default cacheable list because fonts are assumed static and harmless.
  • HLS.js, the video player doing the fetching, doesn’t care about extensions at all - it scans the response for MPEG-TS sync bytes and program tables and plays whatever it finds.

The origin server even returns text/plain for these “.font” files, and Cloudflare caches it anyway, because the decision was already made at the extension. Nobody validated that the bytes behind movie-part-04.woff2 start with 77 4F 46 32 (the real WOFF2 magic number) instead of 0x47 (an MPEG-TS sync byte). The extension was treated as ground truth.

There is an important distinction here: disguising the extension is not what makes the content cacheable. .mp4 is already cacheable by Cloudflare’s default behavior, and Cache Rules can make any extension cacheable. Getting into the cache was never the difficult part. The more convincing explanation is that the .woff2 disguise targets Cloudflare’s automated abuse detection and account-freeze systems. Cache eligibility is a side effect; evasion is the goal.

Case 2: phishing pages that inherit a good reputation

I came across the second case while investigating a compromised client. The malicious flow eventually led to a phishing page hosted on an r2.dev subdomain. That detail looked worth following, so I searched urlscan.io for page.domain:"r2.dev" and excluded titles already identified as phishing, dead, or access-denied. What remained was a steady stream of live, unflagged pages: credential-harvesting clones of Microsoft 365 and banking logins, fake CAPTCHA and “verify you’re human” pages leading to malware, and crypto wallet drainers. All of them were hosted on Cloudflare’s default public subdomain for R2 buckets. It has become a convenient free host for this content for reasons that mirror the .woff2 case:

  • Any bucket gets a *.r2.dev subdomain with a valid, trusted TLS certificate for free, instantly, with no domain registration or identity check. Compare that to registering micros0ft-login.com, which gets flagged by domain-age heuristics almost immediately.
  • The subdomain sits under Cloudflare’s own reputation - filtering and allowlisting logic that treats “it’s on Cloudflare” as a weak positive signal doesn’t distinguish a legitimate app’s static assets from a credential-harvesting HTML page dropped in an anonymous bucket an hour ago.
  • Takedown is slow and decentralized: there’s no single registrar to notify, and a burned bucket costs nothing to replace with a fresh one and a fresh URL.

Same shape as before: the platform’s trust boundary (a Cloudflare-issued cert and subdomain) doesn’t line up with the actual boundary that matters, who controls the content behind it.

The common thread

Both cases are enforcement economics, not technical vulnerabilities in the strict sense. Nothing was hacked. Cloudflare’s caching, abuse detection, and object storage all did roughly what they were built to do - cache by extension, watch for abuse patterns at scale, provision buckets instantly, issue TLS certs automatically. What both operators are actually buying with a disguised extension or a disposable r2.dev bucket is the same thing: a lower chance of being noticed by whatever automated system is watching for their pattern, for as long as possible. The abuse lives in the gap between “this platform is generally trustworthy” and “this specific piece of content on the platform is trustworthy” - and, per the corrected read of case 1, in the gap between “this looks like normal traffic” and “this looks like traffic at abuse scale.”

My conclusion from both investigations is straightforward: stop trusting the label, and don’t let automated detection be fooled by cosmetic changes that don’t alter the traffic pattern underneath.

  • For abuse detection: fingerprint by behavior (request cadence, payload shape, magic bytes) rather than by extension or reported MIME type - an extension swap shouldn’t be enough to dodge the same detector that would catch the traffic as .ts or .mp4.
  • For subdomain/reputation-based allowlisting: don’t grant *.r2.dev, *.workers.dev, *.pages.dev, etc. the same trust as a first-party domain in any filtering logic. Anyone can get one.
  • For hunting, not just blocking: search by infrastructure signature (page.domain:"r2.dev") and explicitly exclude what’s already been triaged, so what’s left is the unknown - that pattern generalizes to any shared-subdomain host, not just R2.

If you run a CDN, a WAF, or a link-scanning tool, my findings point to the same lesson: extensions, subdomains, and certificates are metadata an attacker gets to choose. Treat them as hints, not verdicts.

Share