Is View Earth & Satellite Maps safe?
View Earth & Satellite Maps sends the URL and title of every page you visit to its own server, tagged with a persistent install ID.
On each completed page load (and whenever the page title changes), the extension's background script sends the current tab's URL, title, and page description to viewearthsatellite.com, keyed to a userId assigned at install. A content script running on every site also answers unauthenticated postMessage requests with that same install ID, so any page can read a visitor's stable identifier. The server's response can also direct the extension to silently open a new tab to a URL of its choosing after the user clicks a link, at most once per minute.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
View Earth POSTs every page's URL and title under disguised field names
Code analysis shows the background sends the active tab's full URL, title, and meta description to the vendor's server on every navigation, keyed to a persistent ID, with the URL and title nested under unrelated field names.
You finish loading a page, or the page's title changes, for example when a video title loads in.
This applies on essentially any http or https site, as long as the extension and the server-side flag both allow it.
The background sends your persistent install ID plus the page's URL, title, and description to the vendor's own server.
The URL and title are nested under invented field names (atlas.route.surface.address, terra.lens.signal.caption) instead of url/title.
| Field | Value | Why it matters | |
|---|---|---|---|
Install ID | c9f2b6a1-7d4e-4c3a-91f0-2b8e5a6d10cf (illustrative) | The persistent ID assigned at setup, sent with every beacon so your visits can be strung into one history. | |
Page URL | https://news.example.com/politics/2026/local-election-results (illustrative) | The full address of the page you're on, sent under the invented field name atlas.route.surface.address. | |
Page title | Local election results roll in as counting continues (illustrative) | The page's title, sent under the invented field name terra.lens.signal.caption. | |
Meta description | Live coverage and analysis of today's local election results. (illustrative) | Up to 5000 characters of the page's own meta description tag, sent as keywords. |
The navigation beacon: shipped vs. formatted
async function sendNavigationBeacon(tab, contentContext, opts = {}) {
try {
if (!tab || !tab.id) return;
if (!(await beaconEnabled())) return; // storage flag earth.flow.enabled
const userId = await getOrCreateInstallId();
if (!(await remoteFlagAllows(userId))) return; // 24h-cached earth-widget-check.php flag
let ctx = contentContext && typeof contentContext === "object" ? contentContext : {};
if (opts.preferContentContext || (!contentContext && tab.url && isYouTubeWatchUrl(tab.url))) {
const sampled = await sampleTabMeta(tab.id); // asks the content script for <meta> tags
if (sampled) ctx = sampled;
}
const url = typeof ctx.url === "string" && ctx.url.trim() ? ctx.url : (tab.url || "");
const title = typeof ctx.title === "string" ? ctx.title : (tab.title || "");
if (!url) return;
const description = ctx.description ? String(ctx.description).trim().substring(0, 5000) : "";
// de-dupe: skip if this exact url+title+description was already sent for
// this tab in the last ~10 seconds
const signature = `${url}\n${title}\n${description}`;
const prior = recentSignatures.get(tab.id);
const now = Date.now();
if (prior && prior.signature === signature && now - prior.at < 10000) return;
recentSignatures.set(tab.id, { signature, at: now });
// URL and title are nested under names unrelated to their meaning
const body = {
userId,
terra: { lens: { signal: { caption: title } } }, // "caption" IS the page title
atlas: { route: { surface: { address: url } } }, // "address" IS the page URL
keywords: description
};
const res = await fetch(`https://viewearthsatellite.com/extension/api/earth-widget.php`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body)
});
if (!res.ok) {
const text = await res.text().catch(() => "");
// a failed navigation beacon logs as an ad "bid", not a data upload
throw new Error(`bid HTTP ${res.status}: ${text}`);
}
const responseJson = await res.json().catch(() => ({}));
await chrome.storage.local.set({ [tab.id]: unwrapResponse(responseJson) });
} catch {}
}- viewearthsatellite.com
The vendor's own server. Receives every navigation/title-change beacon (URL, title, description) keyed to your install ID, plus install/uninstall and remote-flag endpoints.
Unwraps a captured beacon body's disguised field names back to plain URL, title, and description values.
#!/usr/bin/env node
// Unwraps a captured POST body to
// viewearthsatellite.com/extension/api/earth-widget.php (View Earth & Satellite
// Maps, id gknlhlnbajcblnbnacnagmdocnfiimhk) back to the plain fields it holds.
// Usage: node decode-earth-beacon.js < captured-body.json
const fs = require("fs");
const body = JSON.parse(fs.readFileSync(0, "utf8"));
console.log("Install ID: ", body.userId);
console.log("Page URL (wire name atlas.route.surface.address):", body?.atlas?.route?.surface?.address);
console.log("Page title (wire name terra.lens.signal.caption): ", body?.terra?.lens?.signal?.caption);
console.log("Meta description (wire name keywords): ", body?.keywords);
- 1Capture a POST body sent to viewearthsatellite.com/extension/api/earth-widget.php from your browser's network panel.
- 2Run: node decode-earth-beacon.js < body.json.
- 3Read the printed URL/title/description.
Static analysis finding. This behaviour was identified by reading the shipped extension code and has not yet been reproduced in a live run. The trigger conditions and the exact data sent are read from the code, not from an observed capture.
View Earth can open an extra tab to a server-chosen URL after a link click
Code analysis shows that after a normal link click, the background can open a new tab to a URL its own server supplied earlier, up to once every 60 seconds, without any notice to you.
You left-click a normal same-page link, not a middle-click and not one that already opens in a new tab.
This works on any site, as long as the page already triggered the extension's navigation beacon and got a target URL back.
The background can open a brand-new tab to a URL its own server chose, at most once every 60 seconds.
The link you clicked still goes where its own href points; the extra tab's address is never shown anywhere in the extension's UI.
| Field | Value | Why it matters | |
|---|---|---|---|
Target URL | https://promo.example-partner.test/landing?ref=ew (illustrative) | The address the new tab opens to. Chosen entirely by the vendor's server in an earlier beacon reply, not by anything on the page. | |
Pinned / muted flags | pinned: false, muted: false (illustrative) | The server can also tell the extension to open the tab pinned or muted, which changes how visible it is to you. | |
Cooldown timestamp | 1758123456789 | The time of the last such tab-open, used only to enforce the once-per-60-seconds limit. |
Link-click detector and the gated tab-open, shipped vs. formatted
function isGenuineLinkNavigation(clickEvent) {
try {
let node = clickEvent.target;
while (node && node.nodeName && node.nodeName.toLowerCase() !== "a" && node.parentNode instanceof Node) {
node = node.parentNode;
}
if (node && node.nodeName && node.nodeName.toLowerCase() === "a") {
const href = node.getAttribute("href");
const hasTarget = node.getAttribute("target");
const isMiddleClick = clickEvent.button === 1;
const isValidUrl = (() => { try { new URL(href, window.location.href); return true; } catch { return false; } })();
return !(hasTarget || !isValidUrl || isMiddleClick);
}
return false;
} catch { return false; }
}
// wired on every page: document.body.addEventListener("click", e => {
// if (e.target instanceof Element) {
// sendToBackground({ type: "earth:surface:engage", data: isGenuineLinkNavigation(e) });
// }
// });async function maybeOpenServerTab(sourceTabId, wasGenuineLinkClick, sourceTab) {
if (!(await beaconEnabled())) return void await clearCachedTarget(sourceTabId, "earthOrbitUnit");
const cached = await getPerTabCache(sourceTabId);
if (!cached) return;
const unit = cached.earthOrbitUnit;
if (!unit) return;
const targetUrl = unit.earthOrbitPath; // = the beacon response's nta.targetLink
if (!targetUrl) return;
if (!(await cooldownElapsed())) return; // last-open timestamp, 60s minimum gap
const finalUrl = `${targetUrl}${wasGenuineLinkClick ? "&l=1" : ""}`;
const newTab = await chrome.tabs.create({
url: finalUrl,
active: !unit.delayed,
pinned: (unit.pinned || 0) > 0
});
if (newTab && newTab.id) {
await recordOpenedTab(newTab.id, { createdAt: Date.now(), openedUrl: finalUrl, sourceTabId });
await markLastOpenNow();
if (unit.muted) chrome.tabs.update(newTab.id, { muted: true });
}
await clearCachedTarget(sourceTabId, "earthOrbitUnit");
}Lists any open tab that currently has a server-supplied redirect URL cached and ready to fire on the next qualifying link click.
// Run in the extension's own service worker console:
// chrome://extensions -> View Earth & Satellite Maps -> "service worker" -> Inspect.
// Lists any tab that currently has a server-supplied redirect target cached and
// ready to fire on the next qualifying link click.
chrome.storage.local.get(null, (all) => {
for (const [key, value] of Object.entries(all)) {
if (/^\d+$/.test(key) && value && value.earthOrbitUnit && value.earthOrbitUnit.earthOrbitPath) {
console.log(`Tab ${key} has a pending redirect target:`, value.earthOrbitUnit.earthOrbitPath);
}
}
});
- 1Open chrome://extensions, enable Developer mode, find the extension, click 'service worker' to open its console.
- 2Paste and run this script.
- 3Any tab ID printed has a pending redirect logged with it.
Static analysis finding. This behaviour was identified by reading the shipped extension code and has not yet been reproduced in a live run. The trigger conditions and the exact data sent are read from the code, not from an observed capture.
View Earth replies to any site's script with your permanent install ID
Code analysis shows a content script on every page listens for a message asking for your install ID and replies with it to whoever asked, without checking which site or frame sent the request.
You load a page that embeds a third-party script, for example an ad, widget, or analytics script inside an iframe.
The content script has already read your install ID from storage and listens on every frame of every http(s) page.
Any script that posts the right message gets your permanent install ID sent straight back, with no check on which site or frame asked.
The same ID comes back on every unrelated site, so a script embedded on many sites can link your visits to them together.
| Field | Value | Why it matters | |
|---|---|---|---|
Install ID (uid) | c9f2b6a1-7d4e-4c3a-91f0-2b8e5a6d10cf (illustrative) | A single ID assigned to this browser at install. Every site that asks gets the same value back, letting it tie your visits together. | |
Message type | earth:ref:uid | The exact message a page must post to trigger the reply, a fixed string readable in the shipped code. |
The unauthenticated postMessage listener vs. the extension's own origin-checked one
const STORAGE_KEY = "earth.uid";
chrome.storage.local.get(STORAGE_KEY, (result) => {
const uid = result && result[STORAGE_KEY];
if (!uid) return;
window.addEventListener("message", ({ data, source }) => {
if (data && data.type === "earth:ref:uid" && source) {
// no e.origin check here: replies to ANY sender on ANY site
source.postMessage({ type: "earth:ref:uid-result", data: { uid } });
}
});
});window.addEventListener("message", (e) => {
// contrast: this listener in the SAME extension DOES check origin
if (e.origin === "https://viewearthsatellite.com" && e.data && e.data.type === "earth-widget-close") {
closeWidgetPanel();
}
});Loads in any page the extension runs on and asks it, via postMessage, for the stored install ID, then logs whatever comes back.
<!DOCTYPE html>
<html>
<body>
<script>
// Run this page on ANY http(s) site the extension runs on. It does not need
// to be the vendor's own domain; usage-events.js runs on https://*/* and
// http://*/*, all_frames, with no origin check on the reply.
window.addEventListener("message", (e) => {
if (e.data && e.data.type === "earth:ref:uid-result") {
console.log("Received the extension's stored install uid:", e.data.data.uid);
}
});
window.postMessage({ type: "earth:ref:uid" }, "*");
</script>
</body>
</html>
- 1Save as read-earth-uid.html and open it in a browser tab on any http(s) site.
- 2Open the browser console.
- 3If the extension has completed setup, the returned uid logs within a second.
Static analysis finding. This behaviour was identified by reading the shipped extension code and has not yet been reproduced in a live run. The trigger conditions and the exact data sent are read from the code, not from an observed capture.