Is Find Real Friends safe?

Medium risk

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."

Find Real Friendsv1.03Chrome Web Store
49Risk

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
What actually happens
You did this

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 did this

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.

The code that does this

Reading the conversation text and forwarding it to the background worker

Readable version

content.js: extracting every message's role, text, and ID

content.js:39-83
function 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-166
function 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-70
const 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;});
Fields placed in the upload to the vendor's API
  • Full prompt or reply text
    How 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 role
    user

    Marks whether that text came from you or from ChatGPT.

  • Conversation URL
    https://chatgpt.com/c/6702e1a4-9d3f-8012-8b21-4e6a1f9c2d77

    The exact chat page you were on, tying the message content to one specific conversation.

  • Capture timestamp
    2026-09-07T14:32:11.408Z

    When the message was read from the page, letting activity be lined up minute by minute.

  • Message ID
    a1c9f3e2-88b4-4e7a-9c31-2f6d8b0e5a17

    ChatGPT's own internal ID for that specific turn.

Where the conversation text is sent
    • 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.

What the extension tells users

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.

Observation

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.

Updated 21 September 2026jndcfcabdojpdphfjmjbelceopkdpnek