Is Illust Downloader for pixiv.net safe?

Low risk

Illust Downloader is low risk. When a licensed user downloads Pixiv content with PC sync and history on, the extension builds a history record and queues it for sync to orca-soft.net: item ID, content type, timestamp, title, compacted thumbnail URL, and author name.

OrcaSoftv1.10.0.0Chrome Web Store
20Risk
Who publishes it

OrcaSoft - 4 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.

Same store account

4 other listings published from this account, 91k+ 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

Pixiv download history synced to orca-soft.net

When a licensed user downloads Pixiv content with PC sync and history on, the extension builds a history record and queues it for sync to orca-soft.net: item ID, content type, timestamp, title, compacted thumbnail URL, and author name.

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

You download Pixiv content with PC sync and download history enabled.

The sync path is also gated on the extension's license check succeeding.

The extension did this

The extension records that download and queues it to be sent to orca-soft.net.

The content script sends a sync_history_wr message, and the background script posts queued records for synchronization.

Fields included in the queued download-history record
  • Pixiv item identifier
    p_a_12345678 (illustrative)

    Links the synced history entry to the specific Pixiv item you downloaded.

  • Content type
    i (illustrative)

    Shows whether the saved item was an illustration, manga, ugoira, novel, or another Pixiv item type.

  • Download time
    1720839117245 (illustrative)

    Adds a time marker to your saved Pixiv history entry.

  • Pixiv page title
    Summer seaside illustration (illustrative)

    Names the downloaded work in the synced history entry.

  • Compacted thumbnail URL
    |C2024/07/12/12/34/56/12345678_p0|F (illustrative)

    Carries a thumbnail reference for the downloaded Pixiv item.

  • Author name
    pixiv_user_123 (illustrative)

    Associates the synced download-history entry with the Pixiv creator shown on the page.

  • Sync operation
    add

    Marks the record as a new history item to add during synchronization.

What's stored on your device

Your Pixiv download-history record can wait in the extension's local queue before the next synchronization upload.

Location
chrome.storage.local key syncDataList
Contents
{  "syncDataList": [    {      "a": "i",      "c": "|C2024/07/12/12/34/56/12345678_p0|F",      "d": 1720839117245,      "n": "pixiv_user_123",      "t": "Summer seaside illustration",      "u": "p_a_12345678",      "sync": "add"    }  ]}
Captured request
POSThttps://orca-soft.net/chrome/pd/sync_api.php

The code treats a text response of done as successful synchronization and removes matching queued records.

Headers
Content-Type
application/x-www-form-urlencoded
The code that does this

The content script creates the history record and the background script uploads the queue

Readable version

sh.js: successful downloads become sync_history_wr records

sh.js
1 == e ? $("a.pxvdwn_l[data-num=" + y +  "]").bind("click", function() {  var G = location.href;  yb(y);  ({    dlmat: na,    novel: ta,    unlisted: va  } = Fa(location.href));  Oa(G)}) : $("a.pxvdwn_l[data-num=" + y + "]").bind("click", function() {  yb(y);  Oa(g)});if (option.iine_dl) {  var c = $("section section").find("button > svg[viewBox='0 0 12 12']").parent().parent();  c.click(function() {    "disabled" != c.find("button").attr("disabled") && $("a.pxvdwn_l[data-num=" + y + "]").click()  });  $("html").keydown(function(G) {    76 == G.keyCode && "disabled" != c.find("button").attr("disabled") && $("a.pxvdwn_l[data-num=" +      y + "]").click()  })}function yb(a) {  $("a.pxvdwn_l[data-num=" + a + "]").css({    "pointer-events": "none",    opacity: .5  })}function Oa(a) {  var g = cb();  if (($a || ab) && Ca) alert(chrome.i18n.getMessage("download_in_progress"));  else {    Ca = !0;    var e = na,      f = ta,      I = va,      y = Za(na, ta, va);    try {      chrome.runtime.sendMessage({        mode: "permissions_check"      }, function(D) {        1 == D.result ? chrome.runtime.sendMessage({          mode: "op"        }, function(M) {          try {            option = JSON.parse(M.option), version = M.version, update = M.update, l = M.l, lspop = M.lspop, ni = M.n, syncTime = M.syncTime, memozed =              JSON.parse(M.memozed), memozedDef = M.memozedDef, ex_md = M.md, after_flag = M.after, eb = 0, Eb(g), Pa({                url: y,                cache: !1,                success: function(U) {                  Fb(U, a, e, g, f, I)                },                error: function(U, W, T) {                  Ja ? fb ? ka.push("[" + W + "] " + a) : (ka.push("[" + W + "] " + a), retryMsg = chrome.i18n.getMessage("alldl_append_msg"), "error" === W ? alert(chrome.i18n.getMessage("dl_sippai") + retryMsg) : "timeout" === W ? alert(chrome.i18n.getMessage("dl_timeout") + retryMsg) : alert(chrome.i18n.getMessage("dl_sippai") + retryMsg)) : "error" === W ? alert(chrome.i18n.getMessage("dl_sippai")) :                    "timeout" === W ? alert(chrome.i18n.getMessage("dl_timeout")) : alert(chrome.i18n.getMessage("dl_sippai"));                  wa(g);                  la(!1)                }              })          } catch (U) {            alert(chrome.i18n.getMessage("unknown_error"))          }        }) : wa(g)      })    } catch (D) {      Ma()    }  }}function Eb(a) {  zb = setTimeout(function() {    qa(chrome.i18n.getMessage("outou_machi"), !0, a)  }, 2E3)}function wa(a) {  clearTimeout(zb);  qa("", !1, a);  $("a.pxvdwn_l").attr("style", "")}function la(a, g, e) {  Ca = !1;  a && Gb(g, e);  option.illust_downloaded && $("body").find("a[data-gtm-value],span[data-gtm-value],a[href*='/artworks/'],a[href*='/novel/show.php']").each(function() {    Qa($(this),      !1)  })}function Hb(a) {  a = a.replace("https://i.pximg.net/", "|A");  a = a.replace("c/600x600/novel-cover-master/img/", "|B");  a = a.replace("c/250x250_80_a2/img-master/img/", "|C");  a = a.replace("c/250x250_80_a2/custom-thumb/img/", "|D");  a = a.replace("_master1200.jpg", "|E");  a = a.replace("_square1200.jpg", "|F");  return a = a.replace("_custom1200.jpg", "|G")}function Gb(a, g) {  if (!va) {    var e = "illust" === g[0].type || "manga" === g[0].type || "ugoira" === g[0].type ? "p_a_" : "novel" === g[0].type ? "p_n_" : "p_u_",      f = Date.now();    a = {      u: e + a[1],      a: g[0].type[0],      d: f,      t: g[0].historyDataArray.title,      c: Hb(g[0].historyDataArray.thumb),      n: g[0].historyDataArray.userName    };    g[0].historyDataArray.r && (a.r = 1);    try {      chrome.runtime.sendMessage({        mode: "dl_w",        jsonData: a      })    } catch (I) {      Ma();      return    }    vb();    if (option.syncPC && option.dl_history && l.result) try {      chrome.runtime.sendMessage({        mode: "sync_history_wr",        userId: option.syncId,        syncData: {          ...a,          sync: "add"        }      }, function(I) {        "error" === I.result && alert(chrome.i18n.getMessage("sync_id_error"))      })    } catch (I) {      Ma()    }  }}

bg.js: sync_history_wr is queued and sent to sync_api.php

bg.js
"sync_history_wr" === a.mode && da(a.mode, a.userId, a.syncData, 1).then(f => {  c({    result: f  })});"sync_history_rm" === a.mode && da(a.mode, a.userId, a.syncData, 2).then(f => {  c({    result: f  })});"sync_history_get" === a.mode &&  V(a.userId, function(f) {    c(f)  });"sync_pointer_refresh" === a.mode && ia(a.userId, function(f) {  c(f)});"sync_check" === a.mode && (S(), c({}))let Z = Promise.resolve();const da = (() => {    async function a(g) {      await Y(async () => {        let l = await h.getItem("syncDataList");        Array.isArray(l) || (l = []);        g && g.u && (l.push(g), await h.setItem("syncDataList", l))      })    }    async function b(g) {      function l(m, r = {}) {        const u = new AbortController,          x = setTimeout(() => u.abort(), 5E3);        return fetch(m, {          ...r,          signal: u.signal        }).finally(() => clearTimeout(x))      }      let q = await h.getItem("syncDataList");      if (!Array.isArray(q) || 0 === q.length) return "done";      const t = new URLSearchParams;      t.append("i", JSON.stringify(q));      t.append("u", g);      t.append("m", "1");      g = 0;      let f = "";      for (; 3 > g;) try {        f = await (await l("https://orca-soft.net/chrome/pd/sync_api.php", {          method: "POST",          cache: "no-store",          headers: {            "Content-Type": "application/x-www-form-urlencoded"          },          body: t.toString()        })).text();        if ("done" === f) {          let m = await h.getItem("syncDataList");          Array.isArray(m) || (m = []);          const r = q.map(u => u.u);          m = m.filter(u =>            !r.includes(u.u));          await h.setItem("syncDataList", m);          return "done"        }        if ("error" === f) return "error";        g++;        if (3 < g) return f;        await new Promise(m => setTimeout(m, 5E3))      } catch (m) {        g++;        if (3 < g) return "fetch_error";        await new Promise(r => setTimeout(r, 5E3))      }      return f    }    let c = null;    return async function(g, l, q) {      await a(q);      c && clearTimeout(c);      c = setTimeout(() => {        Y(() => b(l))      }, 2E3)    }  })()
Synchronization destination
    • orca-soft.net

    Receives the extension's PC synchronization requests for Pixiv download-history records.

What it can do

Permissions this extension asks for, as declared in version 1.9.2.0. Asking for a permission is not a finding on its own - it is what the extension can do if it chooses to. The current listed version is 1.10.0.0, which we have not unpacked yet.

  • Read and change your data on pixiv.net

    http://*.pixiv.net/ and 1 more

  • Read and change your data on pximg.net

    http://*.pximg.net/ and 1 more

  • Read and change your data on orca-soft.net

    http://orca-soft.net/ and 1 more

  • Store data in your browser

    storage

  • Store an unlimited amount of data in your browser

    unlimitedStorage

  • Start, monitor and manage your downloads

    downloads

  • Block and redirect the requests your browser makes

    declarativeNetRequest

  • Show you desktop notifications

    notifications

  • Run hidden pages in the background

    offscreen

declarativeNetRequestWithHostAccess
Updated 30 September 2026fnbkeopcpjainobjebddfcnnknmfipid