Is Friend Requests Sender - Send, Track, Cancel & Auto Add Friends safe?

Medium risk

Friend Requests Sender collects Facebook users' email, phone, address, and birthday from imported profiles, undisclosed in its listing.

When you paste or upload a list of Facebook profile IDs to send friend requests to, the extension also fetches each profile's 'Contact and basic info' page in the background, disguising the request as a normal page visit to avoid detection. It parses out each person's email, phone/WhatsApp number, address, hometown, birthday, and relationship status, stores the results locally, and shows them in table columns you can export to a CSV file. None of this contact-harvesting is mentioned in the extension's Chrome Web Store description, which only advertises sending, tracking, and canceling friend requests.

otisniermanwzv1.1.0Chrome Web Store
45Risk

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

Publishers can request a review.

Findings

SeverityHIGH
ClassUNWANTED
TypeUnexpected
CWECWE-359
SourceAI FOUND

Friend Requests Sender pulls email, phone and birthday off imported profiles

Code analysis shows that importing a Facebook profile fetches that person's private contact info in the background and saves their email, phone, address and birthday, none of which the store listing discloses.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You paste a Facebook profile URL or ID into the extension's 'Import New' dialog.

This adds that person to your bulk friend-request list.

The extension did this

The extension fetches that profile's private contact info in the background and saves their email, phone, address and birthday to your device.

The request's headers are rewritten to match a real page load, avoiding Facebook's automation checks.

02EvidenceCODE COMPARE
The code that does this

Rewriting the profile URL and spoofing navigation headers before the fetch

What it actually does
Tee(): normal profile URL -> contact-info URLcontent-ui.js
// Tee(profileUrl): rewrite a normal profile URL to Facebook's
// "Contact and basic info" endpoint before it's fetched.
function Tee(profileUrl) {
  const url = new URL(profileUrl);
  if (url.searchParams.has("id")) {
    // profile.php?id=123 -> ...&sk=directory_contact_info
    url.searchParams.set("sk", "directory_contact_info");
  } else {
    // /username -> /username/directory_contact_info
    url.pathname = `${url.pathname.replace(/\/+$/, "")}/directory_contact_info`;
  }
  return url.toString();
}
M(): fetch a profile page with headers spoofed as a real navigationbackground.js
// M(profileUrl): runs in the service worker. Installs a temporary
// declarativeNetRequest rule that rewrites this one request's headers
// to look like a real browser page load, fetches with the logged-in
// user's own Facebook cookies attached, then removes the rule.
async function M(profileUrl, timeoutMs = 15000) {
  const ruleId = Math.floor(Date.now() % 1e6) + Math.floor(1000 * Math.random());
  const rule = {
    id: ruleId,
    priority: 100,
    action: {
      type: "modifyHeaders",
      requestHeaders: [
        { header: "sec-fetch-mode", value: "navigate", operation: "set" },
        { header: "sec-fetch-dest", value: "document", operation: "set" },
        { header: "accept", value: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", operation: "set" },
      ],
    },
    condition: {
      urlFilter: `||${new URL(profileUrl).host}/`,
      resourceTypes: ["xmlhttprequest"],
      tabIds: [chrome.tabs?.TAB_ID_NONE ?? -1],
    },
  };
  await chrome.declarativeNetRequest.updateSessionRules({ removeRuleIds: [ruleId], addRules: [rule] });
  try {
    const response = await fetch(profileUrl, { credentials: "include" });
    return await response.text();
  } finally {
    await chrome.declarativeNetRequest.updateSessionRules({ removeRuleIds: [ruleId] });
  }
}
03EvidenceFIELD TABLE
What gets pulled from the target's 'Contact and basic info' page
FieldValueWhy it matters
Email address
d.alvarez1988@gmail.comThe personal email tied to their account, collected without their knowledge.
Phone / WhatsApp number
+1 786 555 0134A direct line to the person, unrelated to sending them a friend request.
Current city
Miami, FloridaWhere they currently live, day to day.
Hometown
San Juan, Puerto RicoWhere they grew up, a common bank and email security-question answer.
Birthday
March 14, 1988Full date of birth, another common account-recovery answer.
Relationship status
In a relationshipA personal-life detail scraped alongside their contact info.
04EvidenceCODE COMPARE
The code that does this

Saving a harvested record for every imported ID, then exporting it

What it actually does
One fetch-and-save cycle per pasted IDcontent-ui.js
// w(ids, status): runs once per profile ID pasted or uploaded into
// 'Import New'. Fetches that profile's harvested record and stores it.
async function importProfiles(ids, status) {
  ids = ids.filter(Boolean);
  if (ids.length === 0) return;
  await forEachWithDelay(ids, async (id) => {
    if (existingRows.find((row) => row.id === id)) return;
    const details = await Kee({ id, name: "", url: `https://www.facebook.com/profile.php?id=${id}` });
    const current = await profileStore.get();
    if (current.find((row) => row.id === id)) return;
    await profileStore.set([...current, { id, status, log: "", details, selected: false }]);
  });
  setStatus("Ready");
}
Mapping a saved record onto CSV/XLSX columnscontent-ui.js
// Maps one saved profile row onto the spreadsheet columns produced
// by the extension's CSV/XLSX export button.
function toExportRow(row) {
  const d = row.details;
  return {
    ID: d?.id,
    Name: d?.name,
    Gender: d?.gender,
    Birthday: d?.birthday,
    Relationship: d?.relationship || "",
    Hometown: d?.hometown?.name || "",
    Location: d?.location?.name || "",
    Bio: d?.bio || "",
    Category: d?.category || "",
    Email: d?.email || "",
    "Phone Number": d?.mobile_phone || "",
    Websites: d?.websites?.join(", ") || "",
  };
}
05EvidencePLAIN NOTE
Not in the store listing

The CWS listing advertises only bulk friend-request sending and says 'all data remains on your device.' It never discloses that importing a profile also harvests that person's own contact details.

06EvidencePLAIN NOTE
Observation

Static analysis finding. This behaviour was identified by reading the shipped extension code and has not yet been reproduced in a live run. The trigger conditions and the exact data sent are read from the code, not from an observed capture.

Updated 30 September 2026padhkflcigakphahffhcgfnfiddimngo