GHSA-j7wh-x834-p3r7: SiYuan: Authorization Bypass Allows Arbitrary SQL Execution via Search API
SummarySiYuan Note v3.6.0 (and likely prior versions) contains an authorization bypass vulnerability in the `/api/search/fullTextSearchBlock` endpoint. When the `method` parameter is set to `2`, the endpoint passes user-supplied input directly as a raw SQL statement to the underlying SQLite database without any authorization or read-only checks. This allows any authenticated user — including those with the `Reader` role — to execute arbitrary SQL statements (SELECT, DELETE, UPDATE, DROP TABLE, etc.) against the application's database.This is inconsistent with the application's own security model: the dedicated SQL endpoint (`/api/query/sql`) correctly requires both `CheckAdminRole` and `CheckReadonly` middleware, but the search endpoint bypasses these controls entirely.Root Cause AnalysisThe Vulnerable Endpoint**File:** `kernel/api/router.go`, line 188This endpoint only applies `model.CheckAuth`, which permits **any** authenticated role (Administrator, Editor, or Reader).The Properly Protected Endpoint (for comparison)**File:** `kernel/api/router.go`, line 177This endpoint correctly chains `CheckAdminRole` and `CheckReadonly`, restricting SQL execution to administrators in read-write mode.The Vulnerable Code Path**File:** `kernel/api/search.go`, lines 389-411**File:** `kernel/model/search.go`, lines 1205-1206When `method=2`, the raw `query` string is passed directly to `searchBySQL()`.**File:** `kernel/model/search.go`, lines 1460-1462**File:** `kernel/sql/block_query.go`, lines 566-569, 713-714**File:** `kernel/sql/database.go`, lines 1327-1337Go's `database/sql` `db.Query()` will execute any SQL statement, including `DELETE`, `UPDATE`, `DROP TABLE`, `INSERT`, etc. The returned `*sql.Rows` will simply be empty for non-SELECT statements, but the destructive operation is still executed.Authorization Model**File:** `kernel/model/session.go`, lines 201-210**File:** `kernel/model/session.go`, lines 380-386Proof of ConceptPrerequisitesSiYuan instance accessible over the network (e.g., Docker deployment)Valid authentication as any user role (including `Reader`)Steps to ReproduceAuthenticate to SiYuan and obtain a valid session cookie or API token.**Read all data (confidentiality breach):****Delete all blocks (integrity/availability breach):****Drop tables (availability breach):****Compare with the properly protected endpoint** (should return HTTP 403 for Reader role):Expected BehaviorThe search endpoint should reject SQL execution for non-admin users, or at minimum enforce read-only access, consistent with `/api/query/sql`.Actual BehaviorAny authenticated user (including Reader role) can execute arbitrary SQL including destructive operations.ImpactIn a multi-user deployment (e.g., Docker with published access, or any network-accessible instance with access authorization code):**Confidentiality:** A Reader-role user can read all data in the SQLite database, including blocks, assets, references, and configuration data they should not have access to.**Integrity:** A Reader-role user can modify or delete any data in the database, despite having read-only access by design.**Availability:** A Reader-role user can drop tables or corrupt the database, rendering the application unusable.Suggested FixAdd `CheckAdminRole` and `CheckReadonly` middleware to the search endpoint, or add explicit validation that only SELECT statements are accepted when `method=2`:**Option A — Restrict method=2 to admin (recommended):**In `kernel/api/search.go`, add a role check when `method=2`:**Option B — Enforce SELECT-only for non-admin users:**Validate the parsed SQL to ensure only SELECT statements are executed when the user is not an administrator.
CVSS v3.1: 9.8