Is Unfollower Tracker for Top Photo App safe?

Medium risk

Unfollower Tracker for IG receives server-controlled extraction patterns and can open arbitrary URLs on command from besocial.top.

Each time the popup opens, the extension contacts besocial.top to check its license token. The server response can supply updated regex-like delimiters that the extension stores and uses to extract the Instagram CSRF token and username from inline page scripts. The same response can also supply an open_link URL, which the extension immediately opens in a background tab with no validation.

BeSocialToolsv1.2.5Chrome Web Store
45Risk

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

Publishers can request a review.

Findings

SeverityMEDIUM
ClassUNWANTED
TypeUnexpected
CWECWE-829
SourceAI SANDBOX

Server-Supplied Rules Extract Instagram Session Fields

Checking Instagram account status asks besocial.top for tokenizer rules and saves the returned CSRF-token and username delimiters.

The content script applies those to Instagram scripts, so the remote response decides what text is captured.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You open the extension while it checks an Instagram page.

The extension did this

The extension asks besocial.top for tokenizer rules, stores the returned delimiters, and uses them to read Instagram session fields from page scripts.

02EvidenceNETWORK CAPTURE
Captured request
GEThttps://besocial.top/unfollower-tracker/check-token.php?token=<redacted>&version=1.2.1&chn=chrome-extension
Confirmed response JSON contained csrf_tokenizer and user_tokenizer objects with start and end delimiters.
03EvidenceFIELD TABLE
Fields controlled or extracted by the tokenizer flow
FieldValueWhy it matters
CSRF-token delimiters
csrf_tokenizer.start=',{"csrf_token":"' and csrf_tokenizer.end='"},'These rules decide where the extension starts and stops reading the Instagram CSRF token from page script text.
Username delimiters
user_tokenizer.start='"username":"' and user_tokenizer.end='","'These rules decide where the extension starts and stops reading the Instagram username from page script text.
Instagram CSRF token
HcT6rNp9vQ2mX4sLa8Kb3YdF0wJe1ZuG (illustrative)This credential-related value is tied to an active Instagram session and can be used by code running in the extension.
Instagram username
acme.social.ops (illustrative)This links the extracted session data to a specific Instagram account.
04EvidenceSTORAGE DUMP
What's stored on your device

The saved tokenizer objects become the rules used during the next Instagram page-script scan.

Locationchrome.storage.local keys csrf_tokenizer and user_tokenizer
Contents (JSON)
{
  "default_csrf_tokenizer": {
    "end": "\"},",
    "start": ",{\"csrf_token\":\""
  },
  "default_user_tokenizer": {
    "end": "\",\"",
    "start": "\"username\":\""
  },
  "server_response_handling": "If the response contains csrf_tokenizer or user_tokenizer, popup.js writes those objects to chrome.storage.local and later sends them to content.js."
}
05EvidenceCODE COMPARE
The code that does this

Remote rules are fetched, stored, sent to the content script, and applied to Instagram scripts

What it actually does
Remote rule fetchpopup/popup.js
check_pro: async function() {
  let t = this,
    e = chrome.runtime.getManifest().version,
    n = i.g + "check-token.php?token=" + t.token + "&version=" + e + "&chn=" + i.b,
    r = null;
  try {
    r = await fetch(n, {
      muteHttpExceptions: !0
    })
  } catch (e) {
    return console.log(e), void t.$emit("server_error", e)
  }
  const a = await r.json();
  let s = a;
  0 == a.premium ? t.is_pro = !1 : t.is_pro = !0, t.is_pro_status_init = !0, t.is_pro || t.is_trial || !a.trial || t.has_trial_show || (t.offer_trial_end = a.trial.trial_end, t.$emit("trial_offer", a.trial), t.has_trial_show = !0), t.is_sub = "1" == a.sub_status, a.notice && t.notice != a.notice && (s.notice_dialog = !0), s.is_pro = t.is_pro || t.is_trial, s.is_sub = t.is_sub, a.open_link && t.open_link != a.open_link && (t.open_link = a.open_link, chrome.tabs.create({
    url: t.open_link,
    active: !1
  })), a.more_tools && (t.more_tools = a.more_tools), t.$emit("server", s)
}
Server response stores tokenizer objectspopup/popup.js
on_server_response: function(t) {
  let e = this;
  e.is_pro = t.is_pro, e.is_sub = t.is_sub, t.more_tools && (e.more_tools = t.more_tools), e.notice = t.notice, e.notice_dialog = t.notice_dialog, e.server_response = t, t.csrf_tokenizer && chrome.storage.local.set({
    csrf_tokenizer: t.csrf_tokenizer
  }, t => {}), t.user_tokenizer && chrome.storage.local.set({
    user_tokenizer: t.user_tokenizer
  }, t => {})
}
Popup sends stored tokenizers to the content scriptpopup/popup.js
connect_content: function() {
  let t = this,
    e = chrome.tabs.connect(t.ig_tab_id);
  e.onMessage.addListener((function(e) {
    "GetInsStatusRsp" == e.type && (console.log(JSON.stringify(e)), t.loading_profile_done = !0, e.is_login && e.username ? (t.ig_username = e.username, t.ig_avatar = e.avatar, t.csrf_token = e.csrf_token, t.igapi = new v(e.csrf_token), t.ig_state = t.IG_READY, chrome.tabs.remove([t.ig_tab_id], (function() {})), clearInterval(t.conn_timer), t.on_ig_ready()) : (t.ig_state = t.IG_NOT_LOGIN, clearInterval(t.conn_timer), t.show_login_required_dialog = !0))
  })), chrome.storage.local.get(["csrf_tokenizer", "user_tokenizer"], n => {
    let r = n.csrf_tokenizer || t.default_csrf_tokenizer,
      i = n.user_tokenizer || t.default_user_tokenizer;
    e.postMessage({
      type: "GetInsStatusReq",
      csrf_tokenizer: r,
      user_tokenizer: i
    })
  })
}
Content script extracts fields with supplied delimiterscontent.js
function n(e, t, n) {
  let r = e.indexOf(t),
    o = e.indexOf(n, r + t.length);
  return r > 0 && o >= 0 ? e.substr(r + t.length, o - r - t.length) : ""
}
let r = 0;
chrome.runtime.onConnect.addListener((function(e) {
  e.onMessage.addListener((function(t) {
    if ("GetInsStatusReq" == t.type) {
      let o = !document.querySelector(".not-logged-in"),
        i = "",
        u = "",
        l = "";
      if (o) {
        let e = document.querySelectorAll("script");
        for (let o = 0; o < e.length; o++) {
          if (e[o].text.startsWith("window._sharedData = ")) {
            r = 1;
            let t = "window._sharedData = ".length,
              n = JSON.parse(e[o].text.substr(t, e[o].text.length - 1 - "window._sharedData = ".length));
            i = n.config.viewer.username, u = n.config.viewer.profile_pic_url;
            break
          }
          r = 2;
          let s = n(e[o].text, t.csrf_tokenizer.start, t.csrf_tokenizer.end);
          s && (l = s);
          let a = n(e[o].text, t.user_tokenizer.start, t.user_tokenizer.end);
          if (a && (i = a), l && i) break
        }
      }
      e.postMessage({
        type: "GetInsStatusRsp",
        is_login: o,
        username: i,
        avatar: u,
        csrf_token: l,
        v: r
      })
    }
  })), e.postMessage({
    type: "Hello"
  })
}))}
06EvidenceTHIRD PARTY LIST
Remote host involved in this tokenizer flow
  • besocial.top

    Receives the extension token/version/channel check request and returns tokenizer delimiter objects used for Instagram script parsing.

Data recipients

besocial.top
Updated 17 September 2026coimhafkimmplkidfmhelnlkjpihopnk