6 min read

LobeHub: A Self-Hosted Workspace for AI Agents (GitHub, Scanned)

A polished, self-hostable workspace for chatting with and scheduling AI agents across dozens of model providers.

LobeHub logo
✅
Scan: safe. Nothing malicious. Know the licence before building a product on it, and if you deploy the Grafana variant of the production Compose files, replace the login server's signing key it ships with. Scanned Sep 27, 2026; the full report is below.

LobeHub began as LobeChat, one of the best-looking ChatGPT-style interfaces on GitHub, and has grown into a workspace for agents. You build an agent by describing it, give it skills and MCP plugins from a library of more than 10,000, put several in a group to work on one task, schedule runs, and let them keep a structured, editable memory of how you work. It connects to OpenAI, Anthropic, Google and dozens of other providers, Ollama included, and the desktop app can drive coding agents such as Claude Code and Codex installed on your machine.

It is a Next.js and TypeScript code base of about 2.5 million lines (plus three million lines of JSON), built by LobeHub LLC with 357 contributors and 818 releases so far. You can use the hosted version at app.lobehub.com or self-host it with Docker. The licence is the LobeHub Community License: Apache-2.0 plus a condition that developing and distributing a derivative work needs a commercial licence.

  • Repository: github.com/lobehub/lobehub
  • Licence: custom (Other)
  • Language: TypeScript. Stars: 82.8K. Forks: 15.9K. Last push: Sep 27, 2026.
  • Scan: safe, Sep 27, 2026, commit 413ec82

Who it is for

Individuals and teams who want one good-looking interface for many model providers, people building multi-agent workflows without writing code, and self-hosters comfortable running a Postgres-backed Docker stack.

Getting started

1. Create a folder for the deployment

mkdir lobehub-db && cd lobehub-db

2. Run the setup script, which downloads the Compose file and writes a .env with generated keys

bash <(curl -fsSL https://lobe.li/setup.sh)

3. Start the stack

docker compose up -d

The short link redirects to docker-compose/setup.sh in the repository, 863 lines, which is run as is. It downloads the Compose file, SearXNG settings and an .env template from the project's GitHub and generates secrets such as the JWKS key; the only sudo in it is a printed hint about Docker group membership.

Safety scan

We cloned lobehub/lobehub at commit 413ec82 on Sep 27, 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.

  • Five secret hits, none a leak: two test keys in unit tests and two example AWS keys in the environment-variable docs. The fifth deserves a note: docker-compose/production/grafana/init_data.json seeds Casdoor, the login server in that variant of the stack, with a fixed RSA private key for signing tokens. Anyone deploying it unchanged shares a signing key with everyone else who did, so generate a new certificate first. The default setup script uses a different Compose file without Casdoor.
  • 17 pattern hits. Thirteen are curl | sh install commands for third-party coding agents (Amp, Claude Code, Cursor, Devin, Factory, Kimi, OpenCode, Qoder, xAI) and for Ollama, in the table the desktop app displays as install instructions when a tool is missing, and in its tests. The other four are three long prompt or generated files and a Telegram webhook test.
  • Install hooks: the desktop app's postinstall rebuilds Electron native modules, a macOS notifications package compiles its native addon on install, and the root prepare script points Git at the repository's hooks. The two binaries are epub test fixtures, and the seven bare-IP URLs are tests for the filter that recognizes private addresses.
  • The main app's pnpm lockfile is git-ignored, so the advisory check only covered the desktop app's lockfile: one critical (tar 6.2.1, a build-time archive library) and 54 high, mostly in XML and URL parsing libraries. The web app's resolved dependency versions cannot be checked from the repository.
  • 32 workflows. Two use pull_request_target (release tagging and pull request assignment) and neither checks out the pull request; none of the 37 third-party actions is pinned to a commit. Renovate, a security policy and a code of conduct are present.

What the scanner counted

CheckResult
Secrets5 candidates found and read; see the notes above.
Suspicious code17 pattern hits found and read; every one is listed under the raw findings.
Install-time code3 npm lifecycle scripts. 10 installer scripts (one can call sudo)
Committed binaries2 executable or compiled objects committed; listed under the raw findings.
CI workflows32 workflows. 2 use pull_request_target, none check out the pull request head. 37 of 37 third-party actions pinned to a tag rather than a commit.
Network hosts40 distinct hosts referenced from source; most often github.com, app.lobehub.com, cdn.example.com, lobehub.com. 7 URLs to a bare IP address, listed under the raw findings.
Known vulnerabilities88 advisories across 1,876 pinned packages: 1 critical, 54 high, 31 moderate, 2 low. apps/desktop/pnpm-lock.yaml: 1,876 packages, 88 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 (5, redacted)
WhereRuleMatch
apps/server/src/modules/ModelRuntime/index.test.ts:708private-key-----B…--- (27 chars)
docker-compose/production/grafana/init_data.json:592private-key-----B…--- (31 chars)
docs/self-hosting/environment-variables/model-provider.mdx:218aws-access-keyAKIA5S…WBR (20 chars)
docs/self-hosting/environment-variables/model-provider.zh-CN.mdx:216aws-access-keyAKIA5S…WBR (20 chars)
packages/env/src/__tests__/scm.test.ts:5private-key-----B…--- (31 chars)
Pattern hits (17)
WhereRuleMatch
apps/server/src/services/bot/platforms/telegram/helpers.test.ts:82exfil-hostexpect(url).toBe(`https://api.telegram.org/bot${BOT_TOKEN}/setWebhook`);
packages/builtin-skills/src/lobehub/manifest.ts:7very-long-line6978 chars
packages/heterogeneous-agents/src/config.test.ts:55download-piped-to-shellinstall: { commands: ['curl https://cursor.com/install -fsS | bash'] },
packages/heterogeneous-agents/src/config.test.ts:64download-piped-to-shell'curl -fsSL https://app.factory.ai/cli | sh',
packages/prompts/src/chains/goalManager.ts:23very-long-line3928 chars
packages/sdk/src/generated/sdk.gen.ts:5very-long-line11514 chars
packages/types/src/agent/heterogeneousAgent.ts:68download-piped-to-shell'curl -fsSL https://ampcode.com/install.sh | bash',
packages/types/src/agent/heterogeneousAgent.ts:97download-piped-to-shell'curl -fsSL https://claude.ai/install.sh | bash',
packages/types/src/agent/heterogeneousAgent.ts:171download-piped-to-shellcommands: ['curl https://cursor.com/install -fsS | bash'],
packages/types/src/agent/heterogeneousAgent.ts:199download-piped-to-shell'curl -fsSL https://app.factory.ai/cli | sh',
packages/types/src/agent/heterogeneousAgent.ts:228download-piped-to-shell'curl -fsSL https://cli.devin.ai/install.sh | bash',
packages/types/src/agent/heterogeneousAgent.ts:258download-piped-to-shell'curl -fsSL https://x.ai/cli/install.sh | bash',
packages/types/src/agent/heterogeneousAgent.ts:282download-piped-to-shell'curl -fsSL https://code.kimi.com/kimi-code/install.sh | bash',
packages/types/src/agent/heterogeneousAgent.ts:310download-piped-to-shellcommands: ['curl -fsSL https://opencode.ai/install | bash'],
packages/types/src/agent/heterogeneousAgent.ts:356download-piped-to-shell'curl -fsSL https://qoder.com/install | bash',
src/components/OllamaSetupGuide/index.tsx:158download-piped-to-shellcurl -fsSL https://ollama.com/install.sh | sh
src/store/chat/slices/agentRun/actions/__tests__/heterogeneousAgentExecutor.test.ts:2232download-piped-to-shell (test/example)installCommands: ['curl -fsSL https://claude.ai/install.sh | bash'],
URLs to bare IP addresses (7)
WhereRuleMatch
packages/utils/src/url.test.ts:247ip-literal-urlexpect(isLocalOrPrivateUrl('http://172.15.0.1')).toBe(false);
packages/utils/src/url.test.ts:248ip-literal-urlexpect(isLocalOrPrivateUrl('http://172.32.0.1')).toBe(false);
packages/utils/src/url.test.ts:260ip-literal-urlexpect(isLocalOrPrivateUrl('http://8.8.8.8')).toBe(false);
packages/utils/src/url.test.ts:261ip-literal-urlexpect(isLocalOrPrivateUrl('http://1.1.1.1')).toBe(false);
packages/utils/src/url.test.ts:262ip-literal-urlexpect(isLocalOrPrivateUrl('http://192.167.1.1')).toBe(false);
packages/utils/src/url.test.ts:263ip-literal-urlexpect(isLocalOrPrivateUrl('http://192.169.1.1')).toBe(false);
packages/utils/src/url.test.ts:289ip-literal-urlexpect(isLocalOrPrivateUrl('http://256.256.256.256')).toBe(false);
npm lifecycle scripts (3)
  • apps/desktop/package.json postinstall: electron-builder install-app-deps
  • package.json prepare: git rev-parse --git-dir > /dev/null 2>&1 && git config core.hooksPath .githooks || true
  • packages/electron-mac-notifications/package.json install: node scripts/build-native.mjs
Installer scripts (10)
Committed binaries (2)
  • packages/file-loaders/test/fixtures/test.epub: JAR, 4 KB
  • src/libs/document-loaders/loaders/epub/__tests__/demo.epub: JAR, 4 KB
Worst known vulnerabilities (24 of 88)
AdvisorySeverityPackageSummary
GHSA-23hp-3jrh-7fpwcriticaltar@6.2.1node-tar: Decompression/parse DoS via unlimited input
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-mh99-v99m-4gvghighbrace-expansion@1.1.16brace-expansion: DoS via unbounded expansion length causing an out-of-memory process crash
GHSA-rgw5-rvv9-x895highbrace-expansion@1.1.16brace-expansion: DoS via unbounded intermediate arrays, bypassing the CVE-2026-14257 mitigation
GHSA-mh99-v99m-4gvghighbrace-expansion@2.1.2brace-expansion: DoS via unbounded expansion length causing an out-of-memory process crash
GHSA-rgw5-rvv9-x895highbrace-expansion@2.1.2brace-expansion: DoS via unbounded intermediate arrays, bypassing the CVE-2026-14257 mitigation
Workflows worth a look

By the numbers

Stars82.8K
Forks15.9K
Contributors357
Commits14.1K
Open issues372
Open pull requests117
Releases818
Latest releasev2.2.18
Licencecustom
Main languageTypeScript
Project age3 years
Last pushSep 27, 2026
Tracked files17,495
Lines of code6M
Checkout size241 MB

Lines by language: JSON 3.2M, TypeScript 2.5M, Markdown 167.7K, YAML 34.8K, JavaScript 13K, Shell 8,283.

Questions

Is LobeHub free?

The self-hosted version is free to run, including commercially as a service, under the LobeHub Community License. What the licence restricts is developing and distributing a derivative work based on it, which needs a commercial licence from LobeHub LLC. The hosted version at app.lobehub.com is a separate service run by LobeHub, and model usage is billed by whichever providers you connect.

Can LobeHub use local models?

Yes. Ollama is a built-in provider with its own setup guide in the app, and an OpenAI-compatible server such as vLLM, LocalAI or llama.cpp's can be used by overriding the OpenAI base URL. Hosted providers need your own API keys. Note that the README's API key section recommends a third-party OpenAI reseller through a referral link; a reseller sees every prompt you send through it.

LobeHub or Open WebUI?

Both are self-hosted chat front ends for many providers. Open WebUI is the usual choice in front of Ollama, with document search and a Python plugin system, and installs as one container. LobeHub leans toward hosted providers and agents, with groups, schedules, memory and a skills library in a more designed interface, but its Docker stack needs Postgres and object storage. Check both licences before rebranding either.


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.