Last updated: 2026-06-12 (covers v1.7.8)
CL Desk Assistant (“the extension”) does not collect, transmit, sell, share, or store any user data outside the user’s own browser. There is no telemetry, no analytics, no tracking, and no third-party scripts.
New in v1.7.8 (consolidated release — v1.7.7 was an internal-only tag, never published): a security-hardening pass plus two Find / Replace enhancements.
Security hardening (from the June 2026 security audit): (1) the internal messaging bridge between the extension’s content script and the page now rejects messages from any other frame and addresses replies to the page’s own origin only — defense-in-depth; no behavior change. (2) Importing a JSON backup is now atomic (a failed import restores your previous data) and the confirmation dialog states explicitly how much existing data would be replaced or deleted. (3) Smart Refresh refuses to run on ticket pages (in every mode) so it can never discard an unsaved reply or press ticket controls, and full-page mode enforces a 10-second minimum interval. (4) The never-shipped, feature-flagged AI integration (and the third-party AI SDK it referenced) was removed from the codebase entirely — the “no AI SDK is bundled” statement below is now structurally true rather than build-configuration-dependent. (5) The Contact address below changed to a monitored work address.
Find / Replace enhancements, both fully local text transforms over the reply draft already visible in your browser: (1) literal whitespace search — a Find consisting only of spaces (e.g. ten spaces) is now a valid pattern, so runs of spaces can be found and replaced; matches never cross paragraph boundaries. (2) Cleanup (“Tidy draft”) — one-click actions that collapse multiple spaces, remove duplicate blank lines, trim trailing whitespace, remove blank lines at the start/end of the draft, and (opt-in, off by default) remove leading whitespace from paragraphs. Content inside code blocks, preformatted text, and quoted text (blockquotes) is never modified. A single editor undo (Ctrl+Z) reverts the whole cleanup. No network calls, no new permissions, no new hosts, and no draft content is stored or transmitted. One new stored item: your five Cleanup on/off toggles, kept in chrome.storage.sync (key cl.fr_cleanup.v1) — see the storage list below; they are included in JSON backups alongside your other preferences.
New in v1.7.6: the “AI-style symbols / punctuation” built-in Word Alerts detector now flags 9 additional emoji codepoints in addition to the v1.3 baseline typographic tells. The expanded list: — ※ ◆ ◇ ► → ▪ ▫ ✓ ✔ ✅ ⚠ ❌ ℹ 🚀 🤖 💡 📌 🔍 (typographic + the LLM-favored emoji set: white-heavy-check, warning, cross, info, rocket, robot, light-bulb, pushpin, magnifying-glass). The detector remains fully local: pattern matching over the visible text of your reply draft, no network calls, no data sent anywhere. No new data flows vs v1.7.5; no new permissions; no new hosts; no change to what is stored.
New in v1.7.5: bug-fix release. The popup’s Queue Highlights, Word Alerts, Snippets, and Find / Replace tabs each debounce their save-to-chrome.storage by ~250–300 ms while you edit. In v1.7.2–v1.7.4, closing the popup within that debounce window silently dropped the in-flight edit. v1.7.5 adds a flush-on-popup-close path (via the standard pagehide and visibilitychange browser events) so the latest edit is committed to local storage even when the popup is closed quickly. No new data flows, no new permissions, no new hosts, no new network calls; only the timing of an already-promised local-storage write changes.
New in v1.7.4: the “Detect non-public Zendesk article links” detector now uses your existing authenticated Zendesk session (instead of an anonymous request) to read each candidate article’s user_segment_id field — Zendesk’s per-article visibility setting. The detector applies a customer-accessibility rule: articles set to “Visible to everyone” (tier 1) or “Signed-in users” (tier 2) are treated as customer-accessible and NOT flagged; articles set to a restricted segment or to agents-and-admins only are flagged Critical. The request stays on your own Zendesk tenant (or the explicitly allowlisted TuxCare support tenant), uses your existing session cookies (no extra credentials sent, no cookies created), and the response is read in memory only.
To distinguish tier 2 (“Signed-in users”) from tiers 3 and 4 (restricted segments, agents-and-admins), the extension performs one additional authenticated request per Zendesk tenant per browser session against GET /api/v2/help_center/user_segments/applicable.json — the tenant-local endpoint that returns the user segments the currently signed-in user belongs to. The extension reads exactly one integer from the response: the numeric ID of the built-in “Signed-in users” segment (identified by Zendesk’s stable API enums built_in === true and user_type === ‘signed_in_users’). Everything else in the response is read in memory and discarded.
Strict data minimization (locked policy for v1.7.4):
chrome.storage. The classification result is held in memory in the active tab for the lifetime of the current page only; a page reload re-classifies fresh. This is intentional: a Zendesk admin can change an article’s visibility at any moment, and a cached verdict would risk being out of date.chrome.storage.session (key cl.zd_signed_in_user_segments.v1) so the bootstrap call above does not repeat for every article classification. The cache is cleared when the browser quits. This integer is tenant-level metadata (every signed-in user on the tenant resolves the same value); it is not session-specific, not user-specific, not a token.New in v1.7.3: the v1.5 “Detect non-public Zendesk article links” detector and the v1.6 “Copy article reference” button now recognize the TuxCare support Help Center (support.tuxcare.com) in addition to your own Zendesk tenant. The recognized-host list is hardcoded in the build (cloudlinux.zendesk.com and support.tuxcare.com at v1.7.3); other Zendesk Help Center hosts continue to be ignored. The network call to verify TuxCare article visibility uses the same anonymous (credentials: 'omit') Help Center JSON API pattern documented below for CloudLinux articles — no cookies are sent, no third party is contacted, no data leaves your device beyond the request URL itself. The v1.7.3 manifest adds https://support.tuxcare.com/* to host_permissions to allow the anonymous fetch from the background service worker; this is the only permission change in v1.7.3.
v1.7 keeps the same four productivity tools as v1.2 through v1.6, with feature enhancements layered on top rather than new tools. v1.7 itself adds one new built-in Word Alerts detector (the fifth) that flags the distinctive copy-button layout left behind when an agent pastes plain-text content from an internal chatbot UI (CloudLinux’s chatbot-internal, ChatGPT, GitHub Copilot, …): a standalone Copy code or DownloadCopy code line, plus the language label on the preceding line when present (bash, python, powershell, json, …). The match is whole-block exact (the block’s normalized text must equal the artifact, not contain it) so prose like “use bash to run this” or “press Ctrl+C to copy code” does not trip. No network calls, no LLM call — fully local pattern matching. v1.6 added a “Copy article reference” button on public Zendesk Help Center article pages. v1.5 introduced the fourth built-in Word Alerts detector that flags pasted Zendesk Help Center article links the customer cannot actually open. v1.4 added WEBP source-file support to the Snippets image pipeline; v1.3 introduced the first three built-in AI-content detectors. New in vX markers below show which version introduced each piece.
/agent/ and /knowledge/ URL paths), so customer-pasted content, prior ticket comments, and Zendesk’s own UI text never trigger them:
<a href> values inside the composer for the substrings chatgpt.com and utm_source=chatgpt. No external lookup, no LLM call, no network traffic; the match is a plain regex on the href string./knowledge/..., which covers both the legacy /knowledge/articles/<id> editor URL and the newer Knowledge unified-editor /knowledge/editor/<ulid>/<locale> URL), any agent-side URL (/agent/...), and any Help Center admin URL (/hc/admin/...) is flagged synchronously by URL shape alone — no network request, since these paths are agent-only by definition. URLs that match the public Help Center shape /hc/<locale>/articles/<id> additionally require a live unauthenticated HTTPS request to your same Zendesk tenant to decide; see the “Network calls the extension makes” section below for the full description of that request. Cross-tenant *.zendesk.com URLs (a different subdomain than the one the agent is currently composing on) are ignored entirely. No LLM call, no external service.chatbot-internal, ChatGPT, GitHub Copilot, …): a standalone Copy code or DownloadCopy code line, plus the language label on the immediately preceding line when it is one of a fixed list (bash, sh, shell, console, output, terminal, pwsh, powershell, python, js, ts, json, yaml, sql, go, rust, c, cpp, c#, java, kotlin, swift, ruby, php, html, css, xml, dockerfile, nginx, ini, toml, diff, markdown, plaintext, text, and common variants). The match is whole-block exact (the block’s normalized text must equal the artifact, not contain it), so prose like “use bash to run this” or “press Ctrl+C to copy code” does not trip. No external lookup, no LLM call, no network traffic; the match is a plain regex over the block’s normalized text.{{ticket.id}}, {{ticket.subject}}, {{client.name}}, {{client.email}}, {{user.name}}, {{date.today}}), inline images via paste/drop (PNG/JPEG/GIF/WEBP accepted; WEBP and GIF are transcoded in-browser to JPEG or PNG so the output set stays narrow for downstream email-client compatibility; all images downscaled to max 1024 px and compressed in-browser; capped at 256 KB per image, 2 MB per snippet, 8 images per snippet), and a JSON Backup & Restore card in Settings that exports your snippets, word-alert keywords, Find/Replace last-used inputs, and preferences to a local file you save yourself, and re-imports the same shape on demand./agent/filters/), each ticket row whose Assignee column matches a user-configured agent name is highlighted with a subtle left-edge accent stripe. The match is purely local DOM read: the extension walks the visible rows of the view table and compares each row’s Assignee cell text to the configured list of names (case-insensitive, exact). No network call, no LLM call, no external lookup; the configured list and chosen accent color live in chrome.storage.sync alongside the other small settings. If the agent hides the Assignee column from a view, the feature silently does nothing on that view.
All user-configurable data is stored locally in your browser via
chrome.storage
(local for snippet bodies, sync for the smaller settings):
chrome.storage.local on this device only and are not synced across browsers.chrome.storage.session with a one-hour expiry. As of v1.7.4 there is no per-URL verdict cache — every pasted article URL is re-classified by a fresh authenticated request, because an admin can change an article’s visibility at any moment. The only thing now persisted for this detector is a single per-tenant, per-browser-session integer (the built-in “Signed-in users” segment ID, key cl.zd_signed_in_user_segments.v1 in chrome.storage.session); see the v1.7.4 section above.data: URLs — no separate image files are written, and no external image hosts are contacted.chrome.storage.local, per device.cl.fr_cleanup.v1, chrome.storage.sync). Configuration only; no draft content is ever stored. Included in JSON backups alongside your other preferences.The Backup & Restore feature in the Settings tab is user-initiated only. When you click Export, the extension serializes the items above into a JSON file and asks your browser to save it to your local Downloads folder. When you click Import, you select a previously-exported JSON file from your local disk; nothing is uploaded anywhere. Smart Refresh runtime state (running/stopped, tick counter) is deliberately excluded from both export and import as per-device runtime state. Changed in v1.3: Find/Replace last-used inputs are now included in the backup so a new-device restore brings them along.
None of this data leaves your browser. The extension does not connect to any third-party server, does not send anything to the developer, and does not report crashes or usage events.
The extension’s only network calls are to your own Zendesk subdomain’s REST API, using your existing Zendesk session cookies (the same ones your browser already sends to zendesk.com). These calls are made only when a snippet that contains a ticket-, client-, or user-scoped variable is being expanded:
GET /api/v2/users/me.json — agent name, for {{user.name}}.GET /api/v2/tickets/<id>.json — ticket subject, for {{ticket.subject}}.GET /api/v2/users/<requester_id>.json — requester name and email, for {{client.name}} and {{client.email}}.Responses are kept in memory for 30 seconds and then discarded. They are never written to disk, never transmitted elsewhere, and never shared with any third party.
New in v1.5 (superseded by v1.7.4 — see “What v1.7.4 ships” above; this paragraph describes the historical v1.5–v1.7.3 behavior): when the “Detect non-public Zendesk article links”
built-in detector is on (the default), and the agent pastes an article URL into the
reply composer whose shape matches the public Help Center pattern
/hc/<locale>/articles/<id>, the extension’s
background service worker performs one additional HTTPS request to
classify the link:
GET https://<your-tenant>.zendesk.com/api/v2/help_center/articles/<id>.json
— Zendesk’s public Help Center JSON API for the numeric article ID
parsed out of the pasted URL. Locale-agnostic; the API returns the
article’s default-locale visibility verdict. The request is made with
credentials: 'omit', so no Zendesk session cookies,
no authorization headers, and no other credentials are sent. It is what
an anonymous, signed-out browser would receive. The verdict is read from the
HTTP status alone: 200 means the article is visible to anonymous
readers (public); 401, 403, 404,
or any other non-2xx status means Zendesk withheld the article from the
anonymous caller (non-public — covers drafts, agent-only
articles, signed-in-only articles, and user-segment-restricted articles, since
Zendesk’s API returns 404 for any article not visible to the requester
rather than disclosing existence). A network error or 8-second timeout is
classified unknown and the link is left unflagged.
This request is scoped to the same Zendesk tenant the agent is
currently composing on (the originally-pasted URL’s hostname must equal
location.host; cross-tenant *.zendesk.com hostnames
are skipped). Verdicts are cached locally for one hour in
chrome.storage.session so the same URL does not produce repeated
requests, and the cache is cleared when the browser quits. Nothing about the
request, the response, or the classification is transmitted anywhere outside
your browser, and no third party (including the developer) is involved.
New in v1.6: on Zendesk Help Center article pages of the shape
/hc/<locale>/articles/<id>, the extension uses the
same verification call described above to decide whether to mount a small
“Copy article reference” button next to the
article title. The button only appears for articles the verification
classifies as public; restricted articles, drafts, agent/admin URLs
and any URL with a ?preview=… query never receive the
button. Clicking it writes a rich-HTML anchor (the article title as the
visible text, the article URL as the hyperlink target) to your local
clipboard, plus the article URL as plain text for paste targets that
don’t accept rich content. The clipboard write happens entirely in
your browser via the standard navigator.clipboard.write API;
no additional network call is made beyond the verification described
above (which is itself already cached for one hour), no data is
transmitted to the extension developer or any third party.
The extension’s content scripts run on:
https://*.zendesk.com/* — the primary Zendesk Support UI.https://*.cloudlinux.com/* and https://*.zdusercontent.com/*
— only inside iframes that Zendesk embeds within ticket views (CloudLinux Doctor diagnostic
reports linked from tickets, and Zendesk-hosted ticket attachments). Content from these iframes is
inspected only to highlight word-alert keywords and to detect snippet shortcut typing. None of it
is transmitted off-device or stored.
One content script (zendesk-mainworld.js) runs in the page’s main JavaScript world
rather than the extension’s isolated world. This is required to access Zendesk’s
CKEditor 5 reply composer via its model API (the editor ignores DOM mutations from isolated content
scripts). The main-world script communicates with the rest of the extension only via
window.postMessage using a typed protocol; it makes no network requests, never reads
chrome.storage, and imports no third-party libraries.
storage — to persist snippets, word-alert keywords, and settings on this device.offscreen (new in v1.2) — to create a hidden, non-visible extension page used solely to play the optional Word Alerts Critical-match beep through the Web Audio API. The offscreen page is created with the documented AUDIO_PLAYBACK reason, has no DOM-visible UI, makes no network requests, accesses no user data, and exists only to host an oscillator-based two-tone synthesis routine. It is needed because Chrome MV3 content scripts cannot reliably play Web Audio under the autoplay policy.https://*.zendesk.com/* — to inject the productivity tools
onto your Zendesk subdomain and to call the Zendesk REST API for variable resolution.
Cross-domain content-script matches for cloudlinux.com and
zdusercontent.com are declared on individual content scripts to enable iframe
coverage for keyword highlighting and snippet shortcut detection; they are not requested as
broad host permissions, and the extension does not fetch from those origins.<a href> strings, a fixed-glyph character class on composer text, and a count of consecutive empty paragraph-level children in the composer — not calls to any AI service. The fourth built-in detector (introduced in v1.5, non-public Zendesk article links) is a reachability check against your own Zendesk tenant’s Help Center, not an AI call. No prompts are sent to any AI provider. No third-party AI SDK (Anthropic, OpenAI, etc.) is bundled into the production build.
The extension declares a single default keyboard shortcut, Alt+Shift+Z, mapped to
Chrome’s standard _execute_action command to open the popup. You can change or
remove it at any time from
chrome://extensions/shortcuts. No other
keystrokes are captured or recorded.
Issues, questions, or feedback: tali@cloudlinux.com. CloudLinux team members can also use the internal “CL Desk Assistant — Issue & Feedback Collector” page on Slite.