Is Find Real Friends safe?
Find Real Friends reads the full text of your ChatGPT conversations and sends them to its own server.
The extension watches chatgpt.com and captures every message in a conversation, both what you type and what ChatGPT replies, then sends the verbatim text to api.findrealfriends.com whenever the chat updates. It also reports each chatgpt.com page you visit to the same server. This runs despite the extension's own popup stating it "cannot identify who you are and link it to your conversations."
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Find Real Friends sends your full ChatGPT prompts and replies to its own server
Code analysis shows the extension reads the full text of every ChatGPT prompt and reply and uploads it unmodified to its own backend, contradicting its in-app claim that it cannot link conversations to you.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-359
- Source
- Static analysis
You send a prompt on chatgpt.com and wait for the assistant's reply to finish.
This runs on every turn of every conversation, not once per session.
The extension reads the full text of your prompt and ChatGPT's reply from the page and queues it for upload.
A page observer watches for new conversation turns and re-reads the visible text each time one appears.
Reading the conversation text and forwarding it to the background worker
content.js: extracting every message's role, text, and ID
content.js:39-83function extractChatContent() { const now = Date.now(); if (lastMessageTimestamp && (now - lastMessageTimestamp) < MESSAGE_UPDATE_THRESHOLD) { return []; } const messages = document.querySelectorAll('div[data-message-author-role]'); const chatContent = []; let hasValidContent = false; const timestamp = new Date().toISOString(); if (messages.length > 0) { messages.forEach((message) => { try { const role = message.getAttribute('data-message-author-role'); const messageId = message.getAttribute('data-message-id'); let textContent = ''; const markdownDiv = message.querySelector('.markdown.prose'); const whitespacePre = message.querySelector('.whitespace-pre-wrap'); if (markdownDiv) { textContent = markdownDiv.textContent.trim(); } else if (whitespacePre) { textContent = whitespacePre.textContent.trim(); } if (textContent && textContent.length > EMPTY_MESSAGE_THRESHOLD) { hasValidContent = true; chatContent.push({ type: role, // 'user' or 'assistant' message: textContent, messageId, timestamp }); } } catch (error) { console.error('Error processing message (new UI):', error); } }); } return chatContent;}content.js: debouncing 2s then handing the captured turns to the background worker
content.js:145-166function sendChatContent(chatContent) { if (!isTracking || chatContent.length === 0) return; clearTimeout(debounceTimer); debounceTimer = setTimeout(() => { try { if (chrome.runtime?.id === undefined) { console.error('Extension context invalidated'); return; } const data = { timestamp: new Date().toISOString(), chats: chatContent, url: window.location.href, source: 'chatgpt' }; chrome.runtime.sendMessage({ type: 'STORE_CHAT', data }); } catch (error) { console.error('Extension error:', error); } }, DEBOUNCE_DELAY);}background.js: posting the queued turn to the vendor's own API, no redaction
background.js:60-70const response = await fetch(`${API_BASE}/api/chat`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(message)}).catch(error => { console.error('Fetch error:', error); throw error;});- Full prompt or reply textHow do I get a refund from my landlord for a security deposit dispute in California?
The complete message content, not a summary, hash, or excerpt.
- Message roleuser
Marks whether that text came from you or from ChatGPT.
- Conversation URLhttps://chatgpt.com/c/6702e1a4-9d3f-8012-8b21-4e6a1f9c2d77
The exact chat page you were on, tying the message content to one specific conversation.
- Capture timestamp2026-09-07T14:32:11.408Z
When the message was read from the page, letting activity be lined up minute by minute.
- Message IDa1c9f3e2-88b4-4e7a-9c31-2f6d8b0e5a17
ChatGPT's own internal ID for that specific turn.
- api.findrealfriends.com
The extension's own backend. Receives the full text of every prompt and reply, the conversation URL, and a timestamp, on every ChatGPT turn while tracking is on.
The extension's own popup states: 'We cannot identify who you are and link it to your conversations.' The code path that uploads full conversation text applies no redaction, hashing, or truncation before sending it.
Static analysis finding. This behaviour was identified by reading the shipped extension code and has not yet been reproduced in a live run. The trigger conditions and the exact data sent are read from the code, not from an observed capture.
Where it sends data
Destinations our analysis observed Find Real Friends contacting. Sending data somewhere is not a finding on its own - an extension that syncs your settings has to talk to its own server - but it is where your data can go, and who else it goes to.
- api.findrealfriends.com
Find Real Friends sends data to api.findrealfriends.com. No other extension we have analyzed sends data here.