Is Friend Disconnector safe?

High risk

Friend Disconnector sends Facebook friend profiles and activity metrics to api.frienddisconnector.com.

Friend Disconnector runs on Facebook pages, queries Facebook's GraphQL endpoints for friend records, and builds profiles with names, Facebook IDs, profile URLs, avatars, location fields, messages, reactions, comments, activity status, and engagement counts. It stores those records locally and sends them to api.frienddisconnector.com, and it also sends friend names to an AWS Lambda endpoint to infer gender, country, or tier data.

Tier5 Technologiesv2.0.50Chrome Web Store
72Risk
Who publishes it

Tier5 Technologies - 5 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
Tier5 Technologies

Same store account

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

Shared hosts - 1 hostname

Hostnames hardcoded in this extension that few other listings call. That can mean one operator behind both, and it can equally mean a small shared vendor, so it is context rather than a conclusion. Hosts that many listings call are left out: they are services, not connections.

api.frienddisconnector.com
Also called by 4 other listings, including Friend Ejector, Xooma Intelligence Disconnector, Peace Out

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

Publishers can request a review.

Findings

Facebook friend graph uploaded to Friend Disconnector

Friend Disconnector's Facebook sync reads friend records from GraphQL responses, then the background script sends them, including profile IDs, URLs, avatars, location, and engagement counts, to api.frienddisconnector.com/friends.

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

You start Friend Disconnector's Facebook friend sync or analyze flow.

The extension only runs its content script on facebook.com pages.

The extension did this

The extension builds friend records and sends them to Friend Disconnector's API.

Each record can include profile identifiers, profile URLs, avatar URLs, locations, and engagement counts.

Fields assembled before upload
  • Friend name
    Alex Morgan (illustrative)

    Identifies a person in your Facebook friend list.

  • Facebook ID
    100064789123456 (illustrative)

    Links the record to a specific Facebook account.

  • Profile URL
    https://www.facebook.com/100064789123456 (illustrative)

    Lets the recipient open or correlate the friend profile.

  • Avatar URL
    https://scontent.xx.fbcdn.net/v/t39.30808-1/349123456_123456789012345_987654321_n.jpg (illustrative)

    Adds a profile image URL to the person record.

  • Location fields
    Canada / Toronto (illustrative)

    Adds country or hometown context from the Facebook profile.

  • Activity metrics
    messages: 4, reactions: 6, comments: 2, engagements: 8 (illustrative)

    Shows how often you have interacted with that friend.

  • Activity flags
    hasConversation: true, isActive: true (illustrative)

    Marks whether the friend appears active or has a conversation history with you.

  • Fetcher ID
    100012345678901 (illustrative)

    Links the uploaded friend record back to your Facebook account running the sync.

Captured request
POSThttps://api.frienddisconnector.com/friends
The code that does this

Friend records are built in the content script and uploaded by the background script

Readable version

Readable equivalent of FBGraphQLService.fetchFriends

content.js
static fetchFriends(accessToken, fetcherId, fbDtsg, cursor, includeActivity = false, createNew = true, retryFlag = "no") {  return new Promise(async (resolve, reject) => {    try {      if (includeActivity) {        await delay(1000);        await this.fetchExcludedPostsIdNew(fetcherId, fbDtsg, null);      }      const form = {        av: fetcherId,        __user: fetcherId,        __a: 1,        dpr: 1,        fb_dtsg: fbDtsg,        fb_api_caller_class: "RelayModern",        fb_api_req_friendly_name: "FriendingCometFriendsListPaginationQuery",        variables: JSON.stringify({ count: 30, cursor, name: null, scale: 1 }),        server_timestamps: true,        doc_id: 0xf2a65945cd96b      };      const response = await fetch("https://www.facebook.com/api/graphql/", {        method: "POST",        headers: {          "Content-Type": "application/x-www-form-urlencoded",          Accept: "text/html,application/json",          "x-fb-friendly-name": "FriendingCometFriendsListPaginationQuery"        },        body: this.serializeFBReq(form)      });      const graph = await response.json();      if (!isEmpty(graph) && graph.hasOwnProperty("data") && graph.data.hasOwnProperty("viewer") && graph.data.viewer.hasOwnProperty("all_friends")) {        if (graph.data.viewer.all_friends.hasOwnProperty("edges")) {          graph.data.viewer.all_friends.edges.forEach(async (edge) => {            if (!isEmpty(edge)) {              const { id: friendId, gender, name, image, profile_picture, location, hometown } = edge.node;              if (edge.node.id) {                const avatar = !isEmpty(image) && image.hasOwnProperty("uri") && image.uri                  ? image.uri                  : !isEmpty(profile_picture) && profile_picture.hasOwnProperty("uri") && profile_picture.uri ? profile_picture.uri : "";                const profileUrl = `https://www.facebook.com/${friendId}`;                const rawCountry = location && location.hasOwnProperty("location") && location.location && location.location.hasOwnProperty("country") ? location.location.country : null;                const hometownName = hometown && hometown.hasOwnProperty("name") ? hometown.name.split(", ").slice(-1).pop() : "";                const messages = await this.getMessageCount(fbDtsg, fetcherId, friendId);                const reactions = this.reactors.hasOwnProperty(friendId) ? this.reactors[friendId] : 0;                const comments = this.commenters.hasOwnProperty(friendId) ? this.commenters[friendId] : 0;                const hasConversation = messages > 2;                const isActive = messages > 2 || reactions > 0 || comments > 0;                const engagements = reactions + comments;                const foundAt = new Date().getTime();                let normalizedLocation = { tier: "", country: "" };                if (rawCountry || hometownName) normalizedLocation = await normalizeCountry(rawCountry || hometownName);                const friend = {                  name,                  fbId: friendId,                  fetcherId,                  url: profileUrl,                  avatar,                  isDeactivated: false,                  gender,                  country: normalizedLocation.country,                  hometown: hometownName,                  messages,                  reactions,                  comments,                  hasConversation,                  isLost: false,                  isActive,                  engagements,                  foundAt,                  profilePictureUrl: avatar,                  isWhitelisted: false,                  isUnfriended: false,                  tier: normalizedLocation.tier,                  finalSync: 0,                  sync: 0                };                this.friends[friendId] = friend;                this.friendsForSync.push(friend);                chrome.runtime.sendMessage({ type: MessageTypes.SEND_FRIENDS_TO_BG, data: friend, createNew });                await delay(500);              }            }          });          await delay(1000);          this.friendsForSync = [];        }        if (graph.data.viewer.all_friends.hasOwnProperty("page_info") && graph.data.viewer.all_friends.page_info.hasOwnProperty("has_next_page") && graph.data.viewer.all_friends.page_info.has_next_page && graph.data.viewer.all_friends.page_info.end_cursor) {          return resolve(this.fetchFriends(accessToken, fetcherId, fbDtsg, graph.data.viewer.all_friends.page_info.end_cursor, false, createNew, retryFlag));        }        if (await delay(30000), await delay(1000), retryFlag === "no") {          return resolve(this.fetchFriends(accessToken, fetcherId, fbDtsg, null, false, createNew, "yes"));        }        resolve();      }    } catch (error) {      reject(error);    }  });}

Readable equivalent of FriendService.sync

background.js
static sync(token, friends, isFresh, fetcherId) {  return new Promise(async (resolve, reject) => {    try {      await this.http.authorization(token).post("friends", {        friends,        isFresh,        fetcherId      });      resolve();    } catch (error) {      reject(error);    }  });}
External services involved in the flow
    • www.facebook.com

    Source of the GraphQL friend-list data read by the content script.

    • api.frienddisconnector.com

    Receives the friend records through the /friends API path.

What it can do

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

    https://*.facebook.com/*

  • Read and change your data on api.frienddisconnector.com

    https://api.frienddisconnector.com/*

  • Read and change your data on amazonaws.com

    https://*.amazonaws.com/*

  • Read and change your data on frienddisconnector.com

    *://*.frienddisconnector.com/*

  • Schedule its own background tasks

    alarms

  • Store data in your browser

    storage

  • Store an unlimited amount of data in your browser

    unlimitedStorage

Where it sends data

Destinations our analysis observed Friend Disconnector 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.

  • api.frienddisconnector.com

    Friend Disconnector sends data to api.frienddisconnector.com. 3 other extensions we have analysed send data here.

  • z7c5j0fjy8.execute-api.us-east-2.amazonaws.com

    Friend Disconnector sends data to z7c5j0fjy8.execute-api.us-east-2.amazonaws.com. One other extension we have analysed sends data here.

Updated 30 September 2026oncjohnhemocpnedeokkhphpleaiajkk