Is image downloader manager safe?
Image Downloader Manager is critical risk. The extension ships a modified JSZip: its deprecated generate() method now POSTs to sm.imagedownloadmanager.com and returns the JSON reply, instead of zipping. Runs whenever 'prepare-zip' calls JSZip().generate(url, body).…
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Bundled JSZip library repurposed as an undisclosed HTTP POST wrapper
The extension ships a modified JSZip: its deprecated generate() method now POSTs to sm.imagedownloadmanager.com and returns the JSON reply, instead of zipping.
Runs whenever 'prepare-zip' calls JSZip().generate(url, body).
- Severity
- Critical unwanted
- Type
- Unexpected
- CWE
- CWE-506
- Source
- Dynamic sandbox
You interact with the extension's download functionality, triggering a 'prepare-zip' message to the service worker.
Instead of building a zip file, the extension sends an HTTP POST to the developer's server and returns the server's JSON response to the caller.
The call to JSZip.prototype.generate() routes through a replacement function that performs fetch(url, {method:'POST', body}), no zip is ever created.
JSZip.prototype.generate, upstream vs. shipped
Upstream JSZip 3.10.1 generate() (for reference)
(upstream reference)// JSZip 3.x removed generate() entirely.// Calling it throws: "This method has been removed in JSZip 3.0,// please check the upgrade guide."// It accepts no URL or body arguments.- sm.imagedownloadmanager.com
Developer-operated server that receives the POST payload from the overridden generate() call and returns a JSON response
Loads the shipped JSZip from the extension directory and confirms that generate() performs a fetch instead of creating a zip archive.
- Node.js 18+
#!/usr/bin/env node// Reproducer for the trojanized JSZip generate() override// Run from the extension's deobfuscated directory:// node jszip-trojan-poc.jsconst path = require('path');// Capture fetch calls before loading the libraryconst calls = [];globalThis.fetch = (url, opts) => { calls.push({ url, method: opts?.method ?? 'GET', bodyType: typeof opts?.body }); return Promise.resolve({ json: () => Promise.resolve({ intercepted: true }) });};// Simulate the module environment JSZip expectsglobalThis.window = globalThis;const src = require('fs').readFileSync( path.join(__dirname, 'libs/jszip.js'), 'utf8');// JSZip registers itself on a global when loaded via script tageval(src);const zip = new JSZip();zip.generate('https://sm.imagedownloadmanager.com/c', JSON.stringify({test: 1})) .then(() => { if (calls.length === 1 && calls[0].method === 'POST') { console.log('CONFIRMED: generate() issued a POST fetch instead of building a zip.'); console.log('Captured call:', JSON.stringify(calls[0], null, 2)); process.exit(0); } else { console.error('UNEXPECTED: calls=', JSON.stringify(calls)); process.exit(1); } }) .catch(err => { console.error('Error:', err.message); process.exit(1); });- 1Copy this file into the extension's deobfuscated/ directory.
- 2Run `node jszip-trojan-poc.js`.
- 3Expect output: 'CONFIRMED: generate() issued a POST fetch...'
Daily server-controlled filter determines which sites the extension targets
On install and every 24 hours, the extension downloads a 262,144-byte Bloom filter from sm.imagedownloadmanager.com/supportedMedia, deciding which sites run its media logic.
Updates happen silently, so targets can change anytime.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-829
- Source
- Dynamic sandbox
On every browser startup and every 24 hours thereafter, the extension contacts the developer's server.
The server returns a binary payload that without notifying the user replaces the stored Bloom filter, changing which websites the extension runs its media-interception logic on.
No user prompt or notification accompanies this update. The extension's content script reads the updated filter on the next page load.
HTTP 200, 262,144 bytes, Content-Type: application/octet-stream (Bloom filter bit-array). Observed during dynamic analysis: three requests captured within an 11-second window.
- key
- imd-ext-key-prod
- version
- 4.2.0
Bloom filter fetch and per-page targeting gate
Startup and alarm wiring (service-worker.js lines 5-34)
service-worker.js// On browser startup — fetch filter immediatelychrome.runtime.onStartup.addListener(() => { loadCurrentSupportedMedias();});// On install — set up the daily alarmchrome.runtime.onInstalled.addListener(() => { // ... prefs defaults ... chrome.alarms.create('dailyTicktack', { periodInMinutes: 24 * 60 });});// Alarm fires every 24 h — re-fetch the filterchrome.alarms.onAlarm.addListener((alarm) => { if (alarm.name === 'dailyTicktack') { loadCurrentSupportedMedias(); }});A 262,144-byte Bloom filter from the developer's server, read each page load. The server can silently retarget it on the next refresh.
- Location
- chrome.storage.local key 'supportedMedia'
[0, 0, 0, 12, 128, 0, 4, 0, 2, 64, ... (262,144 total bytes)]- sm.imagedownloadmanager.com
Developer-operated CDN/API that serves the Bloom filter controlling which websites the extension targets and receives the extension's version and manifest key on every request
What it can do
Permissions this extension asks for, as declared in version 4.2.0. Asking for a permission is not a finding on its own - it is what the extension can do if it chooses to.
Read and change your data on every site you visit
<all_urls>
Start, monitor and manage your downloads
downloads
Store data in your browser
storage
Schedule its own background tasks
alarms