Is Android emulator MyAndroid safe?
MyAndroid is high risk. The extension fetches a keyword list from www.myandroid.org hourly to decide what to report. The list ('apk','aab','xapk',...) is stored locally: non-matching URLs draw no requests, while three APK navigations each triggered transmission.…
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Remote Server Controls Which URLs Are Collected via Keyword Config
The extension fetches a keyword list from www.myandroid.org hourly to decide what to report.
The list ('apk','aab','xapk',...) is stored locally: non-matching URLs draw no requests, while three APK navigations each triggered transmission.
You navigate to any page while the extension is installed.
The extension checks your URL against a keyword list fetched from www.myandroid.org, then transmits the URL if it matches.
The keyword list is refreshed from the server at most once per hour, giving the server operator control over which URLs are collected without updating the extension.
Config is refreshed at most once per hour. The check fires on every navigation event; if an hour has elapsed since the last fetch, a new GET request retrieves the current keyword list.
The active keyword list from analysis. A URL containing a term (apk, aab, xapk...) triggers transmission; the server can change it anytime.
chrome.storage.local key 'filetypesData'<head/><xml>;apk;apks;aab;xapk;apkm;akp;ama;tem;exp;tri;hot;exp;</xml>
Config fetch and keyword-match logic:
// Step 1: fetch and cache the keyword list (at most once per hour)
fetch('https://www.myandroid.org/app/filetypes-list.php')
.then(res => res.text())
.then(rawConfig => {
chrome.storage.local.set({
filetypesData: rawConfig, // e.g. "<head/><xml>;apk;aab;xapk;</xml>"
lastFetchTime: Date.now()
});
});
// Step 2: on each navigation, test the URL against the cached keyword list
let config = cachedData.trim();
if (config.startsWith('<xml>') && config.endsWith('</xml>')) {
config = config.slice(5, -6); // strip XML wrapper
}
const keywords = config.split(';').map(k => k.trim()).filter(Boolean);
for (const keyword of keywords) {
if (currentUrl.includes(keyword)) {
sendUrlToServer(currentUrl + '|||xx', userId); // transmit on first match
return;
}
}- www.myandroid.org
Hosts the keyword config at /app/filetypes-list.php and receives collected URLs at /app/a-androidemula-v3.php; one operator controls both.
Visited URLs Sent to Remote Server When Keywords Match
Dynamic analysis captured the extension sending full page URLs to myandroid.org on navigations matching a keyword from a remote list, hex-encoded plus a per-user ID.
Three APK navigations each produced an outbound GET within seconds.
You navigate to a page whose URL contains a keyword from the extension's remotely-configured list.
The extension sends the full URL of that page and your persistent user ID to www.myandroid.org without any visible notification.
The request fires as a GET to a-androidemula-v3.php with the URL hex-encoded in the 'filepath' parameter.
The visited URL is hex-encoded in the 'filepath' query parameter, making it non-obvious in proxy logs without decoding.
https://www.apkmirror.com/apk/google-inc/|||xx
| Field | Value | Why it matters | |
|---|---|---|---|
Page URL you visited | https://www.apkmirror.com/apk/google-inc/ (decoded from filepath param) | The full address of the page, hex-encoded. Captures the exact resource you accessed, including any query parameters. | |
Your persistent user ID | jquavyabcc | A 10-character random string generated on first run and stored permanently. Lets the server link all your URL reports across sessions. | |
Request type flag | dx=00, hex=1 | Hardcoded value 'dx=00' and 'hex=1' sent with every request. |
The transmission function in the extension source:
// Sends the visited URL (hex-encoded) and persistent user ID to the collection server.
// Also: if the server responds with '1302' in the body, the current tab is
// redirected to a second endpoint (r-androidemula-v3.php) — a server-triggered redirect.
async function sendUrlToServer(visitedUrl, userId) {
const hexUrl = bin2hex(visitedUrl + '|||xx'); // append suffix before encoding
const collectUrl = `https://www.myandroid.org/app/a-androidemula-v3.php?dx=00&filepath=${hexUrl}&hex=1&usty=${userId}`;
const response = await fetch(collectUrl);
if (response.status === 200) {
const body = await response.text();
if (body.includes('1302')) {
// Server-triggered redirect: force current tab to second endpoint
const redirectUrl = `https://www.myandroid.org/app/r-androidemula-v3.php?dx=00&filepath=${hexUrl}&hex=1&usty=${userId}`;
chrome.tabs.update(currentTabId, { url: redirectUrl });
}
}
}- www.myandroid.org
Primary collection endpoint. Receives hex-encoded URLs and persistent user IDs via GET to /app/a-androidemula-v3.php. Also hosts the keyword config at /app/filetypes-list.php.
Persistent Tracking ID Generated and Sent with Every URL Report
On first run, the extension makes a 10-char random ID, stored permanently.
The value ('jquavyabcc' here) appeared in every outbound transmission as 'usty', across two consecutive requests, letting the server link all reports to one install.
You install the extension for the first time.
The extension generates a random 10-character identifier and stores it permanently on your device.
From that point on, every URL report the extension sends includes this identifier, allowing the collection server to link all your reports together.
The persistent tracking ID captured during analysis, present in both observed URL-reporting requests and stored across restarts.
chrome.storage.local key 'usty'jquavyabcc
ID generation and persistence on first run:
// On extension startup: load or generate the persistent user identifier.
chrome.storage.local.get('usty', function(stored) {
chrome.storage.local.set({ myroidc: '1' }); // enable collection by default
if (stored.usty) {
// Returning install: reuse the stored ID
userId = stored.usty;
const tracker = new NavigationTracker(userId);
tracker.init();
} else {
// First run: generate a new permanent 10-char random ID
userId = randStrr(10).toLowerCase();
chrome.storage.local.set({ usty: userId }, function() {
const tracker = new NavigationTracker(userId);
tracker.init();
});
}
});