Is CAI Tools safe?
CAI Tools is medium risk. CAI Tools' ChatGPT-backed greeting generator fetches your ChatGPT session endpoint, extracts the access token, and uses it to send ChatGPT a conversation request with your prompt, a generated device ID, and sentinel proof tokens.
Who publishes itİrşat - 1 other listing from the same operator, none carrying a finding
İrşat - 1 other listing from the same operator, none carrying a finding
What this publisher told the store about itself, and the other listings that told it the same thing.
Same store account
1 other listing published from this account, 5k+ users between them, none of them carrying a finding.
Shared hosts - 12 hostnames
Hostnames hardcoded in this extension that few other listings call. That can mean one operator behind both, and it can equally mean a small shared vendor, so it is context rather than a conclusion. Hosts that many listings call are left out: they are services, not connections.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
ChatGPT token used for extension prompts
CAI Tools' ChatGPT-backed greeting generator fetches your ChatGPT session endpoint, extracts the access token, and uses it to send ChatGPT a conversation request with your prompt, a generated device ID, and sentinel proof tokens.
What actually happens
You click the extension feature that asks ChatGPT to generate a greeting.
The popup builds the prompt from character settings, persona text, and special instructions.
The extension reads your ChatGPT access token and uses it to send the prompt to ChatGPT's backend API.
The code also adds sentinel proof tokens and a generated device ID to match the ChatGPT web request shape.
Captured request
The code reads accessToken from this session response; no dynamic response body was recorded for the confirmed proof.
Captured request
The code sends a locally generated chat-requirements token before building the final conversation request; no dynamic request body was recorded.
Captured request
The code submits the generated prompt to ChatGPT's conversation API with bearer authorization and sentinel headers; no dynamic request body was recorded.
Values the extension reads or sends in the ChatGPT path
- ChatGPT access tokenBearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImNoYXRncHQtd2ViIn0.eyJzdWIiOiJ1c2VyXzEyMzQ1IiwiYXVkIjoid2ViIn0.RXhhbXBsZVNpZ25hdHVyZUZvckJhY2tmaWxs
This token authenticates the request as your logged-in ChatGPT web session.
- Greeting prompt textWrite an opening greeting using the character settings and persona notes provided in the extension.
This is the content the extension asks ChatGPT to answer for you.
- Generated device ID77d7e6f4-6f7c-4b33-9c22-7342de9eec40
This value makes the request look like it came from a particular ChatGPT web device session.
- Sentinel proof tokensopenai-sentinel-proof-token: gAAAAABWyIxMMiwiVHVlIEp1bCAxNCAyMDI2IiwwLDQyLCJNb3ppbGxhLzUuMCJd
These values satisfy ChatGPT's request checks before the conversation is submitted.
- Visibility flagis_visible: false
This marks the generated turn as not visible in the ChatGPT conversation UI.
The code that does this
ChatGPT token read and conversation request construction
Popup trigger for the ChatGPT greeting feature
deobfuscated/src/popup/popup.js// Get prompt, import char settings, import persona, import special instructionslet prompt = defaultGreetingGenPrompt_GPT;let rawPersonaText = persona ? '\n\n' + Object.keys(persona) .filter((key) => persona[key]) // Leave out the empty and undefined .map((key) => `${key}: ${persona[key]}`).join('\n') : '';prompt = prompt.replace(/{{dynamic-char-settings/g, rawCharPersonalityText) .replace(/{{user-persona}}/g, rawPersonaText) .replace(/{{special-instructions}}/g, special ? `\n\n${special}` : '');this.ReportProgress("Loading... (Asking ChatGPT)");generateGreetingWithChatGPT({ prompt, model: this.model_select.value })Read the ChatGPT web access token
deobfuscated/src/utils/helper.jsexport async function generateGreetingWithChatGPT(args) { try { const gptLoginData = await getChatGPTAccessToken(); if (!gptLoginData.token) return { error: "not_logged_in", message: `You need to login to your ChatGPT account to be able to use this feature.<br/><a href='https://chatgpt.com/' target='_blank'>https://chatgpt.com/</a><br/>If you are already logged in, try logging out & in on ChatGPT.${gptLoginData.error ? `<br/>${gptLoginData.error}` : ''}` }; // Ask gpt const res = await askChatGPT(args.prompt, gptLoginData.token, args.model); return res; } catch (error) { return { error: "unexpected_error", message: error.message || error }; }}// Get session for access tokenasync function getChatGPTAccessToken() { try { const res_session = await fetch("https://chatgpt.com/api/auth/session"); if (!res_session.ok) throw new Error("ChatGPT login error.", res_session.status, res_session.statusText) const data_session = await res_session.json(); return { token: data_session.accessToken }; } catch (error) { return { error }; }}Build sentinel proof values and send the conversation request
deobfuscated/src/utils/helper.jsasync function askChatGPT(prompt, chatgptAccessToken, model, maxTries = 3, modelSelection = 1) { const randomDeviceId = crypto.randomUUID(); try { // For chat requirements const chatReqToken = await solveChallenge("chat_req_token", { chatReqSeed: "" + Math.random(), chatReqDifficulty: "0" }); if (!chatReqToken) { return { error: "requirements_failed", message: "Couldn't generate the first gpt chat requirement token." }; } const res_req = await fetch("https://chatgpt.com/backend-api/sentinel/chat-requirements", { "headers": { "accept": "*/*", "authorization": `Bearer ${chatgptAccessToken}`, "content-type": "application/json" }, "body": JSON.stringify({ p: chatReqToken }), "method": "POST" }); if (!res_req.ok) { try { const errorData = await res_req.json(); if (errorData.detail?.code === "token_expired") { return { error: "token_expired", message: "ChatGPT session has expired. Please login again.<br/><a href='https://chatgpt.com/' target='_blank'>https://chatgpt.com/</a>" } } throw ""; } catch (err) { throw new Error("Error while trying to get ChatGPT chat requirements.", res_req.status, res_req.statusText); } } const data_req = await res_req.json(); const chatReqSeed = data_req.proofofwork.seed; const chatReqDifficulty = data_req.proofofwork.difficulty; const chatReqTokenFinal = data_req.token; if (!chatReqTokenFinal) { return { error: "requirements_failed", message: "Couldn't generate the final gpt chat requirement token." }; } let chatReqArkoseToken; // required for gpt-4 but I am not using gpt-4 even when available // Generate proof token const proofToken = await solveChallenge("proof_token", { chatReqSeed, chatReqDifficulty }); if (!chatReqTokenFinal) { return { error: "requirements_failed", message: "Couldn't generate the proof token." }; } // const model = modelSelection === 1 ? await getChatGPTModel(chatgptAccessToken) : "text-davinci-002-render-sha"; const payload = { "action": "next", "arkose_token": chatReqArkoseToken, "messages": [ { "id": crypto.randomUUID(), "author": { "role": "user" }, "content": { "content_type": "text", "parts": [ prompt ] } } ], "model": model || "text-davinci-002-render-sha", "parent_message_id": crypto.randomUUID(), "is_visible": false, // false to skip extra request to make it invisible "force_nulligen": false, "force_paragen": false, "force_paragen_model_slug": "", "force_rate_limit": false, "suggestions": [], "conversation_mode": { "kind": "primary_assistant" } } const headers = { "accept": "text/event-stream", "content-type": "application/json", "oai-device-id": randomDeviceId, "oai-language": "en-us", "authorization": `Bearer ${chatgptAccessToken}`, "openai-sentinel-chat-requirements-token": chatReqTokenFinal, ...(proofToken ? { "openai-sentinel-proof-token": proofToken } : {}), ...(chatReqArkoseToken ? { "openai-sentinel-arkose-token": chatReqArkoseToken } : {}) } // Start conversation const res_convo = await fetch("https://chatgpt.com/backend-api/conversation", { "headers": headers, "body": JSON.stringify(payload), "method": "POST" }); if (!res_convo.ok) { if (modelSelection !== 3) { return await askChatGPT(prompt, chatgptAccessToken, model, maxTries, modelSelection + 1); } if (res_convo.status === 429) { // "You've reached our limit of messages per hour. Please try again later." return { error: "chatgpt_limit", message: "ChatGPT message limit for this model has been reached." }; } if (maxTries > 0) { maxTries--; return await askChatGPT(prompt, chatgptAccessToken, model, maxTries, modelSelection); } else { throw new Error("Error while asking ChatGPT. Try logging out and in on chatgpt. " + res_convo.status + ", " + res_convo.statusText); } } // Read the event stream let finalItem = await readAllChunks(res_convo); if ((!finalItem || !finalItem.gptResponse) && maxTries < 3) { maxTries--; return await askChatGPT(prompt, chatgptAccessToken, model, maxTries, modelSelection); } if (finalItem.error) { return { error: "asking_failed", message: finalItem.error }; } else if (!finalItem || !finalItem.gptResponse) { return { error: "asking_failed", message: "Unknown error. No response returned." }; } // Return the final result return finalItem; } catch (error) { return { error: "unexpected_error", message: error.message || error }; }}External ChatGPT hosts contacted by this feature
- chatgpt.com
Provides the web session endpoint, sentinel requirements endpoint, and conversation backend used by the greeting generator.
