Extenssr

ID: camiehngogdpflplmapknnjkeeofhfop

Supported Languages

🇺🇸US English

Extension Info & Metadata

Status
Active
Version
2.6.3
Size
34.91 MB
Rating
4.4/5
Reviews
9
Users
5,000
Type
Extension
Updated
Nov 3, 2023
Category
Just for fun
Price
Free
Featured
No
Visibility
Listed
Mature
No
By Google
No
Trusted
No

Publisher Contextual Analysis

Author
Extenssr DevelopersView Profile
MX records exist
Yes
Domain exists
Yes
Is disposable
No
Is role-based
No
Mailbox exists
Yes
Total Extensions
1
Active
1
Obsolete
0
Listed
1
Unlisted
0
Total Users
5,000

'Extenssr - A browser extension for Geoguessr'

This is an extension for the browser based geography game Geoguessr. Latest change log: https://gitlab.com/nonreviad/extenssr/-/blob/main/Changelog.md This is a browser extension for the browser based map game Geoguessr. Current functionality: - show exact locations for completed Battle Royale rounds - filter effects on the map - bookmark locations as you find them on the map - cursed game modes Complete features list: https://gitlab.com/nonreviad/extenssr/-/blob/main/Readme.md

Item
Type
Severity
Description
Contextual Risk Factors
Risk Factor
High
The following context increases the overall risk:• 10% increase: Early script execution enables pre-emptive content manipulation
storage
Permission
Medium
This permission allows storing data locally in the browser. Rated Medium because it can persist sensitive user data, track user activities over time, and potentially store malicious payloads.
unlimitedStorage
Permission
Medium
This permission removes storage quota restrictions. Rated Medium because it can store large amounts of user data without limits, potentially impacting browser performance and storing extensive tracking data.
Early Content Script Execution
Risk Factor
Medium
This extension runs content scripts at document_start.

The extension completely replaces the global `window.WebSocket` constructor with a subclass that intercepts every outgoing `send()` call and every incoming `message` event, re-dispatching the full parsed payloads as DOM CustomEvents. This gives the extension visibility into all WebSocket traffic on geoguessr.com — including live game state, round data, and any authentication tokens transmitted over the socket — before any existing page code sees it.

websocket_inject.bundle.js (Line 13)
class s extends WebSocket {  constructor(s, E) {    super(s, E);    const t = this.send;    this.send = (...s) => {      t.apply(this, s);      const E = JSON.parse(s[0]);      document.dispatchEvent(new CustomEvent(e.WEBSOCKET_MESSAGE, {        detail: {          type: e.WEBSOCKET_MESSAGE,          wsMessage: E        }      }))    }, this.addEventListener("message", (s => {      const E = JSON.parse(s.data);      document.dispatchEvent(new CustomEvent(e.WEBSOCKET_MESSAGE, {        detail: {          type: e.WEBSOCKET_MESSAGE,          wsMessage: E        }      }))    }))  }}window.WebSocket = s

A MutationObserver watches the entire document for new script elements whose `src` begins with `https://maps.googleapis.com/`. When the Maps API script is detected, the extension hijacks its `onload` handler to immediately replace `google.maps.StreetViewPanorama` with a subclass before any page code runs. This is a supply-chain style hook: the extension inserts itself between the Maps SDK initialization and the host page, guaranteeing it controls the class before the game registers any panoramas.

street_view_inject.bundle.js (Line 80)
i = function(t) {    t.maps.StreetViewPanorama = class extends t.maps.StreetViewPanorama {      constructor(t, n) {        super(t, n), e.reinit(this), s.reinit(this)      }    }  }, new MutationObserver(((t, e) => {    const s = function(t) {      for (const e of t)        for (const t of e.addedNodes) {          const e = t;          if (e && e.src && e.src.startsWith("https://maps.googleapis.com/")) return e        }      return null    }(t);    s && function(t, e, s) {      const n = t.onload;      t.onload = i => {        const o = window.google;        a && t.disconnect(), s(o), n && n.call(t, i)      }    }(s, e, i)  }))  .observe(document.documentElement, {    childList: !0,    subtree: !0  })

The extension hooks `document.createElement` to intercept every canvas element created on the page, then forces `preserveDrawingBuffer = true` on all WebGL contexts. Enabling `preserveDrawingBuffer` prevents the GPU from discarding frame data after compositing, allowing pixel readback (e.g., via `readPixels`) at any time. Combined with the full wrapping of ~20 WebGL API methods (shaderSource, useProgram, all uniform setters), this gives the extension persistent access to the rendered frame buffer and deep control over the WebGL pipeline.

canvas_inject.bundle.js (Line 64)
getContext: e => function(...o) {    const c = o[0],      d = c && c.startsWith("webgl") && "preserveDrawingBuffer" in o[1];    d && (o[1].preserveDrawingBuffer = !0);    const s = e.apply(this, o);    if (d) {      let e = "default",        o = !1;      const c = {};      s.oldShaderSource = s.shaderSource, s.oldGetUniformLocation = s.getUniformLocation, s        .oldAttachShader = s.attachShader, s.oldUniform1fv = s.uniform1fv, s.oldUniform2fv = s        .uniform2fv, s.oldUniform3fv = s.uniform3fv;      // ... wraps: attachShader, getUniformLocation, shaderSource,      // uniform1f/fv/i/iv, uniform2f/fv/i/iv, uniform3f/fv/i/iv,      // uniform4f/fv/i/iv, uniformMatrix2/3/4fv, useProgram

After monkey-patching the Google Maps StreetViewPanorama class (by intercepting the Maps API script load via MutationObserver), the extension attaches a `position_changed` listener that fires on every Street View movement and captures the user's exact lat/lng coordinates. All position data is broadcast as DOM events consumed by content.bundle.js, which stores them for route replay. While used for in-game features, this constitutes continuous geographic tracking of every map position the user visits.

street_view_inject.bundle.js (Line 17)
reinit(e) {  this.deinit(), e && (this.streetView = e, this.moveListener = e.addListener("position_changed", (() => {    const e = this.streetView.getPosition(),      s = {        lat: e.lat(),        lng: e.lng()      };    document.dispatchEvent(new CustomEvent(t.MOVE_ON_MAP, {      detail: {        pos: s      }    })), this.bindBackToHomeButton()  })))}

Uses the same MutationObserver pattern as street_view_inject to intercept the Google Maps API load event and replace `google.maps.Map` with a subclass that captures the first Map instance. This gives the extension a persistent reference to the game's map object, used to draw polylines and inject saved-location markers — but also grants the ability to call any Map API method, read map bounds, center, zoom, or attached data layers at any time.

maps_inject.bundle.js (Line 95)
i = function(e) {    e.maps.Map = class extends e.maps.Map {      constructor(e, i) {        super(e, i);        const a = this.addListener("idle", (() => {          null === t && (t = this, s.reinit(this), o.reinit(this), a.remove())        }))      }    }  }, new MutationObserver(((e, t) => {    const s = function(e) {      for (const t of e)        for (const e of t.addedNodes) {          const t = e;          if (t && t.src && t.src.startsWith("https://maps.googleapis.com/")) return t        }      return null    }(e);    s && function(e, t, s) {      const o = e.onload;      e.onload = i => {        const a = window.google;        a && t.disconnect(), s(a), o && o.call(e, i)      }    }(s, t, i)  }))  .observe(document.documentElement, {    childList: !0,    subtree: !0  })

The extension wraps `document.createElement` itself on the document object, meaning every call site that creates any element passes through extension-controlled code. While the inner branch only activates for `canvas`, the outer wrapper intercepts all element creation at the document level — a broader hook than needed for legitimate shader injection, and a pattern that could be expanded to intercept other element types.

canvas_inject.bundle.js (Line 59)
t(document, {      createElement: e => function(...o) {          const n = e.apply(this, o),            c = o[0];          return c && "canvas" === c.toLowerCase() && t(n, {                getContext: e => function(...o) {

By severity

Critical0
High2
Medium3
Low1

Versions scanned

Showing 1 of 45 scanned versions with more than one unique finding. Counts are unique findings that include each version.

Extension VersionCode Review Findings
2.6.36

Files with findings

4 distinct paths — top paths by unique finding count:

  • canvas_inject.bundle.js2
  • street_view_inject.bundle.js2
  • maps_inject.bundle.js1
  • websocket_inject.bundle.js1
S.No.
Category
Severity
File
Summary
Found in Version
1Code Injection
high
street_view_inject.bundle.js (line 80)A MutationObserver watches the entire document for new script elements whose `src` begins with `https://maps.googleapis.com/`. When the Maps API script is detected, the extension hijacks its `onload` handler to immedi…
2Network Interception
high
websocket_inject.bundle.js (line 13)The extension completely replaces the global `window.WebSocket` constructor with a subclass that intercepts every outgoing `send()` call and every incoming `message` event, re-dispatching the full parsed payloads as D…
3Code Injection
medium
canvas_inject.bundle.js (line 64)The extension hooks `document.createElement` to intercept every canvas element created on the page, then forces `preserveDrawingBuffer = true` on all WebGL contexts. Enabling `preserveDrawingBuffer` prevents the GPU f…
4Code Injection
medium
maps_inject.bundle.js (line 95)Uses the same MutationObserver pattern as street_view_inject to intercept the Google Maps API load event and replace `google.maps.Map` with a subclass that captures the first Map instance. This gives the extension a p…
5Tracking
medium
street_view_inject.bundle.js (line 17)After monkey-patching the Google Maps StreetViewPanorama class (by intercepting the Maps API script load via MutationObserver), the extension attaches a `position_changed` listener that fires on every Street View move…
6Code Injection
low
canvas_inject.bundle.js (line 59)The extension wraps `document.createElement` itself on the document object, meaning every call site that creates any element passes through extension-controlled code. While the inner branch only activates for `canvas`…
URLs
182
IPv4
9
IPv6
0

URLs

View the external URLs this extension communicates with to understand its network activity and data interactions.

Gain full insight into all external connections.

Upgrade for full visibility.

stuk.github.io/jszip/documentation/howto/read_zip.htmlhttps://stuk.github.io/jszip/documentation/howto/read_zip.html
fb.me/use-check-prop-typeshttp://fb.me/use-check-prop-types
reactjs.org/docs/error-decoder.htmlhttps://reactjs.org/docs/error-decoder.html?invariant=
www.w3.org/1999/xlinkhttp://www.w3.org/1999/xlink
www.w3.org/XML/1998/namespacehttp://www.w3.org/XML/1998/namespace
www.w3.org/1999/xhtmlhttp://www.w3.org/1999/xhtml
www.w3.org/2000/svghttp://www.w3.org/2000/svg
www.w3.org/1998/Math/MathMLhttp://www.w3.org/1998/Math/MathML
reactjs.org/link/react-polyfillshttps://reactjs.org/link/react-polyfills
www.geoguessr.com/game/$%7Bn.token%7D%60;window.location.assign(rhttps://www.geoguessr.com/game/${n.token}`;window.location.assign(r
Showing 1 to 10 of 190 rows
Rows per page:

Gain full insight into all external connections.

Upgrade for full visibility.

3.1.1.1
IPv4
-
3.1.2.1
IPv4
-
3.1.3.1
IPv4
-
3.1.4.1
IPv4
-
3.1.5.1
IPv4
-
3.1.6.1
IPv4
-
3.1.7.1
IPv4
-
7.1.1.1
IPv4
-
9.1.1.1
IPv4
-
Showing 1 to 10 of 50 rows
Rows per page:

Code Diff

Compare extension code between any two versions.

0 changed files (scanned top 25 shared text files)

No comparable text files found between these versions.

Browse and explore files within this extension package

Gain full insight into all external connections.

Upgrade for full visibility.