Is Ads Trust safe?

Medium risk

Ads Trust reads Facebook Ads access tokens from business pages and stores them for display in its popup.

On Facebook Ads Manager and Business Manager pages, the content script scans page scripts for accessToken values and sends the token to the extension background page. The background stores it in local extension storage by tab, and the popup can reveal or copy the token for the active tab.

CPA.RIPv0.6Chrome Web Store
45Risk
Who publishes it

CPA.RIP - 1 other listing 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

1 other listing published from this account, 50k+ 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

Ads Trust reads your Facebook access token from the page and stores it locally

On Facebook Ads Manager and Business Manager pages, Ads Trust reads your account access token straight out of the page and saves it in its own local storage, where its popup displays the full value with a copy button.

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

You visit a page on adsmanager.facebook.com or business.facebook.com while logged in.

The extension's content script runs automatically on any page under either domain.

The extension did this

The extension reads your account access token out of the page's own script tags and saves it.

The token is passed to the background service worker and written to the extension's local storage.

What the extension extracts and keeps
  • Facebook access token
    EAAGm0PX4ZCpsBAK...Zwlo (illustrative)

    Whoever holds this token can act on your Facebook Ads or Business Manager account until it expires or is revoked.

The code that does this

Extraction, storage, and popup display, in the extension's own shipped source

Readable version

Content script scans every script tag for a token

js/app.js
function getAccessToken () {	const scriptNodes = document.querySelectorAll('script');	let accessToken = null;	for (const node of scriptNodes) {		const text = node.textContent;		if (!text) continue;		const m = text.match(/window\.__accessToken="([^"]+)"/);		if (m) {			accessToken = m[1];			break;		}	}	return accessToken;}function getAnOtherToken () {	const scriptNodes = document.querySelectorAll('script');	let token = null	const regex = /"accessToken":"([^"]+)"/;	for (const node of scriptNodes) {		const dataString = node.textContent;		if (!dataString) continue;		const match = dataString.match(regex);		if (match) {			token = match[1];		}	}	return token;}function handleActivated() {	const data = getLevel();	const accessToken = getAccessToken();	const anOtherTokenData = getAnOtherToken();	trustData = {		level: data?.level,		hit: data?.hit,		accessToken: accessToken || anOtherTokenData	}	chrome.runtime.sendMessage({ icon: data?.level, hit: data?.hit, accessToken: accessToken || anOtherTokenData });}handleActivated();

Service worker persists the token to chrome.storage.local

js/background.js
chrome.runtime.onMessage.addListener(function (msg, sender, sendResponse) {  const tabId = sender.tab?.id;  if (!tabId) return;  chrome.storage.local.get(['trustData'], (res) => {    const all = res.trustData || {};    all[tabId] = {      ...(all[tabId] || {}),      hit: msg?.hit ?? all[tabId]?.hit,      accessToken: msg?.accessToken ?? all[tabId]?.accessToken,      anOtherTokenData: msg?.anOtherTokenData ?? all[tabId]?.anOtherTokenData,      level: msg?.icon ?? all[tabId]?.level,      isAdsManager: Boolean(msg?.icon) || all[tabId]?.isAdsManager || false,    };    chrome.storage.local.set({ trustData: all });  });});

Popup shows the full token behind a reveal button and offers a copy button

js/popup.js
function renderToken(name, tokenParam) {  const {hasToken, fullToken, shortToken} = tokenParam;  return `<p class="access-token-block">                ${name}: <b        id="access-token-value"        class="access-token-value"        data-full-token="${hasToken ? fullToken : ''}"        data-short-token="${shortToken}"        data-visible="short"      >${shortToken}</b>      ${hasToken ? `          <button id="toggle-access-token" class="toggle-access-token" title="Show / hide full token">\u{1F441}</button>          <button id="copy-access-token" class="copy-access-token" title="Copy full token">\u{1F4CB}</button>        ` : ''}          </p>`}
What's stored on your device

The extension keeps a copy of your token in local storage for as long as the tab stays open, alongside showing it in the popup.

Location
chrome.storage.local key 'trustData', one entry per open tab
Contents
{  "trustData": {    "1585209825": {      "level": "2",      "accessToken": "EAAGm0PX4ZCpsBAK...Zwlo (illustrative)",      "isAdsManager": true    }  }}
What we did and did not observe

We confirmed this by planting a marker value on an in-scope Ads Manager page and tracing it into storage and the popup. No network destination was found; the confirmed flow stays on the device.

What it can do

Permissions this extension asks for, as declared in version 0.6. 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 open.er-api.com

    https://open.er-api.com/*

  • See the address and title of every tab you have open

    tabs

  • Act on the current tab, but only after you click the extension

    activeTab

  • Store data in your browser

    storage

Updated 30 September 2026lanhjpladilgmdkepgeggnllpiofkefi