GCVE Workshop - 22 September 2026 (14:00-18:00), Luxembourg Before The Vulnopticon Conference - Registration

GHSA-HJH7-R5W8-5872

Vulnerability from github – Published: 2026-04-22 20:51 – Updated: 2026-04-27 16:34
VLAI
Summary
SiYuan: Path Traversal via Double URL Encoding in `/export/` Endpoint (Incomplete Fix Bypass for CVE-2026-30869)
Details

Summary

The fix for CVE-2026-30869 in SiYuan v3.5.10 only added a denylist check (IsSensitivePath) but did not address the root cause — a redundant url.PathUnescape() call in serveExport(). An authenticated attacker can use double URL encoding (%252e%252e) to traverse directories and read arbitrary workspace files including the full SQLite database (siyuan.db), kernel log, and all user documents.

Details

In kernel/server/serve.go, the serveExport() function (line 314-320) processes file paths as follows:

filePath := strings.TrimPrefix(c.Request.URL.Path, "/export/")
decodedPath, err := url.PathUnescape(filePath)     // second decode
fullPath := filepath.Join(exportBaseDir, decodedPath)

Go's HTTP server already decodes percent-encoded characters once during request parsing. The additional url.PathUnescape() call creates a double-decode vulnerability:

  1. Attacker sends: GET /export/%252e%252e/siyuan.db
  2. Go HTTP decodes %25%, result: URL.Path = /export/%2e%2e/siyuan.db
  3. Go's path cleaner sees %2e%2e as literal characters (not ..), no redirect occurs
  4. url.PathUnescape("%2e%2e") decodes to ..
  5. filepath.Join(exportBaseDir, "../siyuan.db") resolves to <workspace>/temp/siyuan.db

The CVE-2026-30869 fix added IsSensitivePath() which blocks <workspace>/conf/ and OS-level paths (/etc, /root, etc.). However, it does NOT block: - <workspace>/temp/siyuan.db — full document database - <workspace>/temp/blocktree.db — block tree database - <workspace>/temp/siyuan.log — kernel log - <workspace>/temp/asset_content.db — asset content database

Note: the /appearance/ handler in the same file correctly uses gulu.File.IsSubPath() to validate paths (line 447), but this check is missing from the /export/ handler.

PoC

poc.zip Please extract the uploaded compressed file before proceeding

  1. docker compose up -d --build
  2. sh poc.sh

스크린샷 2026-04-19 오후 5 08 30

Impact

  • Data exfiltration: An authenticated user (including low-privilege Publish/Reader users via the Publish service) can download the entire SQLite document database containing all blocks, documents, attributes, and full-text search indexes.
  • Information disclosure: Kernel log (siyuan.log) leaks internal server paths, versions, configuration details, and error messages.
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/siyuan-note/siyuan/kernel"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "3.6.5"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-41894"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-22"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-04-22T20:51:22Z",
    "nvd_published_at": "2026-04-24T19:17:14Z",
    "severity": "HIGH"
  },
  "details": "### Summary\nThe fix for CVE-2026-30869 in SiYuan v3.5.10 only added a denylist check (`IsSensitivePath`) but did not address the root cause \u2014 a redundant `url.PathUnescape()` call in `serveExport()`. An authenticated attacker can use double URL encoding (`%252e%252e`) to traverse directories and read arbitrary workspace files including the full SQLite database (`siyuan.db`), kernel log, and all user documents.\n\n### Details\nIn `kernel/server/serve.go`, the `serveExport()` function (line 314-320) processes file paths as follows:\n\n```go\nfilePath := strings.TrimPrefix(c.Request.URL.Path, \"/export/\")\ndecodedPath, err := url.PathUnescape(filePath)     // second decode\nfullPath := filepath.Join(exportBaseDir, decodedPath)\n```\n\nGo\u0027s HTTP server already decodes percent-encoded characters once during request parsing. The additional `url.PathUnescape()` call creates a double-decode vulnerability:\n\n1. Attacker sends: `GET /export/%252e%252e/siyuan.db`\n2. Go HTTP decodes `%25` \u2192 `%`, result: `URL.Path = /export/%2e%2e/siyuan.db`\n3. Go\u0027s path cleaner sees `%2e%2e` as literal characters (not `..`), no redirect occurs\n4. `url.PathUnescape(\"%2e%2e\")` decodes to `..`\n5. `filepath.Join(exportBaseDir, \"../siyuan.db\")` resolves to `\u003cworkspace\u003e/temp/siyuan.db`\n\nThe CVE-2026-30869 fix added `IsSensitivePath()` which blocks `\u003cworkspace\u003e/conf/` and OS-level paths (`/etc`, `/root`, etc.). However, it does NOT block:\n- `\u003cworkspace\u003e/temp/siyuan.db` \u2014 full document database\n- `\u003cworkspace\u003e/temp/blocktree.db` \u2014 block tree database\n- `\u003cworkspace\u003e/temp/siyuan.log` \u2014 kernel log\n- `\u003cworkspace\u003e/temp/asset_content.db` \u2014 asset content database\n\nNote: the `/appearance/` handler in the same file correctly uses `gulu.File.IsSubPath()` to validate paths (line 447), but this check is missing from the `/export/` handler.\n\n### PoC\n[poc.zip](https://github.com/user-attachments/files/26866234/poc.zip)\nPlease extract the uploaded compressed file before proceeding\n\n1. docker compose up -d --build\n2. sh poc.sh\n\n\u003cimg width=\"550\" height=\"184\" alt=\"\u1109\u1173\u110f\u1173\u1105\u1175\u11ab\u1109\u1163\u11ba 2026-04-19 \u110b\u1169\u1112\u116e 5 08 30\" src=\"https://github.com/user-attachments/assets/6aea4334-0b5a-4f45-bd1f-ecfad61ba524\" /\u003e\n\n\n\n\n### Impact\n- Data exfiltration: An authenticated user (including low-privilege Publish/Reader users via the Publish service) can download the entire SQLite document database containing all blocks, documents, attributes, and full-text search indexes.\n- Information disclosure: Kernel log (`siyuan.log`) leaks internal server paths, versions, configuration details, and error messages.",
  "id": "GHSA-hjh7-r5w8-5872",
  "modified": "2026-04-27T16:34:02Z",
  "published": "2026-04-22T20:51:22Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/siyuan-note/siyuan/security/advisories/GHSA-hjh7-r5w8-5872"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-41894"
    },
    {
      "type": "WEB",
      "url": "https://github.com/siyuan-note/siyuan/commit/bb481e1290c4a34255652ede85a546504505d2a7"
    },
    {
      "type": "ADVISORY",
      "url": "https://github.com/advisories/GHSA-2h2p-mvfx-868w"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/siyuan-note/siyuan"
    },
    {
      "type": "WEB",
      "url": "https://github.com/siyuan-note/siyuan/releases/tag/v3.6.5"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "SiYuan: Path Traversal via Double URL Encoding in `/export/` Endpoint (Incomplete Fix Bypass for CVE-2026-30869)"
}



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…

Detection rules are retrieved from Rulezet.

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…