Is Tandem Health safe?
We analyzed Tandem Health version 1.82.3's actual code and gave it a 62/100 trust score. Tandem Health fits its stated note-transfer purpose but combines…
Bottom line
Tandem Health fits its stated note-transfer purpose but combines broad medical-page access with a meaningful local-control weakness.
What it can access
The extension can run across websites and read or change medical-record pages, including clinical notes and patient-related fields. [Q1] [Q2] It handles sensitive medical information for its stated transfer feature, but the reach is broad. [Q3] [Q4]
Security weaknesses
A local program controlling the extension’s local connection could send valid commands that edit an authorized medical-record page. [Q19] The privileged bridge is limited to named websites and includes origin and message checks, which reduce but do not remove the risk. [Q21] [Q16]
Signs of misuse
The extension sends selected medical-record data, transfer results, and diagnostic information to Tandem or its local companion as part of the stated workflow. [Q6] It also records an instance ID and device details, but no unrelated collection or browser-session theft was established. [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-sites page access and can request scripting plus all-site host access, although those website access are optional and requested through Chrome's consent UI.
Declares tabs and webNavigation, optional scripting and <all_urls>, and an all-frames content script matched to <all_urls>. — manifest.json:18-81
Calls permissions.request only after the user presses Continue in a dedicated permission window. — chunks/grant-permission-DcJ1oFVR.js:1
Which websites can it run on, and can it read or change what appears on those pages?
It reads and edits medical-record page content to locate fields, preserve existing values, insert notes, choose codes, and operate record-system controls.
Contains adapters for many medical-record systems that query page elements and write structured note content into inputs, editors, and selectors. — content-scripts/content.js:113,663
Can it see sensitive information you type, such as passwords, payment details, messages, or form entries?
It handles clinical notes, patient names, encounter identifiers, diagnoses, and medical codes as part of the advertised transfer workflow.
Defines structured medical-note payloads and record-system adapters that insert headings, note text, codes, dates, and patient-related data. — content-scripts/content.js:115,663
Routes validated copy_content and retrieve_codes messages between Tandem and selected medical-record tabs. — background.js: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.
Requests alarms, tabs, and webNavigation, but not history, bookmarks, passwords, or autofill permissions. — manifest.json:12-21
Can it access anything else on your device, such as files, location, camera, microphone, clipboard, or installed applications?
No evidence of this behavior was found in the reviewed package.
Does not request media capture, downloads, clipboardRead, desktopCapture, or filesystem permissions. — manifest.json:12-21
Does it send information outside your browser? If so, what information is sent, where does it go, and why?
It returns selected medical-record data, transfer results, and diagnostic logs to the Tandem web app or local Tandem service; these destinations are part of the product workflow.
Relays retrieval results and batched logs to the selected Tandem tab or localhost WebSocket. — background.js:1
Collects requested codes and patient name from supported record systems and sends a structured retrieval_result to Tandem. — content-scripts/content.js:115,663
Does it download or run code, settings, or instructions supplied by a remote server?
Tandem can remotely supply the supported record-system URL configuration, but each new origin still requires browser-granted host access.
UPDATE_EXTENSION_CONFIG replaces the in-memory EMR URL list; missing permissions trigger the explicit grant flow. — background.js:1
Shows the permission UI and requests the supplied record-system origins only after Continue is clicked. — chunks/grant-permission-DcJ1oFVR.js:1
Can it take actions without a clear user request, such as opening pages, redirecting searches, downloading files, or sending requests?
It automatically maintains a localhost connection, heartbeats, tab/frame discovery, and diagnostic logging, but note transfers require a validated instruction.
Reconnects to ws://localhost:15435 on an alarm and watches navigation to initialize configured record-system frames. — background.js:1
Sends a periodic heartbeat from the top frame and batches diagnostic logs. — content-scripts/content.js:663
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.
Requests no settings, proxy, declarativeNetRequest, or webRequest permission. — manifest.json:12-21
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.
Bundled product logic remains structurally readable and names its message types, medical-record adapters, and safeguards. — content-scripts/content.js:1-663
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.
Processes remote messages as schema-validated data rather than executable code. — background.js:1
Uses packaged adapters and event hooks; no dynamic-code execution sink was found. — content-scripts/content.js:1-663
Does it track the websites, pages, searches, or links you visit?
No evidence of this behavior was found in the reviewed package.
Uses tabs.query, tabs.get, and webNavigation to find configured origins and route transfers to the correct tab and frame. — background.js:1
Does it create a persistent ID or browser fingerprint to recognize you?
Diagnostic context includes a generated instance ID, extension version, browser version, platform, and install type, which can help correlate a session.
The logger creates a random instance ID and records browser, platform, extension, and install metadata before relaying logs to Tandem. — background.js:1
Does it send cookies, session details, authentication data, or page contents elsewhere?
No evidence of this behavior was found in the reviewed package.
Does not request cookies or webRequest permissions. — manifest.json:12-21
Does it record typing, form entries, clipboard contents, or screenshots?
It programmatically edits medical forms and rich-text editors, but no keystroke logging or unrelated form harvesting was found.
Writes note values, selects options, clicks controls, and dispatches input/change events in supported record systems. — content-scripts/content.js:113,663
Packaged main-world hook appends validated note text to CKEditor instances. — ckeditor-inject-hook.js:1
Can a website or remote server send commands that make the extension take actions?
The Tandem app can instruct the extension to paste server-supplied note content into an authorized record-system page, but exact-origin checks, schemas, user-granted site access, and transfer checks constrain it.
Accepts copy_content only from exact Tandem/Juvoly origins, validates its structure, and routes PASTE_CONTENT to packaged adapters. — content-scripts/content.js:115,663
Checks sender origin and payload schema, refuses ambiguous tab selection, and invokes the permission flow when target access is missing. — background.js:1
Avoids overwriting populated fields in multiple adapters and includes a patient-AI-consent check for a supported workflow. — content-scripts/content.js:268,663
Does it alter links, referral codes, advertisements, shopping carts, or search results?
No evidence of this behavior was found in the reviewed package.
Implements many named record-system adapters that manipulate form and editor state. — content-scripts/content.js:113,663
Does it redirect or modify web traffic, request headers, downloads, or proxy settings?
No evidence of this behavior was found in the reviewed package.
Requests neither downloads, proxy, webRequest, nor declarativeNetRequest. — manifest.json:12-21
Can it communicate with software on the computer or services running on localhost?
It accepts transfer instructions from a localhost Tandem service without an application-level token; a hostile local process controlling that port could issue valid page-editing commands.
Automatically connects to ws://localhost:15435/?tandem=true and passes schema-valid messages to the same privileged handler used for Tandem web messages. — background.js: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.
Accepts validated COPY_CONTENT and UPDATE_EXTENSION_CONFIG data from Tandem and routes it to packaged code. — background.js:1
Uses remote note data as values for predefined record-system adapters, not as code. — content-scripts/content.js:663
Can ordinary websites access privileged extension features through messaging or exposed files?
It provides a privileged page-to-extension bridge, but restricts callers to exact Tandem/Juvoly origins, checks event.source, and validates every accepted message schema.
Externally connectable pages are limited to app.tandemhealth.ai, tandem.juvoly.nl, and app.juvoly.nl. — manifest.json:68-74
The window-message bridge requires event.source === window and an exact allowlisted origin before forwarding schema-valid messages. — content-scripts/content.js:115,663
onMessageExternal repeats the exact-origin check and schema validation. — background.js: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.
Stores EMR URL patterns from UPDATE_EXTENSION_CONFIG and requests missing scripting/origin permissions before injection. — background.js:1
Requires the user to press Continue before Chrome displays and processes the requested origins. — chunks/grant-permission-DcJ1oFVR.js:1
Does it perform hidden resource-intensive work, such as cryptocurrency mining?
No evidence of this behavior was found in the reviewed package.
Background work is limited to message routing, tab discovery, logging, permission handling, and local-service keepalive. — background.js:1
Does it change form fields or where a form sends its information?
It deliberately edits medical form inputs, selectors, and rich-text editors, but no code redirects form actions or sends values to an unrelated destination.
Writes structured Tandem note values into matching record fields and triggers the page's normal input, change, blur, click, and save behavior. — content-scripts/content.js:113,663
Validates editor identifiers and expected current text before appending content through TinyMCE. — tinymce-inject-hook.js:1