ChessVanced

ID: ammcjghngpnnpibfnojlnmeghcmcgdib

Could be malicious

Supported Languages

🇺🇸US English

Extension Info & Metadata

Status
Removed
Version
2.5.0
Size
0.22 MB
Rating
3.3/5
Reviews
12
Users
5,000
Type
Extension
Updated
Sep 19, 2023
Category
Productivity Education
Price
Free
Featured
Yes
Visibility
Listed
Mature
No
By Google
No
Trusted
Yes

Publisher Contextual Analysis

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

Free Game Review for Chess.com and Lichess

ChessVanced is a tool for free game review of chess games, while you play your game on Chess.com or Lichess, the extension will analyze the game in the background, and after the game is finished you may press "Free Game Review" button to be prompted to chessvanced.com where you will view your game review

Item
Type
Severity
Description
offscreen
Permission
High
This permission creates hidden browser documents with full DOM access. Rated High because it can run background operations invisibly, potentially executing malicious code without user awareness.
Contextual Risk Factors
Risk Factor
High
The following context increases the overall risk:• 10% increase: Early script execution enables pre-emptive content manipulation• 25% increase: Unsafe code evaluation capabilities increase attack surface
Unsafe WebAssembly Execution
Risk Factor
High
This extension's CSP allows "wasm-unsafe-eval".
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.
tabs
Permission
Medium
This permission enables tab management and monitoring. Rated Medium because it can track open tabs, access tab metadata, and monitor user browsing patterns.
*://*.chess.com/*
Host
Medium
Host permission — access limited to this URL pattern.
*://*.lichess.org/*
Host
Medium
Host permission — access limited to this URL pattern.
*://*.chessvanced.com/*
Host
Medium
Host permission — access limited to this URL pattern.
Early Content Script Execution
Risk Factor
Medium
This extension runs content scripts at document_start.

When the user visits chessvanced.com/analysis, the extension reads ALL accumulated game data from chrome.storage.local (full move history, FEN positions, Stockfish analysis results, player ELO ratings, player side) and injects it into a hidden DOM element, then dynamically injects contentScript.js as a page-level script tag. This bridges sensitive user chess data from local extension storage to the chessvanced.com page context, where the external website's JavaScript receives and can process it arbitrarily. The dynamic script injection also bypasses CSP controls on the target page.

contentScriptWrapper.js (Line 161)
s.includes(e) ? async function() {  await async function() {    var e = document.createElement("div");    e.id = "injectedData";    const t = await n("analysisData");    e.setAttribute("analysisData", JSON.stringify(t));    const s = await n("moveArray");    e.setAttribute("moveArray", JSON.stringify(s));    const o = await n("fenArray");    e.setAttribute("fenArray", JSON.stringify(o));    const a = await n("analyzedFens");    e.setAttribute("analyzedFens", JSON.stringify(a));    const r = await n("playerSide");    e.setAttribute("playerSide", JSON.stringify(r));    const i = await n("playerElos");    e.setAttribute("playerElos", JSON.stringify(i)), (document.head || document.documentElement)      .appendChild(e)  }();  var e = document.createElement("script");  e.src = chrome.runtime.getURL("contentScript.js"), (document.head || document.documentElement)    .appendChild(e)}()

This injected script runs in the chessvanced.com page context and hands all collected user game data directly to `window.playerControllerInst.setGameFromExtension()`, a function defined and controlled entirely by the chessvanced.com website. The website can implement `setGameFromExtension` to do anything with the data — including sending it to remote servers — and the extension has no visibility or control over this. This creates an uncontrolled trust boundary: the external site fully owns what happens with the scraped chess data.

contentScript.js (Line 1)
!async function() {  for (var {      analysisData: e,      moveArray: a,      fenArray: t,      analyzedFens: r,      playerSide: n,      data: s    } = function() {      var e = {},        a = document.getElementById("injectedData"),        t = JSON.parse(a.getAttribute("analysisData")),        r = JSON.parse(a.getAttribute("movearray")),        n = JSON.parse(a.getAttribute("fenarray")),        s = JSON.parse(a.getAttribute("analyzedFens")),        i = JSON.parse(a.getAttribute("playerSide"));      return e.playerElos = JSON.parse(a.getAttribute("playerElos")), {        analysisData: t,        moveArray: r,        fenArray: n,        analyzedFens: s,        playerSide: i,        data: e      }    }(), i = await async function() {      for (; null == window.playerControllerInst;) await new Promise((e => setTimeout(e, 2e3)));      return window.playerControllerInst    }(); 0 == i.setGameFromExtension(t, a, e, r, n, s);) await new Promise((e => setTimeout(e, 500)))}();

The `MemoryHandlerSet` message handler allows any page listed in `externally_connectable` (chess.com, lichess.org, and chessvanced.com) to write arbitrary key-value pairs into the extension's `chrome.storage.local` by sending a runtime message. Because the storage is shared with all extension components, a malicious or compromised chessvanced.com page could overwrite analysis data, game state, or inject tampered values that influence extension behavior. The `externally_connectable` manifest entry with three domains is the prerequisite that makes this attack surface reachable from external web pages.

backgroundScript.js (Line 1069)
class q {  constructor() {    chrome.runtime.onMessage.addListener((e => {      if ("MemoryHandlerSet" == e.type) {        var r = e.message.key,          t = e.message.value;        this.setData(r, t)      }      if ("MemoryHandlerGet" == e.type) {        r = e.message;        this.getData(r)      }    }))  }  async setData(e, r) {    var t = {};    t[e] = r, await chrome.storage.local.set(t), chrome.runtime.sendMessage({      type: "MemoryHandler",      status: "ok"    })  }

The content script scrapes player ELO ratings from both chess.com and lichess.org DOM elements and continuously polls game state every 2 seconds in an infinite loop. This creates a persistent surveillance pipeline: ELO ratings (personally identifying metadata about a user's chess account ranking) are harvested without explicit user consent and stored in chrome.storage.local before being transmitted to chessvanced.com. The polling interval means even games the user never manually reviews are fully captured.

contentScriptWrapper.js (Line 14)
getPlayersElo() {    try {      var e, t = [];      window.location.href.includes("chess.com") ? e = document.getElementsByClassName("rating-score-rating") :        window.location.href.includes("lichess") && (e = document.getElementsByTagName("rating"));      for (const n of e) t.push(parseInt(n.textContent));      return t    } catch (e) {      return [-1, -1]    }  }  ...  async startScraping() {    for (;;)      if (await new Promise((e => setTimeout(e, 2e3))), this.isLiveGame()) {        this.tryToDeleteButton("chessvanced-floating");        try {          this.sendCurrentGameState()        } catch (e) {}      } else this.sendCurrentGameState(), this.tryToCreateButton()  }

Every chess position analyzed (including positions from chess.com games) is sent to the Lichess cloud eval API with the full FEN string, leaking the user's game positions to a third-party service regardless of which platform the user is playing on. Additionally, `axios` is referenced but is never loaded in the offscreen document (the HTML only loads stockfish.js and mainOffscreenScript.js), meaning this call silently fails at runtime — suggesting either a stripped dependency, code tampering, or a version mismatch where the network exfiltration was removed but the call site was not cleaned up.

offscreen/mainOffscreenScript.js (Line 165)
async getLichessData(e) {  try {    const t = `https://lichess.org/api/cloud-eval?fen=${encodeURIComponent(e)}&multiPv=2`,      s = await axios.get(t);    return s.data.fen ? s.data.pvs.length < 2 ? [!1] : [!0, s.data] : [!1, s.data]  } catch (e) {    return [!1]  }}async checkCache(e) {  const t = await this.getLichessData(e);  return 1 == t[0] ? [!0, this.stockfishParser.cachedDataToParsed(t[1])] : [!1]}

The `externally_connectable` manifest entry grants chess.com, lichess.org, and chessvanced.com the ability to send messages directly to the extension service worker via `chrome.runtime.sendMessage()`. Combined with the `MemoryHandlerSet` listener in backgroundScript.js, this creates a pathway for any page on these domains to write to extension storage. A subdomain takeover, XSS vulnerability, or malicious script on any of these domains could be exploited to tamper with the extension's internal state.

manifest.json (Line 52)
{  "externally_connectable": {    "matches": [      "*://*.chess.com/*",      "*://*.lichess.org/*",      "*://*.chessvanced.com/*"    ]  }}

The background script persistently stores the complete move history, all FEN board positions, player side, and ELO ratings of both players in `chrome.storage.local` with each game update. This creates a long-lived on-device record of the user's chess activity that is subsequently bulk-transferred to chessvanced.com on demand. The `currentGameId` key stores the full game URL, which constitutes browsing history tracking across multiple sessions.

backgroundScript.js (Line 1195)
async analyzeMoveArray(e, r, t, n = [-3, -3]) {    ...    chrome.storage.local.set({      moveArray: this.totalMoveArray    }),    chrome.storage.local.set({      fenArray: this.totalFenArray    }),    chrome.storage.local.set({      playerSide: this.playerSide    }),    chrome.storage.local.set({      playerElos: n    });

By severity

Critical0
High3
Medium3
Low1

Versions scanned

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

Extension VersionCode Review Findings
2.5.07

Files with findings

5 distinct paths — top paths by unique finding count:

  • backgroundScript.js2
  • contentScriptWrapper.js2
  • contentScript.js1
  • manifest.json1
  • offscreen/mainOffscreenScript.js1
S.No.
Category
Severity
File
Summary
Found in Version
1Data Exfiltration
high
contentScriptWrapper.js (line 161)When the user visits chessvanced.com/analysis, the extension reads ALL accumulated game data from chrome.storage.local (full move history, FEN positions, Stockfish analysis results, player ELO ratings, player side) an…
2Data Exfiltration
high
contentScript.js (line 1)This injected script runs in the chessvanced.com page context and hands all collected user game data directly to `window.playerControllerInst.setGameFromExtension()`, a function defined and controlled entirely by the …
3Privilege Escalation
high
backgroundScript.js (line 1069)The `MemoryHandlerSet` message handler allows any page listed in `externally_connectable` (chess.com, lichess.org, and chessvanced.com) to write arbitrary key-value pairs into the extension's `chrome.storage.local` by…
4Data Exfiltration
medium
offscreen/mainOffscreenScript.js (line 165)Every chess position analyzed (including positions from chess.com games) is sent to the Lichess cloud eval API with the full FEN string, leaking the user's game positions to a third-party service regardless of which p…
5Privilege Escalation
medium
manifest.json (line 52)The `externally_connectable` manifest entry grants chess.com, lichess.org, and chessvanced.com the ability to send messages directly to the extension service worker via `chrome.runtime.sendMessage()`. Combined with th…
6Unauthorized Data Collection
medium
contentScriptWrapper.js (line 14)The content script scrapes player ELO ratings from both chess.com and lichess.org DOM elements and continuously polls game state every 2 seconds in an infinite loop. This creates a persistent surveillance pipeline: EL…
7Unauthorized Data Collection
low
backgroundScript.js (line 1195)The background script persistently stores the complete move history, all FEN board positions, player side, and ELO ratings of both players in `chrome.storage.local` with each game update. This creates a long-lived on-…
URLs
9
IPv4
0
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.

chessvanced.com/analysishttps://chessvanced.com/analysis
www.chess.com/gamehttps://www.chess.com/game
clients2.google.com/service/update2/crxhttps://clients2.google.com/service/update2/crx
github.com/niklasf/stockfish.wasmhttps://github.com/niklasf/stockfish.wasm
emscripten.org/docs/porting/pthreads.htmlhttps://emscripten.org/docs/porting/pthreads.html#blocking-on-the-main-browser-thread
github.com/ddugovic/Stockfishhttps://github.com/ddugovic/Stockfish
github.com/niklasf/stockfish.jshttps://github.com/niklasf/stockfish.js
github.com/kripken/emscripten/wiki/WebAssemblyhttps://github.com/kripken/emscripten/wiki/WebAssembly#binaryen-methods
lichess.org/api/cloud-evalhttps://lichess.org/api/cloud-eval?fen=${encodeURIComponent(e

Gain full insight into all external connections.

Upgrade for full visibility.

No IP addresses found
Showing 1 to 5 of 10 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.