Is Onoff Business | Click2Call & SMS safe?
We analyzed Onoff Business | Click2Call & SMS version 2.12.1's actual code and gave it a 62/100 trust score. This is a useful but broad calling extension…
Bottom line
This is a useful but broad calling extension that automatically reads phone numbers across most websites and sends them to Onoff, creating meaningful privacy and security concerns.
What it can access
It scans visible text across nearly every website, adds calling controls, can use the microphone, and sends found numbers to Onoff, which is broad but partly aligned with its purpose. [Q1][Q2][Q5][Q6]
Security weaknesses
Automatic page scanning and narrowly targeted traffic changes create misuse opportunities, while server messages are limited to fixed account and display actions. [Q8][Q16][Q18]
Signs of misuse
The extension automatically sends page phone numbers and some active page addresses to Onoff and analytics services, alongside persistent usage tracking. [Q6][Q12][Q13][Q14]
Code findings
What access does this extension ask for, and does that access make sense for what it claims to do?
It declares an all-URLs page access plus tabs, scripting, storage, unlimited storage and declarative request-rule access. The cross-site access supports its advertised click-to-call feature, but it is broad: after authentication the script scans most visible pages by default.
Declares the permissions, an all-URLs content script, narrow Onoff host permissions and one request-rule file. — manifest.json:23-61
src/content/script/index.ts enables the page parser only while authenticated, below the device limit and not paused for the current host. — content.js.map:1
Which websites can it run on, and can it read or change what appears on those pages?
It runs on almost every URL after sign-in, walks visible text nodes, detects phone numbers, replaces matched text with clickable highlighted elements and adds a fixed extension widget. It skips scripts, styles, textareas, options, hidden nodes and editable regions.
Registers content.js and content.css on all URLs except listed Onoff pages. — manifest.json:33-40
src/content/script/phoneNumbersParser/lib/domTreeWalker/index.ts filters visible non-editable text, while src/content/script/phoneNumbersParser and its components highlight matches and watch DOM changes. — content.js.map:1
src/content/script/index.ts gates activation by authentication and paused-host state and responds to highlighting preferences. — content.js.map:1
Can it see sensitive information you type, such as passwords, payment details, messages, or form entries?
No evidence of this behavior was found in the reviewed package.
src/content/script/phoneNumbersParser/lib/domTreeWalker/index.ts rejects HTMLTextAreaElement, HTMLOptionElement and contenteditable descendants. — content.js.map:1
src/content/widget/screens/Messages/components/MessagesFooter handles text entered in the extension widget and sends it only on the send action or Enter. — widget.js.map:1
Can it access private browser data such as cookies, signed-in sessions, browsing history, bookmarks, or downloads?
No evidence of this behavior was found in the reviewed package.
cookies, history, bookmarks and downloads permissions are absent. — manifest.json:23-29
src/serviceWorker/storage/slices/authentication/actions/thunk.ts stores the access token returned by Onoff after login/MFA and maintains an extension device token. — widget.js.map:1
Can it access anything else on your device, such as files, location, camera, microphone, clipboard, or installed applications?
The embedded calling widget is allowed to request microphone access for calls and can enumerate/select audio devices through its calling library. A visible file picker can upload user-selected image or audio attachments.
src/content/script/components/WidgetIFrame/index.ts creates the extension iframe with allow='microphone'. — content.js.map:1
src/content/widget/screens/Messages/components/MessagesFooter selects a user-chosen file and dispatches the upload only when the user sends it. — widget.js.map:1
No camera, geolocation, clipboardRead, nativeMessaging or file-system permission is declared. — manifest.json:23-29
Does it send information outside your browser? If so, what information is sent, where does it go, and why?
After each page scan, newly found phone numbers are automatically POSTed to Onoff's contact-summary services. Onoff also receives expected login credentials, device details, calls, messages and user-selected attachments.
src/content/widget/@redux/actions/phoneNumbersParser/index.ts dispatches contactsGetContactsForNumbers at scan completion; ContactsService POSTs the numbers to mobile/contacts/find-contact-summary-by-number. — widget.js.map:1
src/common/services/AnalyticsService/index.ts sends deviceToken as client_id, userId and events to google-analytics.com; authentication/actions/thunk.ts and useAnalyticsServiceWidget include currentUrl. — widget.js.map:1
src/serviceWorker/index.ts forwards content-script errors and their page URL to Sentry. — background.js.map:1
AuthenticationService and MessagesService send credentials, messages and selected media through fixed Onoff service workflows. — widget.js.map:1
Does it download or run code, settings, or instructions supplied by a remote server?
It receives account, contact, call and message data plus authenticated PubNub events from Onoff. Those events can update displayed user/category/message state or force logout through a fixed switch.
src/content/widget/hooks/usePubNub/hooks/usePubNubMessagesHandler/index.ts accepts only enumerated category, message, user-change and force-logout event types. — widget.js.map:1
src/content/widget/services/MessagesService/index.ts uses a server-provided preSignedUrl only for the user-selected attachment upload. — widget.js.map:1
No eval call was found; the fixed new Function global fallback has no server response or message argument. — widget.js:2
Can it take actions without a clear user request, such as opening pages, redirecting searches, downloading files, or sending requests?
Once signed in and not paused, page scanning starts automatically and repeats after page mutations; scan completion automatically requests contact matches for new numbers. Calls, messages, attachment uploads, settings pages and the full Onoff web app require a visible user action.
src/content/script/index.ts starts the parser when the authenticated storage selector becomes active; phoneNumbersParser re-runs on page mutations. — content.js.map:1
src/content/widget/@redux/actions/phoneNumbersParser/index.ts automatically resolves scanned numbers against Onoff contacts. — widget.js.map:1
src/serviceWorker/helpers/openWebApp/index.ts opens or focuses the fixed Onoff web app only after an internal click-triggered message. — background.js.map:1
Can it change important browser settings, including your proxy, search engine, homepage, privacy settings, or other extensions?
No evidence of this behavior was found in the reviewed package.
The permissions list omits proxy, search, homepage, management and privacy APIs. — manifest.json:23-29
Is any important behavior difficult to inspect because the code is hidden, heavily obfuscated, dynamically generated, or supplied by third parties?
No evidence of this behavior was found in the reviewed package.
Source maps are packaged and even listed as web-accessible resources. — manifest.json:42-51
Contains named original sources for analytics, authentication, contact lookup, messages, PubNub and UI behavior. — widget.js.map:1
Does it use eval(), new Function(), or string-based timers to turn text into executable code?
No evidence of this behavior was found in the reviewed package.
Webpack runtime fallback calls new Function with the literal string 'return this'. — widget.js:2
Contains the same build-runtime global-object fallback rather than data-dependent code generation. — background.js:2
Does it track the websites, pages, searches, or links you visit?
No evidence of this behavior was found in the reviewed package.
authentication/actions/thunk.ts adds currentUrl to the cx_login event; useAnalyticsServiceWidget adds it to cx_send_msg. — widget.js.map:1
src/serviceWorker/index.ts adds the content script's window.location.href to the Sentry scope only when reporting an extension error. — background.js.map:1
Phone-number scan completion sends newly found numbers to Onoff's contact resolver without an additional click. — widget.js.map:1
Does it create a persistent ID or browser fingerprint to recognize you?
It creates and persistently stores a random device token. Onoff receives it as a device/instance identifier, and Google Analytics receives it as client_id together with the signed-in Onoff user ID.
src/serviceWorker/storage/slices/authentication/actions/thunk.ts generates and persists deviceToken and sends device metadata during login/MFA. — widget.js.map:1
src/common/services/AnalyticsService/index.ts uses deviceToken as client_id and the account ID as user_id. — widget.js.map:1
Does it send cookies, session details, authentication data, or page contents elsewhere?
The user-entered Onoff email/password and MFA data go to Onoff's fixed authentication services, which is ordinary first-party login rather than demonstrated credential theft. The extension also sends found page phone numbers to Onoff and event-based active URLs to Google Analytics/Sentry.
src/serviceWorker/services/AuthenticationService/index.ts sends login and MFA bodies only through the fixed Onoff API base. — widget.js.map:1
ContactsService receives normalized found phone numbers; AnalyticsService sends currentUrl events to Google Analytics. — widget.js.map:1
No cookies permission is declared. — manifest.json:23-29
Does it record typing, form entries, clipboard contents, or screenshots?
No evidence of this behavior was found in the reviewed package.
src/content/script/phoneNumbersParser/lib/domTreeWalker/index.ts excludes textareas and editable descendants. — content.js.map:1
The widget MessageInput is controlled locally and messagesSendTextMessageHandler runs on the visible send action. — widget.js.map:1
No clipboardRead, desktopCapture or tabCapture permission is present. — manifest.json:23-29
Can a website or remote server send commands that make the extension take actions?
Onoff can send authenticated per-user PubNub events that add/update/delete categories, display a new message, update user data or force logout. The handler uses an explicit switch and ignores unknown types; it cannot evaluate code, modify arbitrary webpages or invoke arbitrary extension methods.
src/content/widget/hooks/usePubNubConfig subscribes to a user/device-specific TLS channel with a server-issued auth key. — widget.js.map:1
usePubNubMessagesHandler/index.ts enumerates the only accepted event types; its category, message and user handlers dispatch fixed state actions. — widget.js.map:1
Does it alter links, referral codes, advertisements, shopping carts, or search results?
It replaces detected phone-number text with styled clickable number elements and adds call/message controls, matching the advertised feature. No link rewriting, affiliate code, advertising injection, cart modification or search-result manipulation was found.
src/content/script/phoneNumbersParser/components/HighlightedPhoneNumber and ActionIcon create the number wrapper and Onoff action controls. — content.js.map:1
Click handlers start an Onoff call/message or open the fixed Onoff web app; they do not change links or purchase flows. — content.js.map:1
Does it redirect or modify web traffic, request headers, downloads, or proxy settings?
A declarative rule removes the Origin request header from main-frame or subframe requests to Onoff's mobile services when initiated outside the two trusted Onoff domains. This is a confirmed but narrowly scoped traffic modification.
The enabled rule removes only Origin for *.onoffapp.net/mobile/* main/subframe requests and excludes onoffbusiness.com and onoff.app initiators. — rules.json:1-20
Loads rules.json as the sole declarativeNetRequest ruleset; proxy and downloads permissions are absent. — manifest.json:53-61
Can it communicate with software on the computer or services running on localhost?
No evidence of this behavior was found in the reviewed package.
nativeMessaging and localhost/private-network host permissions are absent. — manifest.json:23-29
Reviewed first-party services use remote HTTPS API, analytics, error-reporting and messaging destinations. — widget.js.map:1
Does it decode, decrypt, or unpack hidden data and then execute or inject it?
No evidence of this behavior was found in the reviewed package.
src/content/widget/hooks/usePubNub decodes/parses messages and passes them to an explicit type switch. — widget.js.map:1
The only Function constructor match uses fixed build-runtime text, not decoded data. — widget.js:2
Can ordinary websites access privileged extension features through messaging or exposed files?
No evidence of this behavior was found in the reviewed package.
widget.html, an icon, audio and source maps are web-accessible on all URLs; externally_connectable is absent. — manifest.json:42-51
The content script listens to chrome.runtime messages, not page window messages. — content.js.map:1
No first-party MessageEvent/window message receiver accepts commands from the embedding page. — widget.js.map:1
Does suspicious behavior activate only for certain users, websites, dates, or remote settings?
No evidence of this behavior was found in the reviewed package.
src/serviceWorker/storage/slices/general/selectors and src/content/script/index.ts enforce authentication, device-limit, paused-host and visibility gates. — content.js.map:1
PubNub initialization requires account ID, device ID and auth key, then accepts a fixed event allowlist. — widget.js.map:1
Does it perform hidden resource-intensive work, such as cryptocurrency mining?
No evidence of this behavior was found in the reviewed package.
src/content/script/phoneNumbersParser watches page mutations for new phone numbers and stops observation while the page is hidden. — content.js.map:1
Scan completion and contact lookup are debounced and previously processed numbers are not re-sent during the session. — widget.js.map:1
Does it change form fields or where a form sends its information?
No evidence of this behavior was found in the reviewed package.
src/content/script/phoneNumbersParser/lib/domTreeWalker/index.ts excludes textarea, option and contenteditable nodes. — content.js.map:1
HighlightedPhoneNumber and ActionIcon create phone UI elements; no form.action, submit listener or form-value assignment was found. — content.js.map:1