Is Alichrome - Free Invoice generator safe?

Medium risk

AliChrome is medium risk. Clicking Download PDF Invoice on an AliExpress order page makes the content script collect the shipping flag and currency, prepend them to an alert, and have the background worker send it to api.alichrome.io over HTTP, exposing the IP.

AliChromev3.6Chrome Web Store
45Risk
Who publishes it

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

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.

api.alichrome.io
Also called by 2 other listings: AliExpress Image Search, AliExpress Dropshipping Center

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

Publishers can request a review.

Findings

Invoice country and currency sent over HTTP

Clicking Download PDF Invoice on an AliExpress order page makes the content script collect the shipping flag and currency, prepend them to an alert, and have the background worker send it to api.alichrome.io over HTTP, exposing the IP.

Severity
Medium unwanted
Type
Unexpected
CWE
CWE-359
Source
Dynamic sandbox
What actually happens
You did this

You click the Download PDF Invoice button on an AliExpress order detail page.

The extension adds this button next to the existing order-status controls.

The extension did this

The extension prefixes invoice-generation messages with your shipping country flag and currency, then sends them to api.alichrome.io over HTTP.

The background worker uses a GET request to the /alert/ path on that host.

Fields placed in the alert request
  • Shipping destination flag
    FR

    This reveals the destination country shown on the order page when you generate the invoice.

  • Selected currency
    EUR

    This reveals the currency shown in the AliExpress order interface.

  • Network address context
    198.51.100.23 (illustrative)

    The remote host receiving the HTTP request can see the network address used for the request, which can add location context.

Captured request
GEThttp://api.alichrome.io/alert/${e.content}

The source issues the request without awaiting or reading a response.

The code that does this

The invoice button and alert fetch path

Readable version

Invoice button click handler in deobfuscated content.js

js/content.js
function addButtons(e = 0) {  const t = "_aig-print-button";  if (document.querySelector(`#${t}`)) return;  const n = [".order-status > button:last-of-type", ".order-status button:last-of-type", ".order-status button.comet-btn:last-of-type", ".order-status .comet-btn:last-of-type", ".order-status-box ~ button:last-of-type"];  let r = null;  for (const e of n)    if (r = document.querySelector(e), r) {      console.log(`[AliExpress Invoice] Found button with selector: ${e}`);      break    } if (!r) {    const e = document.querySelectorAll(".order-status button.comet-btn"),      t = ["Receipt", "Reçu", "Beleg", "Quittung", "Recibo", "Ricevuta"];    for (const n of e) {      const e = n.textContent.trim().toLowerCase();      if (t.some((t => e.includes(t.toLowerCase())))) {        r = n, console.log(`[AliExpress Invoice] Found "Receipt" button by text content: ${n.textContent.trim()}`);        break      }    }!r && e.length > 0 && (r = e[e.length - 1], console.log("[AliExpress Invoice] Using last available button as fallback"))  }  if (!r) return e < 50 ? void setTimeout((() => {    addButtons(e + 1)  }), 100) : (console.error("[AliExpress Invoice] Could not find target button after", 50, "attempts"), void console.error("[AliExpress Invoice] Available buttons:", document.querySelectorAll(".order-status button")));  try {    let e = r.cloneNode(!0);    e.setAttribute("id", t), e.innerHTML = "Download PDF Invoice", e.addEventListener("click", storePdf), e.style.background = "#ff4747", e.style.color = "#ffffff", e.style.borderColor = "#ff4747", r.insertAdjacentElement("afterend", e), console.log("[AliExpress Invoice] Button added successfully")  } catch (e) {    console.error("[AliExpress Invoice] Error adding button:", e)  }}

Alert message construction in deobfuscated content.js

js/content.js
function recordMessage(e, t) {  if (2 === t) console.error(e);  else if (1 === t) console.warn(e);  else if (0 === t) return void console.log(e);  let n = document.querySelector(`#${messageContainerId}`);  if (!n) {    let e = document.querySelector(".order-status-box");    if (e) try {      n = document.createElement("div"), n.setAttribute("id", messageContainerId), n.style.border = "1px solid #e62e04", n.style.padding = "1ex", n.style.marginTop = "1ex", n.style.display = "block", n.innerHTML = "<b>Invoice generation log</b>", e.appendChild(n), console.log("[AliExpress Invoice] Message container created on demand")    } catch (e) {      console.error("[AliExpress Invoice] Error creating message container:", e)    }  }  n && (n.innerHTML += `<br/>${e}`, n.style.display = "block", chrome.runtime.sendMessage({    type: "alert",    content: `%5B${getShipToFlag()}%7C${getCurrency()}%5D ${e}`  }, (e => {    console.log("alert:: " + e)  })))}function getShipToFlag() {  try {    let e = document.querySelector('[class*="ship-to--info"] span:nth-of-type(1)');    if (e) {      return e.textContent.trim().split("/")[1] || "Unknown"    }    return console.error('Element with class containing "ship-to--info" and :nth-of-type(1) not found'), "Unknown"  } catch (e) {    return console.error("Error in getShipToFlag:", e), "ERROR"  }}function getCurrency() {  try {    let e = document.querySelector('[class*="ship-to"] :nth-of-type(2)');    if (e) {      return e.textContent.trim() || "Unknown"    }    return console.error('Element with class containing "ship-to" and :nth-of-type(2) not found'), "Unknown"  } catch (e) {    return console.error("Error in getCurrency:", e), "ERROR"  }}

HTTP fetch in deobfuscated background.js

js/background.js
chrome.runtime.onInstalled.addListener(onExtensionUpdated), chrome.runtime.onConnect.addListener(onConnect), chrome.runtime.onMessage.addListener((function(e, t, n) {  return "alert" === e.type && fetch(`http://api.alichrome.io/alert/${e.content}`), !0}));
Remote host contacted by the alert path
    • api.alichrome.io

    Receives the /alert/ GET request containing the invoice-generation alert content, including the country and currency prefix.

What it can do

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

  • Store data in your browser

    storage

Updated 30 September 2026ldacgepjfajfdaodegphiolcelhlnkfm