Research · Security
How Piracy Sites Disguise Video as Fonts to Abuse Cloudflare Caching
A measured investigation into MPEG-TS segments served under .woff2 URLs, cached at Cloudflare, and reproduced across two delivery paths.
Commercial movie piracy runs on other people’s CDNs, and I’ve spent a long time working out whose. Last year one of those sites started serving its video as font files, and in July I found a second, unrelated operation doing the same thing. Its player was pulling .woff2 files, one every ten seconds, sized between 111 KB and 888 KB.
WOFF2 is a web font format. The 2025 Web Almanac puts the median font response at 23 KB and the 90th percentile at 79 KB. Every file in that sequence beat the 90th percentile. The largest beat it by 11x.
I pulled one down and ran file on it:
MPEG transport stream data
H.264 video, AAC audio. Byte zero was 0x47, the MPEG-TS sync byte, and the 188-byte packets ran clean to the end of the file. No wrapper, no header to strip. Someone had run mv segment.ts segment.woff2 and shipped it.
Why the rename is enough
Two systems handle that file, and they disagree about what decides its type.
Cloudflare goes by the filename. Its cache documentation, updated 6 May 2026, is direct about it: caching decisions use the file extension, not the returned MIME type. The default eligibility list covers fonts (WOFF, WOFF2, TTF, EOT, OTF) and media (MP4, MKV, WEBM, MP3, FLAC). It does not cover .ts or .m3u8, which is what HLS actually ships.
HLS.js goes by the bytes. In version 1.5.18, TSDemuxer.probe() calls syncOffset(), which scans the first 940 bytes for 0x47 markers at 188-byte spacing and checks for a program association table. The URL suffix never enters the decision. A raw TS segment starting at byte zero returns offset 0 and plays.
So the rename costs one command and satisfies both. The CDN sees a font extension on its cache list. The player sees valid transport stream at byte zero.
The obvious question is why not .mp4, which is also on the default list. My read is that .mp4 announces itself. Any pipeline scanning request metadata can flag it without touching the payload. A .woff2 URL announces nothing, and confirming what is inside it means fetching enough of the object to check its signature and packet structure. Cloudflare frames its video restriction as a bandwidth problem, and a second of video costs roughly what a page load costs. The extension swap does not make the violation undetectable. It makes it more expensive to confirm and act on, which is a different and more useful property if you are running the operation.
What twelve segments showed
July 2026, minochinos[.]com, twelve .woff2 segments from its Cloudflare-fronted fallback CDN.
Response headers on the first one:
HTTP/1.1 200 OK
Content-Type: text/plain;charset=UTF-8
cf-cache-status: HIT
cf-ray: ...-SIN
server: cloudflare
The origin does not even bother matching MIME type to extension. It sends text/plain for a file named .woff2 containing video, and the object still caches.
First 32 bytes:
00000000: 47 40 00 11 00 00 B0 0D 00 01 C1 00 00 00 01 EF
00000010: FF 36 90 E2 3D FF FF FF FF FF FF FF FF FF FF FF
A WOFF2 file starts 77 4F 46 32. This one starts 47.
| Segment | Size | TS packets |
|---|---|---|
| 1 | 114,680 | 610 |
| 2 | 111,672 | 594 |
| 3 | 120,696 | 642 |
| 4 | 114,680 | 610 |
| 5 | 156,792 | 834 |
| 6 | 310,200 | 1,650 |
| 7 | 782,456 | 4,162 |
| 8 | 860,664 | 4,578 |
| 9 | 686,200 | 3,650 |
| 10 | 698,232 | 3,714 |
| 11 | 695,224 | 3,698 |
| 12 | 887,736 | 4,722 |
Every size divides evenly by 188 with no remainder, so there is no padding, trailer or shell anywhere in these files. All twelve returned cf-cache-status: HIT. The playlist advertises ten-second segments and ffprobe measured 10.06 to 10.08 seconds across the set, so the eightfold size spread is bitrate and scene complexity rather than length.
One thing I did not do: a control test fetching the same object under a different extension. Cache rules, Cache-Control headers and other zone configuration can all contribute to whether a specific response is stored, and I cannot isolate the extension as the cause from these twelve requests alone. What I can say is that the objects were served from edge cache, and that the extension is the only variable here that maps onto Cloudflare’s documented default list.
The same film, two CDNs
The site’s primary delivery path is stranger. It serves the same video through the CDN of a billion-dollar consumer tech company, as PNG polyglots: a 70-byte valid PNG shell with raw TS appended, uploaded through an advertiser-facing image endpoint and served on year-long signed URLs. When those fail, the player falls back to the Cloudflare path. I am not naming the platform here, since that vector is unpatched and the operator has no obvious substitute for it.
| Pair | Polyglot | Cloudflare WOFF2 | TS payload | Packets |
|---|---|---|---|---|
| 1 | 114,750 | 114,680 | 114,680 | 610 |
| 2 | 111,742 | 111,672 | 111,672 | 594 |
| 3 | 120,766 | 120,696 | 120,696 | 642 |
| 4 | 156,862 | 156,792 | 156,792 | 834 |
The polyglot files are exactly 70 bytes larger. Strip the PNG shell and the SHA256 hashes match the Cloudflare segments byte for byte (pairs 1 to 3 against segments 1 to 3, pair 4 against segment 5; segments 1 and 4 share a payload). Same film, two abuse techniques running in parallel.
Of the two, WOFF2 is the cheap tier. The polyglot needs a construction step and a player that will scan past the shell. The rename needs an origin, a disposable Cloudflare-fronted domain, and mv. When the domain gets flagged, register another.
Scale
This is not one hobbyist. The StreamHG cluster, visible across domains including kravaxxa[.]com and haxloppd[.]com, used .woff2 on disposable Cloudflare domains through 2025 and drew an estimated 6.4 million monthly visits (SEMrush, September 2025, the most recent figure I could get). Minochinos is a separate operation and its traffic is not in that number.
StreamHG also put .woff2 filenames on Cloudflare R2 presigned URLs, shaped like [bucket].r2.cloudflarestorage.com/.../file.woff2?X-Amz-Signature=.... I could not confirm edge caching on those, and Cloudflare’s R2 docs say presigned URLs live on the S3 API domain and cannot be used with custom domains. Its terms update also permits serving video from R2 through the CDN, since the video restriction targets content hosted outside Cloudflare. So the R2 case is copyright infringement and disposable infrastructure, but it is not the same cache bypass. The persistence of the naming convention into a context where it buys nothing reads like a shared upload tool rather than a deliberate technique, which makes it a clustering lead and nothing stronger.
Why it keeps working
The gap here is enforcement economics, not a bug. Caching by extension is intentional, documented and good for performance. And the signals that would catch this are cheap:
A .woff2 file that does not start 77 4F 46 32 is wrong, and checking that costs four bytes at cache fill. None of my twelve segments had a valid header.
A page requests a small, reusable set of fonts. HLS requests a long ordered sequence of distinct objects at fixed intervals for two hours. That pattern is visible in request metadata alone, with zero payload bytes read.
Neither signal is decisive on its own. CJK font families legitimately split into hundreds of Unicode-range subsets and can run far past web-wide size percentiles, so a high object count or a large font is not proof of anything. Sequence, interval, size and a missing magic number together are a different story.
Which leaves the honest version: Cloudflare can detect this. The reason it persists is that a burnable domain costs a few dollars and the abuse pipeline needed to act on detection costs considerably more. Pirates do not need a bypass that works forever. They need to be cheaper to tolerate than to remove, and right now they are.
The general lesson outruns piracy. Any system that decides how to handle a file from its extension, while the eventual consumer decides from the bytes, has this gap. Extension equals content holds right up until the attacker picks the filename.
Prior art
Chocolatkey documented the general technique in February 2024 in “How pirate video hosts circumvent Cloudflare’s TOS”, covering randomized extensions (.txt, .css, .html, .gif, .png) with cf-cache-status: HIT confirmed. That is the earliest public write-up I found. .woff2 does not appear in it, and I have not found an earlier report describing the WOFF2 variant, the R2 presigned-URL naming, or the dual-CDN fallback arrangement.
File format, packet alignment, duration, hash matching and CDN response findings are reproduced from downloaded evidence. Cache behaviour and player probing are from Cloudflare’s documentation and hls.js 1.5.18 source. Traffic estimates are third-party (SEMrush, September 2025). No copyrighted material is hosted or distributed by the author. Evidence files are retained privately and available to CDN providers and law enforcement on request. Live domains are defanged.