Is Smoothwall Cloud Filter safe?
Smoothwall Cloud Filter is high risk. On every page, Smoothwall Cloud Filter copies the full HTML (up to 256KB), incl. iframes, to its background script every 5 seconds. It backs content-filtering but fires unconditionally, reading email previews into worker memory.
Who publishes itSmoothwall Ltd - no other listings under this identity
Smoothwall Ltd - 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
Full DOM of Every Page Captured Even When Unprovisioned
On every page, Smoothwall Cloud Filter copies the full HTML (up to 256KB), incl. iframes, to its background script every 5 seconds.
It backs content-filtering but fires unconditionally, reading email previews into worker memory.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-200
- Source
- Dynamic sandbox
You load any web page, a webmail thread, an intranet wiki, a Google Doc, a banking dashboard, in a tab or iframe.
The capture also fires inside every embedded iframe on the page, not just the top-level document.
Smoothwall's content script reads the page's rendered HTML and forwards it to its service worker, then re-sends the live DOM every 5 seconds while the tab is open.
It does this even when the extension has no Smoothwall tenant configured; there is no policy gate, no opt-in, and no on-screen indicator that DOM capture is happening.
- The URL of the pagehttps://mail.example.org/mail/u/0/#inbox/FMfcgzGwJVNzPxRBLstqNGZQVnxZRkbV
The exact address of the page or iframe you are looking at, including any query parameters and fragments.
- The full HTML of the page<html lang="en"><head><title>Inbox (3) - alice@example.org</title>...</head><body><div class="thread"><div class="msg" data-from="hr@example.org">Subject: Q3 compensation review – please review attached salary band changes before Friday...</div></div></body></html>
Up to 256,000 chars of the live DOM: visible text, form values, hidden fields, draft emails, wiki content, previews, anything rendered.
- The page titleQ3 Compensation Review – Confidential – Google Docs
The browser tab title, often more revealing than the URL (e.g. 'Inbox (3), alice@example.org').
Every 5 seconds
Once a page finishes loading, the content script immediately sends one DOM snapshot, then keeps sending a fresh snapshot every 5 seconds until the tab is closed or navigates away. Single-page apps (Gmail, Notion, Office 365) therefore stream a continuous timeline of their evolving DOM state.
The DOM-capture loop, exactly as shipped in v3.2.3.
5-second capture interval
// Once readyState is non-'loading', start the periodic capture.// First snapshot is sent immediately; further snapshots fire every 5s.startRepeatedlySendingContentToExtension(intervalMs = 5000) { this.stopRepeatedlySendingContentToExtension(); this.sendContentToExtension(); // initial snapshot this._contentSendInterval = setInterval(() => { this.sendContentToExtension(); // every 5 seconds }, intervalMs);}DOM read + intra-extension send
// Reads up to 256KB of live HTML and posts it to the service worker.// No allow-list / deny-list / tenant check — runs on every page,// in every frame, whether or not the extension has any policy.sendContentToExtension(overrideHtml = null) { try { const html = overrideHtml !== null ? overrideHtml : document.querySelector('html')?.outerHTML.substring(0, 256_000) ?? ''; chrome.runtime.sendMessage( chrome.runtime.id, new PageContentMessage( window.location.href, // exact URL (path + query + fragment) html, // up to 256KB of rendered DOM document.title // tab title ), this.handleMessageFromExtension ); } catch (e) { console.error('Failed to send content to extension'); console.error(e); }}PageContentMessage payload shape
// The exact object that crosses the content-script → service-worker boundary.class PageContentMessage extends Message { constructor(url = '', content = '', title = '') { super(PageContentMessage.type); this.url = url; // window.location.href this.content = content; // outerHTML[0..256000] this.title = title; // document.title }}PageContentMessage.type = 'page-content';Manifest content_scripts entry
// Injects content-script.js into EVERY frame on EVERY origin// at the earliest possible moment (document_start)."content_scripts": [{ "matches": ["*://*/*"], // every http and https URL "js": ["./content-script.js"], "run_at": "document_start", "all_frames": true // also runs inside every iframe}]We loaded the extension into a fresh Chrome profile with **no managed-storage Serial / TenantId** and navigated to five third-party sites (google.com, amazon.com, wikipedia.org, reddit.com, youtube.com).
- The service worker logged `Serial ID is missing from policy` and `No provisioning info found in cache`. - Despite that, **20 `Page content received from tab X, frame N` log entries** were emitted by `FilterController._onPageContentMessageReceived` across the five navigations. - Frames `0, 7, 8, 9, 11, 12, 13, 16` all participated, confirming `all_frames: true` is honoured. - `Re-scanning URL for tab X` entries interleaved, confirming the captured outerHTML was being driven into the URL re-scan pipeline.
In other words: the DOM capture is **not** gated on the extension being provisioned for an organisation. Every installed user — including individuals who may have installed the extension by mistake or evaluators looking at the listing — has their full page DOM read out and shipped to the service worker on every page, in every frame, every 5 seconds.
Run this in the Smoothwall service-worker DevTools console to log every 'page-content' message Smoothwall receives, including the originating tab, frame, URL, title, and a length + first-200-character preview of the captured HTML. Lets you verify on your own machine that the DOM is being read on every page, in every frame, every 5 seconds, even when no Smoothwall policy is configured.
- Chrome 110+ with Developer mode enabled in chrome://extensions
- Smoothwall Cloud Filter installed (any version 3.2.x)
- Permission to open the extension's service-worker DevTools
// smoothwall-page-content-tap.js// Paste into the DevTools console of Smoothwall's service worker:// chrome://extensions → enable Developer mode → find// 'Smoothwall Cloud Filter' → click 'service worker' link.//// It wraps chrome.runtime.onMessage so any 'page-content' message// the extension receives is logged with sender + payload preview.(function () { const tag = '[smoothwall-tap]'; if (globalThis.__smoothwallTapInstalled) { console.warn(tag, 'already installed'); return; } globalThis.__smoothwallTapInstalled = true; let count = 0; chrome.runtime.onMessage.addListener((msg, sender) => { if (!msg || msg.type !== 'page-content') return; // ignore non-DOM messages count += 1; const html = typeof msg.content === 'string' ? msg.content : ''; console.log( tag, `#${count}`, `tab=${sender.tab && sender.tab.id}`, `frame=${sender.frameId}`, `url=${msg.url}`, `title=${JSON.stringify(msg.title)}`, `htmlBytes=${html.length}`, `preview=${JSON.stringify(html.slice(0, 200))}` ); // Returning nothing — we are observing, not blocking. }); console.log(tag, 'installed. Open or reload any tab and watch this console.');})();- 1Open chrome://extensions, enable Developer mode.
- 2Open 'service worker' DevTools for Smoothwall.
- 3Paste script into Console.
- 4Visit sites.
- 5See one entry per load, one per 5s.
- 6Repeat unenrolled; captures still appear.
- (stays inside the extension)
The DOM payload goes to Smoothwall's worker via sendMessage, for filtering. Not exfiltrated on its face, but worker code can read it; a bug could expose every page DOM rendered.