Is Font Changer safe?
Font Changer rewrites shopping links and queries deals99.com for affiliate promotion URLs.
When you visit supported shopping sites such as AliExpress, Agoda, Booking, or Banggood, its content script scans page links and changes matching URLs to affiliate links. For AliExpress pages, it sends the site's hostname and product identifiers from links to deals99.com to receive promotion URLs before replacing those links.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Extension Swaps In Its Own Affiliate ID On Shopping Links
On Agoda, Booking.com, and Banggood, the extension rewrites links to carry its own affiliate ID.
Testing found all 111 Booking.com and 120 Banggood links rewritten.
A matching AliExpress/deals99.com lookup exists in code, unobserved firing.
- Severity
- Medium unwanted
- Type
- Unexpected
- CWE
- CWE-506
- Source
- Dynamic sandbox
You open a hotel or product listing page on Agoda, Booking.com, or Banggood with the extension installed.
The extension's content script is already running on the page; it injects at document_start on every site.
The extension rewrites every outbound link on the page so it carries its own hardcoded affiliate identifier before you can click it.
A DOM MutationObserver re-runs the rewrite as the page updates, so links that load in later get the same treatment.
- Agoda hotel linkhttps://www.agoda.com/room2-chiswick-hometel/hotel/london-gb.html?checkIn=2026-08-15&los=1&room=1&adults=2&cid=1763404
The hotel link you'd click carries the extension's own Agoda affiliate ID, so any booking is credited to the extension's account.
- Booking.com hotel linkhttps://www.booking.com/hotel/gb/art-otel-london-hoxton.html?aid=2082838
Every hotel link on a Booking.com results page, 111 out of 111 in our test, was rewritten with the same affiliate parameter.
- Banggood product linkhttps://www.banggood.com/USLION-5A-USB-to-Type-C-Cable-QC-SCP-AFC-PPS-MTK-PE-Fast-Charging-Data-Transmission-Nylon-Core-Line-1M-or-2M-Long-for-Samsung-Galaxy-Note-20-for-Huawei-Mate50-for-Xiaomi-Mi12-p-1975796.html?cur_warehouse=CN&ID=457636287830&rmmds=search&p=7W24238151091201612I
Every product link on a Banggood results page, 120 out of 120 in our test, was rewritten with the same affiliate token.
- AliExpress product lookup (deals99.com){"site":"aliexpress","hostname":"www.aliexpress.com","source_ids":"1005006331891004","account":"2","tracking_id":"ea_medium_14"}
On AliExpress, code sends the hostname and product IDs to deals99.com and swaps in the returned link. Present in code, not observed firing.
Per-site affiliate-ID rewrite functions
Agoda rewrite
// Replaces (or appends) the Agoda "cid" affiliate parameter with the// extension's own hardcoded ID (window._ea.aid.AGODA === "1763404")function rewriteAgodaLink(existingCidMatch, originalUrl) { const extensionAgodaId = window._ea?.aid?.AGODA || ""; // "1763404" if (existingCidMatch) { return originalUrl.replace(existingCidMatch[0], `cid=${extensionAgodaId}`); } return `${originalUrl}${originalUrl.includes("?") ? "&" : "?"}cid=${extensionAgodaId}`;}Banggood rewrite
// Replaces (or appends) the Banggood "p" affiliate token with the// extension's own hardcoded value (window._ea.aid.BANGGOOD === "7W24238151091201612I")function rewriteBanggoodLink(existingTokenMatch, originalUrl) { const extensionBanggoodToken = window._ea?.aid?.BANGGOOD || ""; if (existingTokenMatch) { return originalUrl.replace(existingTokenMatch[0], `p=${extensionBanggoodToken}`); } return `${originalUrl}${originalUrl.includes("?") ? "&" : "?"}p=${extensionBanggoodToken}`;}Booking.com rewrite
// Replaces (or appends) the Booking.com "aid" affiliate parameter.// getBookingAffiliateId() reads a browser-specific hardcoded ID:// default "2082838", Firefox "2085046", Edge "2344472".function rewriteBookingLink(existingAidMatch, originalUrl) { const aidParam = `aid=${getBookingAffiliateId()}`; if (existingAidMatch) return originalUrl.replace(existingAidMatch[0], aidParam); if (/(\/searchresults\.(.+)\.html)|(\/index\.(.+)\.html)/.test(originalUrl)) { const [path, query] = originalUrl.split("?"); return `${path}?${aidParam}&${query}`; } return `${originalUrl}${originalUrl.endsWith(".html") ? "?" : ";"}${aidParam}`;}Link-rewrite dispatcher
// Runs once immediately, then again on every DOM mutation (via a// MutationObserver wired up by J()). Walks every <a href> on the page// not already processed and rewrites it in place.function rewriteLinksForSite(site) { if (!site) return; const extractProductOrCid = siteExtractors[site]; // one of Y/z/Q/tt if (!extractProductOrCid) return; const pendingAliExpressIds = []; (async () => { const links = document.querySelectorAll('[href]:not(.ea-processed, link)'); if (links.length === 0) return; links.forEach(anchor => { let href = anchor.getAttribute('href') || ''; if (href === '#' || href.startsWith('javascript:')) { anchor.classList.add('ea-processed'); return; } const match = extractProductOrCid(href); if (match) { if (site === 'agoda') { applyRewrite(/cid=\d+/, m => rewriteAgodaLink(m, href)); return; } if (site === 'banggood') { applyRewrite(/p=\w+/, m => rewriteBanggoodLink(m, href)); return; } if (site === 'booking') { applyRewrite(/aid=\d+/, m => rewriteBookingLink(m, href)); return; } // AliExpress: queue the product ID for a batched deals99.com lookup if (!pendingAliExpressIds.includes(match)) pendingAliExpressIds.push(match); anchor.classList.add('ea-promotion'); anchor.setAttribute('data-ea-pid', match); } else { anchor.classList.add('ea-processed'); } }); // Fetch replacement promotion URLs for every queued AliExpress product ID const promotionUrls = await fetchPromotionUrls(site, pendingAliExpressIds); document.querySelectorAll('[href].ea-promotion:not(.ea-processed, link)').forEach(anchor => { const pid = anchor.getAttribute('data-ea-pid'); if (pid) { const url = promotionUrls[pid]; if (url != null && url.startsWith('http')) anchor.setAttribute('href', url); } anchor.classList.add('ea-processed'); }); })();}Top-level navigation to the Agoda hotel page after the content script ran; cid=1763404 matches the hardcoded AGODA affiliate ID in the extension's own code (window._ea.aid.AGODA), not a site-default or third-party affiliate value.
AliExpress remote lookup, present in the code, did not fire during this test session
Batch AliExpress product IDs and request promotion URLs
// Called once per page with the site name ("aliexpress") and the list// of AliExpress product IDs found by the link scanner. Caches results// for 1 hour, batches in groups of 10, and asks the background worker// to fetch https://deals99.com/jsonp/product/kanai-urls for each batch.async function fetchAliExpressPromotionUrls(site, productIds) { const trackingId = window._ea?.aid?.AE || ""; // "ea_medium_14" (browser-specific) const cacheKey = `promotion_urls:${site}`; const now = Date.now(); let cached = cache.get(cacheKey) || {}; cached = keepUnexpired(cached, now); const uncachedIds = productIds.filter(id => !(id in cached)); if (uncachedIds.length) { const { hostname } = window.location; const expiresAt = now + 60 * 60 * 1000; // 1 hour for (const batch of chunk(uncachedIds, 10)) { const response = await backgroundApiRequest('/product/kanai-urls', { site, hostname, source_ids: batch.join(','), account: '2', tracking_id: trackingId, }); for (const [productId, promoUrl] of Object.entries(response.records)) { cached[productId] = `${promoUrl}:EA:${expiresAt}`; } } cache.set(cacheKey, cached); } return stripExpiryMarker(cached);}Background worker performs the fetch on the content script's behalf
// The content script cannot fetch cross-origin from the page context in// this build, so it sends a runtime message and the background service// worker (which has host permissions for <all_urls>) makes the request.async function handleApiMessage(request, sendResponse) { let { url } = request; const { data, method } = request; if (method === 'GET' && data && Object.keys(data).length > 0) { url = `${url}?${new URLSearchParams(data)}`; } try { const res = await fetch(url, { method, body: ['GET', 'HEAD'].includes(method) ? undefined : JSON.stringify(data), }); if (!res.ok) throw new Error(res.statusText); sendResponse({ type: 'success', content: await res.json() }); } catch (err) { sendResponse({ type: 'fail', content: err }); }}browser.runtime.onMessage.addListener((request, sender, sendResponse) => { if (request.action === 'api') handleApiMessage(request, sendResponse); return true; // keep the message channel open for the async response});- agoda.com
Normal navigation destination; hotel links are rewritten locally in the browser to carry cid=1763404, the extension's own affiliate ID.
- booking.com
Normal navigation destination; hotel links are rewritten locally to carry aid=2082838 (or a browser-specific variant), the extension's own affiliate ID.
- banggood.com
Normal navigation destination; product links are rewritten locally to carry p=7W24238151091201612I, the extension's own affiliate token.
- deals99.com
Receives the page hostname and AliExpress product IDs, returns promotion URLs replacing product links. Coded in; not observed firing during testing.
What it can do
Permissions this extension asks for, as declared in version 3.0.2. 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 site you visit
<all_urls>
Store data in your browser
storage
Where it sends data
Destinations our analysis observed Font Changer 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.
- deals99.com
Font Changer sends data to deals99.com. 2 other extensions we have analysed send data here.