| Title | Tencent WeKnora main SQL Injection |
|---|
| Description | A SQL validation bypass in Tencent WeKnora lets an authenticated user with the lowest role (Viewer) list and read arbitrary files on the server through the data_analysis agent tool, and read documents that belong to other workspaces.
Affected component: internal/utils/inject.go (SQL validator) and internal/agent/tools/data_analysis.go (DuckDB data-analy
sis tool). Affected version: main branch (advisory baseline commit b18ae0f7; re-verified still unfixed at commit 478a652
and later, 2026-09-07). No fixed release exists.
Root cause: validateSubquery in internal/utils/inject.go iterates only FromClause, TargetList, WhereClause, GroupClause and HavingClause and then returns nil. It never inspects Op, Larg or Rarg. For a set-operation (UNION) node the two branches live in Larg and Rarg, so validateSubquery iterates nothing, returns nil, and the guard that rejects a table function in the FROM clause is never reached. In addition, internal/agent/tools/data_analysis.go calls ValidateSQL with WithAllowedTables, WithSingleStatement and WithNoDangerousFunctions, but not WithNoSubqueries (which the sibling database_query.go applies through WithSecurityDefaults). FROM subqueries are therefore allowed and the validator gap is reachable. The table whitelist does not help, because the payload hides the table function inside a UNION branch rather than naming a disallowed table.
Impact:
1. Arbitrary server file read and directory listing. Any file readable by the WeKnora process is returned to the requesting user. read_text is used for text, read_blob for binary, and glob for enumeration.
2. Cross-workspace document disclosure. With the default local storage backend (STORAGE_TYPE=local, LOCAL_STORAGE_BASE_DIR=/data/files) every workspace stores its uploaded documents under one directory tree, so a Viewer in any workspace can enumerate that tree and read every other workspace's documents.
Both require only the Viewer role, which otherwise grants read access to the caller's own knowledge base and nothing else.
Proof of concept (through the data_analysis tool, as a Viewer, on a default docker compose install). T is the internal table name of the caller's own knowledge base, which is disclosed in an error message or in the knowledge-bases API response.
Read an arbitrary file:
SELECT * FROM T, (SELECT CAST(region AS VARCHAR) AS c FROM T UNION ALL SELECT content FROM read_text('/etc/passwd')) x
The contents of /etc/passwd are returned in the response.
List and read other workspaces documents:
SELECT * FROM T, (SELECT CAST(region AS VARCHAR) AS c FROM T UNION ALL SELECT file FROM glob('/data/files/**')) x
SELECT * FROM T, (SELECT CAST(region AS VARCHAR) AS c FROM T UNION ALL SELECT content FROM read_text('/data/files/<other-workspace-file>')) x
Suggested fix: add WithNoSubqueries to the ValidateSQL call in data_analysis.go, and make validateSubquery reject or recurse into Op, Larg and Rarg (and add the missing WithClause, IntoClause and LockingClause checks) so it mirrors validateSelectStmt.
CVSS 3.1 vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N (High, 7.7)
Vendor was contacted through a private GitHub Security Advisory, by email, and through a public discussion request, with no response after more than three weeks. |
|---|
| Source | ⚠️ https://github.com/k4z01/WeKnora-SQL-Validation-Bypass/blob/main/weknora-sql-validation-bypass.md |
|---|
| User | k4z0 (UID 101097) |
|---|
| Submission | 09/08/2026 12:48 (2 months ago) |
|---|
| Moderation | 10/11/2026 12:45 (1 month later) |
|---|
| Status | Accepted |
|---|
| VulDB entry | 416598 [Tencent WeKnora up to 0.8.1 SQL Validator internal/utils/inject.go validateSubquery sql injection] |
|---|
| Points | 20 |
|---|