Is QuestionAI Homework Powered AI Assistant safe?

High risk

QuestionAI is high risk. QuestionAI writes a persistent cookie, QUESTION_AI_PCUID, into five sites (google.com, baidu.com, facebook.com, youtube.com, instagram.com), same value each. Expires in ~100 years, not HttpOnly. Lands automatically, no visit needed.…

D3 Dimension Technologyv2.8.26Chrome Web Store
78Risk
Who publishes it

D3 DIMENSION TECHNOLOGY PTE. LTD. - no other listings under this identity, 1 shared hostname

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

Publisher
D3 Dimension Technology
Declared legal entity
D3 DIMENSION TECHNOLOGY PTE. LTD.
Registered contact
Question.AI

Shared hosts - 1 hostname

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.

zybang.com
Also called by 3 other listings, including 大学搜题酱插件

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

Publishers can request a review.

Findings

Tracking Cookie Written to Google, Facebook, YouTube, Baidu, Instagram

HighunwantedCWE-359Dynamic sandbox

QuestionAI writes a persistent cookie, QUESTION_AI_PCUID, into five sites (google.com, baidu.com, facebook.com, youtube.com, instagram.com), same value each.

What actually happens

You did this

You install QuestionAI and use it once, so it can generate a client ID for itself.

The extension did this

QuestionAI writes that ID as a cookie named QUESTION_AI_PCUID directly into the cookie jars of google.com, baidu.com, facebook.com, youtube.com, and instagram.com.

It also reads the cookie back from any of those five sites and re-writes it to all of them, keeping the same value synced across every site's cookie jar – you never have to visit any of these sites yourself.

What's stored on your device

The same tracking ID was found on all five sites named here, confirming it was planted broadly, not scoped to the extension's own domain.

Location
chrome.cookies store, cookie name QUESTION_AI_PCUID
Contents
{  "www.baidu.com": "rkxhnj0cnutyu6wkual83vkl1jce87_1788084761",  "www.google.com": "rkxhnj0cnutyu6wkual83vkl1jce87_1788084761",  "www.youtube.com": "rkxhnj0cnutyu6wkual83vkl1jce87_1788084761",  "www.facebook.com": "rkxhnj0cnutyu6wkual83vkl1jce87_1788084761",  "www.instagram.com": "rkxhnj0cnutyu6wkual83vkl1jce87_1788084761"}

The code that does this

The code that writes the persistent ID onto five third-party sites' cookie jars.

Readable version

The tracked-site list and the fan-out write function

const TRACKED_SITES = [  "https://www.questionai.com",  "https://passport.questionai.com",  "https://www.google.com",  "https://www.baidu.com",  "https://www.facebook.com",  "https://www.youtube.com",  "https://www.instagram.com",];const PCUID_COOKIE_NAME = "QUESTION_AI_PCUID";// Called whenever the persistent client ID is generated or refreshedasync function persistIdEverywhere(cookieName, value) {  await setLocalStorage(cookieName, value);  for (const siteUrl of TRACKED_SITES) {    await writeCookieOnSite(cookieName, value, siteUrl);  }}

The underlying chrome.cookies.set call

// Writes a cookie directly into the named site's cookie jar via the// privileged chrome.cookies API -- not marked HttpOnly, expires ~100 years outfunction writeCookieOnSite(name, value, url) {  return new Promise((resolve) => {    chrome.cookies.set({      url,      name,      value,      expirationDate: Date.now() / 1000 + 3153600000, // ~100 years    }, resolve);  });}

The ID-resolution flow that keeps the cookie synced across all five sites

// Resolves (or mints) the persistent client ID, then fans it out to// every tracked site's cookie jar -- including reading it back from// whichever site already has it, if anyasync function getPersistentClientId() {  let pcuid = await getLocalStorage(PCUID_COOKIE_NAME);  if (!pcuid) pcuid = await readCookieFromAnyTrackedSite(PCUID_COOKIE_NAME);  if (pcuid) {    persistIdEverywhere(PCUID_COOKIE_NAME, pcuid); // re-syncs it to all sites    return pcuid;  }  const { data } = await api.fetchPost(APIKeys.GET_PCUID, { uuid: await getOrCreateUuid(), cuid: "start" });  persistIdEverywhere(PCUID_COOKIE_NAME, data.cuid);  return data.cuid;}

Sites this cookie is planted on, whether or not you've ever used QuestionAI there

    • www.google.com

    Receives the QUESTION_AI_PCUID cookie; readable by any script running on google.com pages since the cookie is not HttpOnly.

    • www.baidu.com

    Receives the QUESTION_AI_PCUID cookie; readable by any script running on baidu.com pages since the cookie is not HttpOnly.

    • www.facebook.com

    Receives the QUESTION_AI_PCUID cookie; readable by any script running on facebook.com pages since the cookie is not HttpOnly.

    • www.youtube.com

    Receives the QUESTION_AI_PCUID cookie; readable by any script running on youtube.com pages since the cookie is not HttpOnly.

    • www.instagram.com

    Receives the QUESTION_AI_PCUID cookie; readable by any script running on instagram.com pages since the cookie is not HttpOnly.

Check if you're affected

Checks whether the QUESTION_AI_PCUID tracking cookie is present on the current site. Since the cookie is not HttpOnly, it is readable from any page's own script context via document.cookie.

Requires
  • Chrome with QuestionAI extension installed and enabled
  • A visit to one of the five listed sites
  • Developer Tools access (F12)
questionai-pcuid-cookie-check.js · js
// questionai-pcuid-cookie-check.js// Run in the DevTools console on google.com, baidu.com, facebook.com,// youtube.com, or instagram.com while QuestionAI is installed.(function () {  const match = document.cookie.split('; ').find((row) => row.startsWith('QUESTION_AI_PCUID='));  if (match) {    console.log('[QAI_PCUID] Tracking cookie found on this site:');    console.log('  ' + match);    console.log('  This cookie was written by the QuestionAI extension, not by this site.');  } else {    console.log('[QAI_PCUID] No QUESTION_AI_PCUID cookie found on this domain right now.');  }})();
How to run it
  1. 1Install QuestionAI, let it fully load.
  2. 2Open google.com, baidu.com, facebook.com, youtube.com, or instagram.com.
  3. 3Press F12, open Console.
  4. 4Paste this script, press Enter.
  5. 5If present, the cookie prints.

Full List of Installed Extensions Sent to studyquicks.com

MediumunwantedCWE-359Dynamic sandbox

Every QuestionAI sidebar load asks for the installed-extension list (chrome.management.getAll) and sends it, names, IDs, versions, states, to autotrack.studyquicks.com.

What actually happens

You did this

You open the QuestionAI sidebar on any page.

The extension did this

QuestionAI asks the browser for the full list of installed extensions, then sends it (names, IDs, versions, states) to a third-party analytics domain.

This runs on every sidebar mount, is not limited to QuestionAI's own listing, and has no visible opt-out.

Captured request

POSThttps://autotrack.studyquicks.com/log/math_h5

Captured twice in the same session, identical payload (retried delivery by the analytics client). The test environment had only this one extension installed, so the array has a single entry – on a normal browser it would contain every installed extension.

Body
name=H60_112&ets=%5B%7B%22name%22%3A%22QuestionAI+Homework+Powered+AI+Assistant%22%2C%22enabled%22%3Atrue%2C%22version%22%3A%222.8.26%22%2C%22id%22%3A%22hajphibbdloomfdkeoejchiikjggnaif%22%7D%5D&isDark=0

One object like this is sent per extension you have installed

  • Extension name
    QuestionAI Homework Powered AI Assistant

    The human-readable name of each extension installed in your browser, sent for every one of them.

  • Extension ID
    hajphibbdloomfdkeoejchiikjggnaif

    The Store ID of each installed extension, letting the analytics service profile your browser's exact extension toolset.

  • Extension version
    2.8.26

    The installed version number of each extension.

  • Enabled state
    true

    Whether each extension is currently turned on or off in your browser.

The code that does this

The code that retrieves and transmits your full extension inventory.

Readable version

Sidebar mount handler – requests and forwards the full extension list

// sidebar.js -- runs when the sidebar content script mountssendToBackground({ messageType: "getExtensionsInfo" }, (allExtensions) => {  if (Array.isArray(allExtensions) && allExtensions.length) {    const inventory = allExtensions.map((ext) => ({      name: ext?.name,      enabled: ext?.enabled,      version: ext?.version,      id: ext?.id,    }));    addZSEvent("H60_112", {      ets: JSON.stringify(inventory), // full extension inventory, unfiltered      isDark: prefersDarkMode ? 1 : 0,    });  }});

Background handler – answers with the browser's full extension/app inventory

// background.js -- service worker message handlercase "getExtensionsInfo":  chrome.management.getAll((allExtensions) => {    sendResponse(allExtensions); // every installed/enabled extension and app, not just this one  });  return true;

Where your extension inventory ends up

    • autotrack.studyquicks.com

    Analytics beacon endpoint (bundled third-party client, zpID 'OB-MATH-PCW') that receives the full list of your browser's installed extensions on every QuestionAI sidebar mount.

Check if you're affected

Hooks fetch() and XMLHttpRequest to detect and print the extension-inventory beacon QuestionAI sends to autotrack.studyquicks.com, decoding the ets field so you can see exactly which of your extensions were included.

Requires
  • Chrome with QuestionAI extension installed and enabled
  • At least one other extension installed to see the list is not QuestionAI-only
  • Developer Tools access (F12)
questionai-extlist-monitor.js · js
// questionai-extlist-monitor.js// Run in the DevTools console on any page with QuestionAI active.(function () {  function inspect(label, url, body) {    if (!url || !url.includes('log/math_h5')) return;    console.log('[QAI_EXTLIST] ' + label + ' intercepted:', url);    const params = new URLSearchParams(body || '');    const ets = params.get('ets');    if (ets) {      try {        console.log('  extensions reported:', JSON.parse(decodeURIComponent(ets)));      } catch (e) {        console.log('  raw ets value:', ets);      }    }  }  const origFetch = window.fetch;  window.fetch = function (input, init) {    const url = typeof input === 'string' ? input : input instanceof Request ? input.url : String(input);    inspect('fetch', url, init && init.body);    return origFetch.apply(this, arguments);  };  const origSend = XMLHttpRequest.prototype.send;  const origOpen = XMLHttpRequest.prototype.open;  XMLHttpRequest.prototype.open = function (method, url) {    this._qaiUrl = url;    return origOpen.apply(this, arguments);  };  XMLHttpRequest.prototype.send = function (body) {    inspect('XHR', this._qaiUrl, body);    return origSend.apply(this, arguments);  };  console.log('[QAI_EXTLIST_MONITOR] installed. Open or reopen the QuestionAI sidebar to trigger the beacon.');})();
How to run it
  1. 1Install QuestionAI with one other extension.
  2. 2Open a page, press F
  3. 31
  4. 4
  5. 5Console tab, paste this script, press Enter.
  6. 6Open (or reopen) the sidebar.
  7. 7Watch for a [QAI_EXTLIST] entry showing your list sent.

Every Page URL Sent to QuestionAI Servers on Navigation

MediumunwantedCWE-359Dynamic sandbox

Each new page navigated to, QuestionAI sends its full URL to www.questionai.com's classifyWebsite endpoint. 5 requests in 120 seconds, including facebook.com and google.com.

What actually happens

You did this

You navigate to any web page, any site, anywhere.

The extension did this

QuestionAI transmits the full URL of that page to www.questionai.com, along with a persistent identifier tied to your account.

This happens automatically on every page load, not only on homework or educational sites, and requires no action from you.

Captured request

GEThttps://www.questionai.com/questionai/common/classifyWebsite?url=https%3A%2F%2Fwww.facebook.com%2F&cuid=lat3hl4nsq73ryv9m9tkyl16fq0437_1776251284

HTTP 200, returns JSON with isClassified, category, and alertSwitches fields that control whether the extension injects its button UI

What QuestionAI sends on every page you visit

  • The URL you are visiting
    https://www.facebook.com/

    The exact page address you are on, sent as a query parameter on every navigation.

  • Your persistent user ID (cuid)
    lat3hl4nsq73ryv9m9tkyl16fq0437_1776251284

    A unique identifier tied to your QuestionAI account that is included on every request, linking all your browsing activity across sites.

  • App identifier
    aihomework

    A hardcoded string identifying this client as the QuestionAI homework extension. The same value for all users.

  • Client type
    2

    A numeric code identifying the type of client making the request.

The code that does this

The code in the extension's sidebar that triggers this on every page load.

Readable version

onMounted hook — runs when the sidebar content script mounts on any page

// Runs on every page load when sidebar is active (not in side-panel mode)onMounted(() => {  if (!isSidePanelMode) {    classifyCurrentPage(); // calls classifyWebsite with window.location.href  }});

classifyWebsite API call — sends the current page URL to QuestionAI servers

// Issues a GET request to https://www.questionai.com/questionai/common/classifyWebsite// with {url: currentPageUrl} as a query parameterasync function fetchClassification(url) {  try {    return await apiClient.get(APIKeys.CLASSIFY_WEBSITE, { url: url });  } catch (e) {    console.log('Failed to get website classification', e);    return null;  }}

classifyCurrentPage — reads window.location.href and dispatches the request

// Reads the current page URL and sends it to questionai.comasync function classifyCurrentPage() {  const currentUrl = window.location.href; // the page you are visiting  const [classificationResult, isClosePage] = await Promise.all([    fetchClassification(currentUrl),   // → GET classifyWebsite?url=<currentUrl>&cuid=...    isClosedPage(currentUrl)  ]);  if (!classificationResult?.data) return; // still sent the URL even if result is empty  const { isClassified, category, alertSwitches } = classificationResult.data;  if (!isClassified || category !== SiteCategory.SolutionWebsite) return;  // Only shows the inject button if classified as a homework/solution site  // but the URL was already transmitted regardless}

Where your browsing data ends up

    • www.questionai.com

    QuestionAI's primary server; receives the URL of every page visited. classifyWebsite returns data used to decide whether to show the AI homework helper button.

Reproduce it yourself

Paste this into the Chrome DevTools console on any page with QuestionAI active. It intercepts XMLHttpRequest and fetch calls matching 'classifyWebsite' and logs the transmitted URL and cuid to the console, confirming what page data is being sent.

Requires
  • Chrome with QuestionAI extension installed and enabled
  • Developer Tools access (F12)
questionai-classify-monitor.js · js
// questionai-classify-monitor.js// Intercepts outbound classifyWebsite requests from QuestionAI and logs them.// Run in Chrome DevTools console on any page with the extension active.(function() {  // Hook fetch()  const origFetch = window.fetch;  window.fetch = function(input, init) {    const url = (typeof input === 'string') ? input : (input instanceof Request ? input.url : String(input));    if (url.includes('classifyWebsite')) {      const parsed = new URL(url);      console.log('[QAI_CLASSIFY] fetch intercepted');      console.log('  page URL transmitted:', decodeURIComponent(parsed.searchParams.get('url') || '(none)'));      console.log('  cuid:', parsed.searchParams.get('cuid') || '(none)');      console.log('  full request URL:', url);    }    return origFetch.apply(this, arguments);  };  // Hook XMLHttpRequest.open()  const origOpen = XMLHttpRequest.prototype.open;  XMLHttpRequest.prototype.open = function(method, url) {    if (url && url.includes('classifyWebsite')) {      const parsed = new URL(url, window.location.href);      console.log('[QAI_CLASSIFY] XHR intercepted');      console.log('  page URL transmitted:', decodeURIComponent(parsed.searchParams.get('url') || '(none)'));      console.log('  cuid:', parsed.searchParams.get('cuid') || '(none)');      console.log('  full request URL:', url);    }    return origOpen.apply(this, arguments);  };  console.log('[QAI_CLASSIFY_MONITOR] installed. Navigate to any page to see captured classifyWebsite requests.');})();
How to run it
  1. 1Install and enable QuestionAI.
  2. 2Open any page, press F
  3. 31
  4. 4
  5. 5Switch to Console.
  6. 6Paste this script, press Enter.
  7. 7Navigate to any page.
  8. 8Watch for [QAI_CLASSIFY] entries showing the URL and cuid sent.

What it can do

Permissions this extension asks for, as declared in version 2.8.26. 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 every secure site you visit

    https://*/*

  • Read and change your data on every site you visit

    <all_urls>

  • Keep running in the background while your browser is open

    background

  • Act on the current tab, but only after you click the extension

    activeTab

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

    cookies

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

    tabs

  • Add items to the right-click menu

    contextMenus

  • Store data in your browser

    storage

  • Run its own code inside the pages you visit

    scripting

  • See, disable and uninstall your other extensions, including your security ones

    management

  • Show a panel beside the page

    sidePanel

Updated 30 September 2026hajphibbdloomfdkeoejchiikjggnaif