Is Ads Trust safe?
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.
Who publishes itCPA.RIP - 1 other listing from the same operator, none carrying a finding
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
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 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.
- Facebook access tokenEAAGm0PX4ZCpsBAK...Zwlo (illustrative)
Whoever holds this token can act on your Facebook Ads or Business Manager account until it expires or is revoked.
Extraction, storage, and popup display, in the extension's own shipped source
Content script scans every script tag for a token
js/app.jsfunction 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.jschrome.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.jsfunction 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>`}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
{ "trustData": { "1585209825": { "level": "2", "accessToken": "EAAGm0PX4ZCpsBAK...Zwlo (illustrative)", "isAdsManager": true } }}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