Is 图片批量下载助手 safe?

High risk

图片批量下载助手 is high risk. The extension has no visible UI. Opening the panel loads a page from chrome.tool56.com into a shadow-DOM iframe. That page controls what it reads, sends, and runs as JS, with no integrity check, so behavior can change anytime unannounced.…

hxshi127v2.2.0Chrome Web Store
73Risk
Who publishes it

hxshi127 - 2 other listings from the same operator, none carrying a finding

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

Publisher
hxshi127

Same store account

2 other listings published from this account, 1k+ users between them, none of them carrying a finding.

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

Publishers can request a review.

Findings

Extension UI is served from a remote server with no integrity check

The extension has no visible UI.

Opening the panel loads a page from chrome.tool56.com into a shadow-DOM iframe.

That page controls what it reads, sends, and runs as JS, with no integrity check, so behavior can change anytime unannounced.

Severity
Medium unwanted
Type
Unexpected
CWE
CWE-829
Source
Dynamic sandbox
What actually happens
You did this

You open the extension panel by clicking the toolbar icon.

The extension has no bundled interface, opening the panel triggers a live fetch from the remote server.

The extension did this

The extension injects a shadow-DOM iframe whose src is a URL on chrome.tool56.com, cache-busted by the current minute.

Whatever HTML and scripts the server returns at that moment become the extension's active behaviour.

The code that does this

Remote iframe injection, no SRI, cache-busted each minute

Readable version
var baseUrl = 'https://chrome.tool56.com';// Dev fallback: switch to HTTP on .t TLDif (window.location.protocol === 'http:' && window.location.href.includes('.t/'))  baseUrl = 'http://chrome.tool56.t';baseUrl += '/image-downloader/2.0/2.1.html';baseUrl += '?v=' + Math.floor(Date.now() / 60000);  // cache-bust per minuteconst host = document.createElement('chrome-ext');host.id = 'chromeExt';document.body.parentNode.insertBefore(host, document.body.nextSibling);shadowRoot = host.attachShadow({ mode: 'open' });// Inject the remote iframe — no integrity attributeshadowRoot.innerHTML = `  ...  <iframe id="imageDownloader" src="${baseUrl}" class="ext-frame"></iframe>  ...`;
Primitives the remote HTML can invoke via postMessage
  • JavaScript evaluation
    requestGetVal with val:'document.cookie'

    Remote HTML can ask the extension to evaluate any JavaScript expression in the current page's context.

  • Cross-origin fetch proxy
    requestFetchUrlData → https://internal.example.com/api/v1/users

    Remote HTML can direct the extension to fetch any URL on the internet and receive the full response.

  • Full page HTML and URL
    requestGetPageData → {html: '<!DOCTYPE html>…', urlInfo: location}

    Remote HTML can read the complete DOM and current URL of any page you visit.

  • Extension storage read/write
    requestSaveSetting {field:'setting', data:{width:80}}

    Remote HTML can read and overwrite any key in the extension's synced storage.

Remote host that controls extension behaviour
    • chrome.tool56.com

    Serves the extension's entire UI and determines which content-script primitives are invoked each session. Operated by the extension developer (phototool.cn).

Dynamic analysis confirmation

Confirmed live: shadow DOM inspection on Wikipedia showed `<iframe src="https://chrome.tool56.com/image-downloader/2.0/2.1.html?v=29608474">`. The remote page loaded and immediately directed 23 background fetches (dynamic analysis). The extension ships no bundled HTML for the panel; all behaviour is runtime-determined.

Extension acts as an unrestricted cross-origin fetch proxy for a remote iframe

While the panel is open, a remote iframe from chrome.tool56.com can direct the extension to fetch any URL and get the full response.

Broad permissions bypass cross-origin limits and attach cookies. 23 requests confirmed live.

Severity
Medium unwanted
Type
Unexpected
CWE
CWE-940
Source
Dynamic sandbox
What actually happens
You did this

The remote iframe on chrome.tool56.com sends a postMessage with type 'requestFetchUrlData', any target URL, and custom headers.

No allowlist or origin validation is applied in the content script or background handler.

The extension did this

The background service worker fetches the target URL with extension privileges, reads the full response body, and posts all headers and content back to the remote iframe.

This grants the remote server the ability to issue authenticated cross-origin requests from the user's browser.

The code that does this

Background fetch handler, no URL restriction, full response returned

Readable version
case 'fetchUrlData':  var url = e.url || '';  var headers = e.header || {};  // caller-supplied, no validation  var readType = e.readType || 'readAsText';  var result = { url: url, status: 0 };  fetch(url, headers)  // any URL, any headers    .then(function(response) {      response.blob().then(function(blob) {        var reader = new FileReader();        reader.onloadend = function() {          result.data = this.result;        // full response body          result.status = 1;          result.type = response.type;          result.contentType = response.headers.get('Content-Type');          result.contentSize = response.headers.get('Content-Length');          result.statusCode = response.status;          result.statusText = response.statusText;          const allHeaders = {};          response.headers.forEach((v, k) => { allHeaders[k] = v; });          result.header = allHeaders;       // all response headers          sendResponse(result);             // returned to remote iframe        };        if (typeof reader[readType] !== 'function') readType = 'readAsText';        reader[readType](blob);      });    })    .catch(function(err) {      console.error('request error', err);      result.status = 0;      sendResponse(result);    });  return true;  // keep message channel open for async response
The code that does this

Content script relay, forwards iframe postMessage to background

Readable version
case 'requestFetchUrlData':  var msg = n;          // n.url, n.header from the remote iframe  msg.type = 'fetchUrlData';  // Forward to background service worker  chrome.runtime.sendMessage(msg, function(bgResponse) {    // Return full response (body + headers) to the remote iframe    postMessage(bgResponse, callbackId);  });  break;
Dynamic analysis confirmation

Confirmed live on Wikipedia: with the panel open, the chrome.tool56.com iframe issued 23 cross-origin GET requests to Wikipedia and Wikimedia image URLs (observed during dynamic analysis). All responses were relayed back to the iframe. The remote server, not the extension package, determines which URLs are fetched.

What it can do

Permissions this extension asks for, as declared in version 2.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

    *://*/*

  • Store data in your browser

    storage

  • Add items to the right-click menu

    contextMenus

  • Keep running in the background while your browser is open

    background

Updated 15 October 2026ehpgophpmjmlcmjhpmhjognkehlpnfld