Is APK Downloader safe?

Medium risk

Search and download free Android app APK or XAPK files from APKPure.

This extension provides access to APKPure’s online APK downloader for finding free apps and games by app name or package name. It redirects users to an app information page where they can download available APK or XAPK files, including free apps that may be region-restricted on Google Play.

APKPurev1.0.8Chrome Web Store
45Risk

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

Publishers can request a review.

Findings

SeverityMEDIUM
ClassUNWANTED
TypeUnexpected
CWECWE-200
SourceAI SANDBOX

Content script scans every page's DOM and reports it internally on load

APK Downloader's content script runs on every site, scanning the DOM for schema.org data on load and reporting the domain plus product fields to the background worker.

Kept only for ~2 dozen whitelisted app-store domains, else discarded.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You open, switch to, or navigate within any webpage in the browser.

The extension did this

The extension's content script immediately scans the page's DOM for structured product data and reports the domain and any extracted fields to the background service worker.

This happens at document_start, before the page has finished loading, on every site, not only app-store listings.

02EvidenceFIELD TABLE
What the content script extracts and sends to the background script on every page
FieldValueWhy it matters
Page domain
www.example-shop.comThe hostname of every site you visit is included in the internal message, whether or not the site is an app store.
Structured product/app fields
com.whatsappAny name, price, developer, rating, or package-ID data the page exposes via schema.org markup is pulled, on any site carrying it.
Page title
WhatsApp MessengerThe extracted title of the product/app the page describes.
03EvidenceCODE COMPARE
The code that does this

Content script scrapes DOM on load and on every SPA navigation (extract-package-info.605807e3.js)

What it actually does
const config = { run_at: "document_start" };

// Runs immediately when the content script loads on ANY page.
async function reportPageInfo() {
  chrome.runtime.sendMessage(buildPkgInfoMessage());
}

function buildPkgInfoMessage() {
  return {
    type: messageType.pkgInfo,
    data: extractProductDataFromDOM()
  };
}

function extractProductDataFromDOM() {
  // Look for schema.org itemprop="offers" elements
  const offersEls = document.querySelectorAll('[itemprop="offers"]');

  let extracted = {};
  const itempropEls = document.querySelectorAll('[itemprop]');
  const jsonLdEls = document.querySelectorAll('[type="application/ld+json"]');
  const wantedFields = ['image', 'name', 'priceCurrency', 'price', 'ratingValue', 'ratingCount', 'publisher', 'worstRating', 'bestRating'];
  const productTypes = ['MobileApplication', 'SoftwareApplication', 'Product', /* schema.org variants */];

  // Try JSON-LD structured data first (runs on EVERY page with a matching <script type="application/ld+json">)
  try {
    jsonLdEls.forEach(el => {
      const data = JSON.parse(el.innerText);
      // ...matches against productTypes and captures the object into `extracted`
    });
  } catch (e) {}

  // Fall back to itemprop microdata attributes if no JSON-LD matched
  if (itempropEls.length && !Object.keys(extracted).length) {
    itempropEls.forEach(el => {
      wantedFields.forEach(field => {
        if (el.getAttribute('itemprop') === field) {
          extracted[field] = el.content || el.src || el.innerText;
        }
      });
    });
  }

  // Per-site adjustments for ~23 known app-store domains (Google Play, App Store, APKPure, etc.)
  // ...

  return {
    url: extracted.url,
    domain: window.location.hostname,   // sent for EVERY page, whitelisted or not
    packageId: extracted.packageId,
    icon: extracted.image,
    title: extracted.name,
    priceCurrency: extracted.priceCurrency,
    price: extracted.price,
    developer: extracted.publisher,
    ratingValue: extracted.ratingValue,
    reviewCount: extracted.ratingCount,
    worstRating: extracted.worstRating,
    bestRating: extracted.bestRating
  };
}

// Fires once on script load, and again on every SPA navigation.
reportPageInfo();
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
  if (msg.type === messageType.getPkg) sendResponse(buildPkgInfoMessage());
});
window.addEventListener('hashchange', reportPageInfo);
window.addEventListener('pushState', reportPageInfo);
window.addEventListener('popstate', reportPageInfo);
04EvidenceCODE COMPARE
The code that does this

Background worker keeps data only for a hardcoded domain whitelist (background.93e42914.js)

What it actually does
// Called for every pkgInfo message received from the content script, on every page.
function handlePkgInfo(message, tabId) {
  const isWhitelistedDomain = schemaWhiteUrlList.some(host => message.data.domain === host);

  // Record whether this page's domain was on the app-store whitelist — for EVERY page.
  chrome.storage.local.set({ isWhiteUrl: isWhitelistedDomain });

  if (!isWhitelistedDomain) {
    clearBadge(tabId);
    return; // extracted data is discarded here, not persisted
  }

  setBadge(tabId, message.data.title ? '1' : '');
  chrome.storage.local.set({
    data: message.data.title ? JSON.stringify(message.data) : null,
    tabId: tabId
  });
}

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message?.type === messageType.pkgInfo) {
    handlePkgInfo(message, sender?.tab?.id);
  }
});
05EvidenceSTORAGE DUMP
What's stored on your device

Every load writes isWhiteUrl true/false. Whitelisted domains also save scraped fields; 76 of 89 tested loads discarded data.

Locationchrome.storage.local keys 'isWhiteUrl' and 'data'
Contents (JSON)
{
  "isWhiteUrl": false,
  "note_non_whitelisted": "Observed 76 times during dynamic analysis testing on ordinary, non-app-store pages — each one a page load that triggered the DOM scan and internal message, then had its extracted data discarded because the domain wasn't on the whitelist.",
  "data_when_whitelisted_example": {
    "price": "0",
    "title": "WhatsApp Messenger",
    "developer": "WhatsApp LLC",
    "packageId": "com.whatsapp",
    "ratingValue": "4.2"
  }
}
SeverityMEDIUM
ClassUNWANTED
TypeUnexpected
CWECWE-200
SourceAI SANDBOX

Tab URL Sent to pureapk.com on Every Popup Open, Search, and Download

Opening the popup, searching, or clicking download sends your tab URL and a persistent device ID to tapi.pureapk.com.

Two confirmed GET requests carried the tab URL and stored client_id, building a browsing record tied to your device.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You open the extension popup on any browser tab, or type a search, or click the Download button.

The extension did this

The extension reads the URL of your current tab and sends it to tapi.pureapk.com together with a persistent device ID unique to your installation.

The beacon fires for three distinct actions: popup open (event_code=open), search bar submission (event_code=search), and download button click (event_code=download).

02EvidenceNETWORK CAPTURE
Captured request
GEThttps://tapi.pureapk.com/report/search_report?atta_id=05200075581&random=0.8631820457615105&client_id=QwWhmueBPOqEA16zFKKBe&event_code=open&url=https%3A%2F%2Fwww.example.com%2Fa planted marker value
HTTP 403. Endpoint confirmed reachable; the client_id (QwWhmueBPOqEA16zFKKBe) matched the value in chrome.storage.local key 'apk-downloader-uid'. A planted marker value appeared verbatim in the query string.
03EvidenceFIELD TABLE
What the extension sends on each popup open, search, or download:
FieldValueWhy it matters
Current tab URL
https://www.example.com/a planted marker valueThe full address of the page you have open when you interact with the extension.
Device ID (client_id)
QwWhmueBPOqEA16zFKKBeA permanent random ID created on install, stored locally, and sent every request, letting the server track your tab URLs over time.
App partner ID (atta_id)
05200075581A hardcoded value that identifies this extension to the pureapk.com backend. The same for all users.
Action type (event_code)
openWhich user action triggered the beacon: opening the popup, running a search, or clicking download.
Noise salt (random)
0.8631820457615105A random float added to each request, likely to prevent caching, not for privacy.
04EvidenceSTORAGE DUMP
What's stored on your device

Created via nanoid on install, never rotated. Sent as client_id on every request, tying every tab URL you report to the same device.

Locationchrome.storage.local key 'apk-downloader-uid'
Contents (JSON)
{
  "apk-downloader-uid": "QwWhmueBPOqEA16zFKKBe"
}
05EvidenceCODE COMPARE
The code that does this

The reportAtta function that fires the beacon, shipped minified vs. readable.

What it actually does
reportAtta — creates or retrieves persistent UUID, then sends beacon
// Called by background onMessage handler whenever popup sends a 'report' message.
async function reportAtta(eventCode, extraInfo = {}) {
 // Read the persistent device UUID from storage (creates one on first run).
 let { 'apk-downloader-uid': clientId } = await chrome.storage.local.get('apk-downloader-uid');
 if (!clientId) {
 clientId = nanoid; // generates a URL-safe random 21-char ID
 await chrome.storage.local.set({ 'apk-downloader-uid': clientId });
 }

 // Build the query string and fire the GET beacon.
 const params = new URLSearchParams({
 atta_id: '05200075581', // hardcoded partner ID
 random: Math.random.toString, // cache-busting noise
 client_id: clientId, // persistent per-device UUID
 event_code: eventCode, // 'open' | 'search' | 'download' | 'install'
 ...extraInfo // includes { url: <current_tab_url> }
 });
 await fetch(`https://tapi.pureapk.com/report/search_report?${params}`);
}
Popup mount effect — triggers open beacon with current tab URL
// Runs once when the popup loads.
useEffect(async => {
 const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
 if (!tab) return;

 // Send 'open' event to background with the current tab's URL.
 chrome.runtime.sendMessage({
 type: 'report',
 data: {
 eventCode: 'open',
 extraInfo: { url: tab.url || '' }
 }
 });

 // ... then fetch APK info for the page
}, []);
06EvidenceTHIRD PARTY LIST
Where the data is sent:
  • tapi.pureapk.com

    Analytics API for APK Pure (pureapk.com), the extension's parent site. Receives the tab URL, persistent device ID, and event type on every popup interaction.

07EvidenceARTIFACT
Reproduce it yourself

Run this in the DevTools console on the extension's background service worker to intercept all outbound beacons to tapi.pureapk.com and log their full query parameters in readable form.

RequiresChrome with Developer mode enabledAPK Downloader extension installed
apk-downloader-beacon-watcher.js · js
// apk-downloader-beacon-watcher.js
// Patches globalThis.fetch in the APK Downloader background service worker
// to intercept and log every call to tapi.pureapk.com/report/search_report.
//
// Usage:
// 1. Open chrome://extensions, enable Developer mode.
// 2. Find "APK Downloader" and click its service worker link.
// 3. In the DevTools console that opens, paste this entire script.
// 4. Click the APK Downloader toolbar icon on any page.
// 5. Watch for [APK_BEACON] entries in the console.

(function {
 const TARGET = 'tapi.pureapk.com/report/search_report';
 const origFetch = globalThis.fetch.bind(globalThis);

 globalThis.fetch = function (input, init) {
 const url = typeof input === 'string' ? input : input?.url ?? '';
 if (url.includes(TARGET)) {
 try {
 const parsed = new URL(url);
 const params = {};
 parsed.searchParams.forEach((v, k) => { params[k] = v; });
 console.log('[APK_BEACON] Outbound beacon intercepted:');
 console.log(' URL: ', url);
 console.log(' client_id: ', params.client_id, ' ← persistent device UUID');
 console.log(' event_code: ', params.event_code, ' ← open | search | download | install');
 console.log(' url: ', params.url, ' ← current tab URL at time of action');
 console.log(' atta_id: ', params.atta_id);
 console.log(' random: ', params.random);
 console.log(' full params:', params);
 } catch (e) {
 console.error('[APK_BEACON] Parse error:', e);
 }
 }
 return origFetch(input, init);
 };

 console.log('[APK_BEACON_WATCHER] Installed. Open the APK Downloader popup to capture beacons.');
});
How to run it
  1. 1
    Open chrome://extensions, enable Developer mode.
  2. 2
    Open APK Downloader's service worker inspector.
  3. 3
    Paste this script, press Enter.
  4. 4
    Visit any page, click the toolbar icon.
  5. 5
    Look for [APK_BEACON] logs with tab URL and client_id.

Data recipients

APKPure.com
Updated 10 September 2026glngapejbnmnicniccdcemghaoaopdji