Is Distill safe?
Distill shares LinkedIn session cookies and profile page HTML with Distill services.
Distill lets its own web pages request LinkedIn session cookies through the extension, including sending the LinkedIn li_at cookie in an onboarding URL. On LinkedIn profile and company pages, it can automatically send the page URL and full HTML to Distill after checking whether the page is already known. Distill pages can also request an Outlook LokiAuthToken from an open Outlook or Office tab when the extension has access to that tab.
Who publishes itDistill Tech - no other listings under this identity
Distill Tech - no other listings under this identity
What this publisher told the store about itself, and the other listings that told it the same thing.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Distill pages can receive LinkedIn session cookies
Code analysis shows a permitted Distill page can ask the extension for a cookie check.
The service worker reads the LinkedIn session cookie and related cookies and returns them.
Onboarding also places the session cookie in a Distill URL.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-522
- Source
- Dynamic sandbox
You use Distill onboarding or a permitted Distill web page.
The extension reads LinkedIn session cookies and returns them to that page.
The onboarding path also places the session cookie into a Distill URL query string.
- LinkedIn session tokenli_at=AQEDAVi2U3nL5y4HAAABl9JdW2Y (illustrative)
Lets the receiving page identify the active LinkedIn session if LinkedIn accepts the cookie.
- LinkedIn remember-me cookieli_rm=AQH7Gm2b9XrQ4sP1 (illustrative)
Adds another LinkedIn cookie value tied to the browser profile.
- LinkedIn auxiliary cookieli_a=AQJ9p3KxT7rV2mN6 (illustrative)
Adds more account-session context from the LinkedIn cookie jar.
The code navigates a tab to this URL. No request body was recorded for this GET navigation.
- distill.com
Allowed to send external messages; also the default onboarding destination for the session-cookie query string.
- distill.fyi
Allowed to send external messages that reach the cookie-check handler.
The shipped service worker reads LinkedIn cookies and returns them to Distill pages
Manifest allows Distill web pages to message the extension
manifest.json"externally_connectable": { "matches": [ "https://distill.com/*", "https://distill.fyi/*" ]}Cookie readers and onboarding URL builder
js/background.jsconst LINKEDIN_A_COOKIE = "li_a";async function readLinkedInCookie(name) { const cookies = await chrome.cookies.getAll({ domain: "linkedin.com", name }); const newest = cookies.sort((left, right) => (right.expirationDate || 0) - (left.expirationDate || 0))[0]; return newest?.value;}function readLinkedInSessionCookie() { return new Promise((resolve) => { chrome.storage.sync.get(storage.li_at, (stored) => { const previous = stored[storage.li_at]; chrome.cookies.getAll({ domain: "linkedin.com", name: "li_at" }).then((cookies) => { if (!cookies.length) { resolve(null); return; } const cookie = cookies.sort((left, right) => (right.expirationDate || 0) - (left.expirationDate || 0))[0].value; if (cookie === previous) { resolve({ cookie, changed: false }); return; } chrome.storage.sync.set({ [storage.li_at]: cookie }); resolve({ cookie, changed: true }); }); }); });}async function openOnboarding(clearNoCookieFlag) { const linkedInSession = await readLinkedInSessionCookie(); if (linkedInSession) { if (clearNoCookieFlag) chrome.storage.sync.set({ [storage.no_cookie_onboarding]: false }); const params = new URLSearchParams({ li_at: linkedInSession.cookie }); navigateActiveTab(apiHost + "/onboarding?" + params.toString()); } else { chrome.storage.sync.set({ [storage.no_cookie_onboarding]: true }); navigateActiveTab(apiHost + "/onboarding?li_at=none"); }}External cookieCheck handler returns cookie values
js/background.jschrome.runtime.onMessageExternal.addListener((message, sender, sendResponse) => { const acceptedKeys = ["cookieCheck", "cookieSet", "onboarding", "message", "url", "ovr", storage.token, storage.user]; if (typeof message !== "object" || !message || !acceptedKeys.some((key) => key in message)) return; chrome.storage.sync.get([storage.token, storage.user, storage.li_at, storage.no_cookie_onboarding]).then((stored) => { if (message.ovr) apiHost = message.ovr; if (message.cookieCheck) { readLinkedInSessionCookie() .then(async (sessionCookie) => { const [li_rm, li_a] = await Promise.all([ readLinkedInCookie("li_rm"), readLinkedInCookie("li_a") ]); sendResponse({ ...sessionCookie, li_rm, li_a }); }) .catch((error) => sendResponse({ cookie: null, error: String(error) })); return; } if (message.onboarding) { openOnboarding(); sendResponse({ success: true }); return; } if (message.url && !stored[storage.li_at] && stored[storage.no_cookie_onboarding] && message.url.includes("linkedin.com")) { openOnboarding(true); sendResponse({ success: true, message: "URL processed" }); return; } sendResponse({ success: true }); }).catch((error) => sendResponse({ success: false, error: String(error) })); return true;});Distill pages can request an Outlook session token
Code analysis shows a permitted Distill page can ask the extension for an Outlook token.
If an Outlook or Office tab is open and injectable, the service worker reads the page token from storage and returns it to that Distill page.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-522
- Source
- Dynamic sandbox
You have Outlook or Office open while using a permitted Distill web page.
The extension can read Outlook session storage and return the token to that page.
This path depends on the extension having injection access to the Outlook or Office tab.
- Outlook session tokenLokiAuthToken=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1cG4iOiJhbGV4QGV4YW1wbGUuY29tIiwiaWF0IjoxNzIwMDAwMDAwfQ.v9j4GmXk2f8qzP0n5bY3S7mQ1rLdA6hTcNwE2pUaKc8 (illustrative)
Lets the receiving page obtain a token associated with the active Outlook or Office browser session.
- Browser storage sourceLokiAuthToken in session storage (illustrative)
Shows that the value comes from storage inside the open Outlook or Office page.
- Matched tabhttps://outlook.live.com/mail/0/ (illustrative)
Limits the read to open Microsoft webmail or Office pages found in your browser.
same message callback
You didA permitted Distill page sends an Outlook-token request to the extension.
The extension didThe service worker searches open tabs for Outlook or Office and reads session storage.
If a token string is found, it is returned to the requesting page.
- distill.com
- distill.fyi
Allowed to send external messages that can request the Outlook token.
- outlook.live.com
- office.com
A matching open tab whose session storage is read when injection access is available.
The shipped service worker reads the Outlook token from open Outlook or Office tabs
Manifest allows Distill web pages and declares scripting access
manifest.json"permissions": [ "activeTab", "storage", "scripting", "cookies"],"optional_host_permissions": [ "*://*/*"],"externally_connectable": { "matches": [ "https://distill.com/*", "https://distill.fyi/*" ]}Readable equivalent of the Outlook-token branch
js/background.jschrome.runtime.onMessageExternal.addListener((message, sender, sendResponse) => { if (message.getOutlookLokiToken) { chrome.tabs.query({}, (tabs) => { const outlookTab = tabs.find((tab) => { const url = tab.url || ""; return url.includes("outlook.live.com") || url.includes(".office.com"); }); if (!outlookTab || !outlookTab.id) { sendResponse({ outlookLokiToken: null }); return; } chrome.scripting.executeScript({ target: { tabId: outlookTab.id }, world: "MAIN", func: () => { try { return window.sessionStorage ? window.sessionStorage.getItem("LokiAuthToken") : null; } catch (error) { return null; } } }, (results) => { if (chrome.runtime.lastError) { sendResponse({ outlookLokiToken: null }); return; } const result = results && results[0] && results[0].result; sendResponse({ outlookLokiToken: typeof result === "string" ? result : null }); }); }); return true; }});Where it sends data
Destinations our analysis observed Distill contacting. Sending data somewhere is not a finding on its own - an extension that syncs your settings has to talk to its own server - but it is where your data can go, and who else it goes to.
- distill.com
Distill sends data to distill.com. No other extension we have analysed sends data here.
- distill.fyi
Distill sends data to distill.fyi. No other extension we have analysed sends data here.