Vulnerability Overview
What’s Affected
The SiYuan application contains a critical authorization flaw in its /api/block/getRefIDs API endpoint that exposes references to password-protected documents without requiring authentication. This vulnerability affects SiYuan kernel version 3.7.2 and potentially earlier versions containing the same code pattern.
The vulnerability specifically impacts:
- SiYuan instances with API access enabled
- All user roles, including anonymous users and reader-level accounts
- Password-protected documents stored within affected instances
- Organizations relying on SiYuan for sensitive document management
Why This Matters
SiYuan is a privacy-focused note-taking and knowledge management application. Users implement password protection on sensitive documents with the expectation that unauthorized parties cannot discover or access their contents. This vulnerability undermines that security model by allowing attackers to enumerate references to protected documents without authentication.
While the actual document content remains protected, the disclosure of reference IDs creates several risks:
- Information leakage: Attackers learn which sensitive documents exist and their relationships
- Secondary exploitation: Reference IDs can be used to probe other API endpoints for additional information
- Compliance violations: Organizations may breach data protection regulations by failing to prevent unauthorized disclosure
- Reconnaissance: Attackers gather intelligence for targeted attacks against specific documents
Severity Assessment
CVSS v3.1 Score: 5.3 (Medium)
- Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
- Attack Vector: Network
- Attack Complexity: Low
- Privileges Required: None
- User Interaction: None
- Scope: Unchanged
- Confidentiality Impact: Low
- Integrity Impact: None
- Availability Impact: None
The medium severity rating reflects the confidentiality impact without direct access to protected content. However, organizations handling sensitive information should treat this as a priority remediation item.
Technical Details
The Root Cause
The vulnerability stems from incomplete authorization logic in the getRefIDs function. The endpoint implements visibility tier checks but omits password tier validation—a critical oversight that creates an authorization bypass.
The code path follows this pattern:
getRefIDs request
↓
Check visibility tier ✓ (implemented)
↓
Check password tier ✗ (missing)
↓
Return reference IDs
How the Flaw Works
The getRefIDs endpoint accepts requests to retrieve all blocks that reference a specific document block. The function uses a helper method to filter results based on access permissions. However, this helper only validates visibility tiers and lacks the request context necessary to perform password tier checks.
Technical breakdown:
- Request arrives at
/api/block/getRefIDswith a block ID parameter - Visibility check executes and passes (the helper can verify if a document is marked as public/private)
- Password check is skipped because the helper function lacks the
*gin.Contextparameter needed to validate password authentication - Reference IDs are returned to the requester, regardless of password protection status
- Attacker learns which documents reference the queried block, even if those documents are password-protected
Why Password Tier Checks Are Missing
The implementation uses a helper function designed for visibility filtering that doesn’t accept the HTTP request context (*gin.Context). Password tier validation requires access to:
- Session information
- Authentication tokens
- User credentials
- Request headers
Without passing the request context to the filtering function, the code cannot perform password validation. This represents a design oversight where the developer implemented partial authorization checks without completing the security model.
Attack Scenarios
Anonymous User Exploitation
An attacker with no SiYuan account can exploit this vulnerability through direct API calls:
# Attacker queries the API endpoint
curl -X POST http://target-siyuan.com/api/block/getRefIDs \
-H "Content-Type: application/json" \
-d '{"id":"block-id-of-sensitive-doc"}'
# Response reveals references without authentication
{
"code": 0,
"data": {
"refIDs": [
"ref-id-1-in-protected-doc",
"ref-id-2-in-protected-doc",
"ref-id-3-in-protected-doc"
]
}
}
The attacker discovers that password-protected documents contain references to the queried block without ever entering a password.
Reader Role Abuse
A legitimate user with read-only access to public documents can enumerate references within password-protected documents:
- User logs in with reader credentials
- User accesses public documents normally
- User crafts API requests to
getRefIDstargeting blocks in password-protected documents - API returns reference IDs without requiring password authentication
- User gains unauthorized knowledge of document relationships and structure
Information Gathering for Secondary Attacks
Attackers combine this vulnerability with other reconnaissance techniques:
- Enumerate document structure: Use
getRefIDsto map relationships between documents - Identify high-value targets: Discover which documents are referenced most frequently (likely important)
- Probe other endpoints: Use reference IDs with other API endpoints to extract additional metadata
- Social engineering: Use discovered document names and relationships in targeted phishing campaigns
- Targeted attacks: Focus brute-force or credential-stuffing attacks on identified sensitive documents
Risk Assessment
Confidentiality Impact
Direct Impact: Low to Medium
The vulnerability does not expose document content, only the existence of references. However, this information can be highly sensitive:
- Document discovery: Attackers learn which sensitive documents exist
- Relationship mapping: Attackers understand how documents relate to each other
- Organizational intelligence: Attackers infer organizational structure and processes
- Targeting information: Attackers identify high-value documents for focused attacks
Indirect Impact: Medium to High
Reference IDs can be weaponized through:
- API endpoint probing: Using reference IDs to query other endpoints for metadata
- Timing attacks: Analyzing response times to infer document properties
- Correlation analysis: Combining reference data with public information to identify sensitive documents
- Privilege escalation: Using discovered information to craft targeted privilege escalation attempts
Who Is Vulnerable
Directly vulnerable:
- Organizations using SiYuan kernel 3.7.2
- Instances with API access enabled
- Deployments containing password-protected documents
Indirectly vulnerable:
- Organizations where attackers can reach the SiYuan API (network-accessible instances)
- Teams using SiYuan for sensitive project planning, financial data, or confidential research
- Enterprises with compliance requirements (HIPAA, GDPR, SOC 2) for document confidentiality
Lower risk:
- Air-gapped or offline SiYuan instances
- Deployments behind restrictive network controls
- Instances without password-protected documents
Real-World Exploitation Likelihood
Likelihood: High
- Low barrier to entry: No special tools required; standard HTTP requests suffice
- No authentication needed: Anonymous users can exploit immediately
- Passive discovery: Attackers can enumerate references without triggering obvious alerts
- Automated exploitation: Simple to script and scale across multiple targets
- Public API documentation: SiYuan’s open-source nature means attack methods are discoverable
Detection difficulty: Medium
- Legitimate API traffic and malicious queries appear identical
- High-volume legitimate usage can mask exploitation attempts
- Requires correlation with other indicators to confirm attacks
Detection and Verification
Code Review Approach
Step 1: Locate the vulnerable function
# Search for getRefIDs implementation
grep -r "getRefIDs" /path/to/siyuan/source --include="*.go"
Step 2: Examine the authorization logic
Review the function signature and helper calls:
// Look for this pattern (vulnerable)
func getRefIDs(c *gin.Context) {
// ... code ...
refs := filterByVisibility(blockID) // Missing password check
// ... return refs ...
}
// Should look like this (fixed)
func getRefIDs(c *gin.Context) {
// ... code ...
refs := filterByVisibilityAndPassword(c, blockID) // Includes password check
// ... return refs ...
}
Step 3: Verify password tier validation
Confirm that the filtering function:
- Accepts the request context (
*gin.Context) - Checks user authentication status
- Validates password tier permissions
- Returns empty results for unauthorized access
Penetration Testing Methods
Test 1: Anonymous access attempt
# Without authentication, query references to a password-protected document
curl -X POST http://target:5500/api/block/getRefIDs \
-H "Content-Type: application/json" \
-d '{"id":"protected-block-id"}'
# Vulnerable: Returns reference IDs
# Patched: Returns empty array or error
Test 2: Reader role enumeration
- Create a test user with reader-only permissions
- Log in with reader credentials
- Attempt to query
getRefIDsfor password-protected documents - Verify that no references are returned
Test 3: Authenticated user with password
- Log in with credentials for password-protected document
- Enter the document password
- Query
getRefIDsfor that document - Verify that references are returned (expected behavior)
Test 4: Authenticated user without password
- Log in with valid credentials
- Do NOT enter the password for a protected document
- Query
getRefIDsfor that document - Verify that no references are returned (expected behavior)
Log Analysis Indicators
Monitor for exploitation attempts using these indicators:
Suspicious API patterns:
POST /api/block/getRefIDs
- Source: Anonymous or reader-role user
- Target: Block ID from password-protected document
- Frequency: Multiple requests in short timeframe
- Pattern: Systematic enumeration of block IDs
Log entry examples to investigate:
[ALERT] Unauthorized getRefIDs access
User: anonymous
Block: protected-doc-block-123
Timestamp: 2024-01-15T14:32:45Z
Source IP: 192.0.2.100
[ALERT] Reader role accessing protected references
User: reader-user@example.com
Block: password-protected-block-456
Timestamp: 2024-01-15T14:33:12Z
Requests: 47 in 2 minutes
Remediation Steps
Immediate Actions
For the next 24 hours:
- Enable API access logging if not already active
- Review recent API logs for suspicious
getRefIDsrequests - Notify stakeholders of the vulnerability and risk
- Assess exposure by identifying password-protected documents in your instance
- Implement network controls to restrict API access (see Monitoring section)
Code-Level Fixes
Required code modification:
Update the getRefIDs function to pass request context to the filtering helper:
// BEFORE (Vulnerable)
func getRefIDs(c *gin.Context) {
blockID := c.PostForm("id")
// Helper lacks password tier check
refs := filterByVisibility(blockID)
c.JSON(http.StatusOK, gin.H{
"code": 0,
"data": gin.H{"refIDs": refs},
})
}
// AFTER (Fixed)
func getRefIDs(c *gin.Context) {
blockID := c.PostForm("id")
// Helper now includes password tier validation
refs := filterByVisibilityAndPassword(c, blockID)
c.JSON(http.StatusOK, gin.H{
"code": 0,
"data": gin.H{"refIDs": refs},
})
}
// Updated helper function
func filterByVisibilityAndPassword(c *gin.Context, blockID string) []string {
// Check visibility tier
if !isVisible(blockID) {
return []string{}
}
// Check password tier (NEW)
if isPasswordProtected(blockID) && !userHasPassword(c, blockID) {
return []string{}
}
// Return references only if both checks pass
return getReferences(blockID)
}
Key changes:
- Pass
*gin.Contextto filtering function - Add password tier validation before returning results
- Return empty array for unauthorized access
- Maintain backward compatibility for authorized users
Testing and Validation
Unit tests to add:
func TestGetRefIDsPasswordProtected(t *testing.T) {
// Test 1: Anonymous user cannot access protected references
req := httptest.NewRequest("POST", "/api/block/getRefIDs",
strings.NewReader(`{"id":"protected-block"}`))
w := httptest.NewRecorder()
getRefIDs(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Contains(t, w.Body.String(), `"refIDs":[]`)
}
func TestGetRefIDsWithPassword(t *testing.T) {
// Test 2: Authenticated user with password can access references
req := httptest.NewRequest("POST", "/api/block/getRefIDs",
strings.NewReader(`{"id":"protected-block"}`))
req.AddCookie(&http.Cookie{Name: "auth_token", Value: "valid-token"})
w := httptest.NewRecorder()
getRefIDs(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Contains(t, w.Body.String(), `"refIDs":["ref-1","ref-2"]`)
}
Integration testing:
- Deploy patched version to staging environment
- Run full API test suite
- Verify password-protected documents are inaccessible without authentication
- Confirm legitimate users can still access authorized references
- Load test to ensure no performance degradation
Deployment Considerations
Pre-deployment checklist:
- [ ] Code review completed by security team
- [ ] All tests passing (unit, integration, security)
- [ ] Database migrations tested (if applicable)
- [ ] Rollback procedure documented
- [ ] Stakeholders notified of maintenance window
- [ ] Backup created before deployment
Deployment strategy:
- Blue-green deployment: Run patched and current versions in parallel
- Canary release: Deploy to 10% of users first, monitor for issues
- Gradual rollout: Increase to 50%, then 100% over 24 hours
- Monitoring: Watch API error rates, response times, and security logs
Post-deployment validation:
# Verify patch is active
curl -X POST http://target:5500/api/block/getRefIDs \
-H "Content-Type: application/json" \
-d '{"id":"protected-block-id"}'
# Expected response (patched):
# {"code":0,"data":{"refIDs":[]}}
# Previous response (vulnerable):
# {"code":0,"data":{"refIDs":["ref-1","ref-2","ref-3"]}}
Monitoring and Prevention
API Access Logging
Enable comprehensive logging:
{
"timestamp": "2024-01-15T14:32:45.123Z",
"endpoint": "/api/block/getRefIDs",
"method": "POST",
"user": "anonymous",
"user_role": "none",
"source_ip": "192.0.2.100",
"block_id": "protected-doc-block-123",
"response_code": 200,
"response_size": 156,
"processing_time_ms": 12,
"password_protected": true,
"user_authenticated": false,
"authorization_result": "DENIED"
}
Log retention:
- Maintain API logs for minimum 90 days
- Archive logs older than 90 days for compliance
- Ensure logs are immutable and tamper-evident
Anomaly Detection
Implement detection rules:
Rule 1: High-volume getRefIDs requests
Trigger: >100 requests per minute from single IP
Action: Rate limit, alert security team
Rule 2: Anonymous enumeration pattern
Trigger: Anonymous user querying multiple protected block IDs
Action: Block IP, investigate
Rule 3: Reader role abuse
Trigger: Reader-role user accessing protected references
Action: Revoke access, audit account
Rule 4: Systematic block ID scanning
Trigger: Sequential block ID queries (block-1, block-2, block-3...)
Action: Alert, analyze intent
Monitoring dashboard metrics:
- API requests by endpoint
- Authentication failures
- Authorization denials
- Response times
- Error rates
- Source IP distribution
Long-Term Security Hardening
Architectural improvements:
- Implement API gateway with centralized authorization
- Add rate limiting to prevent enumeration attacks
- Require authentication for all API endpoints
- Implement audit logging for all sensitive operations
- Use API versioning to manage security updates
- Add request signing to prevent tampering
Code security practices:
- Security code review for all API endpoints
- Automated security testing in CI/CD pipeline
- Dependency scanning for vulnerable libraries
- Regular penetration testing of API surface
- Threat modeling for new features
- Security training for development team
Affected Versions and Timeline
Confirmed Vulnerable Versions
| Version | Status | Notes |
|---|---|---|
| 3.7.2 | Vulnerable | Confirmed affected |
| 3.7.1 | Unknown | Likely vulnerable; requires verification |
| 3.7.0 | Unknown | Likely vulnerable; requires verification |
| 3.6.x | Unknown | Earlier versions may contain same flaw |
| 3.5.x and earlier | Unknown | Requires code review to confirm |
How to check your version:
# Check SiYuan kernel version
curl http://localhost:5500/api/system/getConf | grep kernel
# Output example:
# "kernel": "3.7.2"
Patch Availability
Current status:
- Patch released: Yes (as of January 2024)
- Patch version: 3.7.3 or later
- Availability: GitHub releases, official download page
Obtaining the patch:
- Visit SiYuan GitHub Releases
- Download version 3.7.3 or later
- Follow upgrade instructions for your platform
Upgrade Guidance
Before upgrading:
- Backup your data
# Create backup of SiYuan workspace
cp -r ~/.siyuan ~/.siyuan.backup.$(date +%Y%m%d)
- Review release notes for breaking changes
- Test in staging environment first
- Schedule maintenance window with minimal disruption
- Notify users of planned upgrade
Upgrade process:
# Stop SiYuan service
systemctl stop siyuan
# Download and extract new version
wget https://github.com/siyuan-note/siyuan/releases/download/v3.7.3/siyuan-3.7.3-linux.tar.gz
tar -xzf siyuan-3.7.3-linux.tar.gz
# Start SiYuan service
systemctl start siyuan
# Verify upgrade
curl http://localhost:5500/api/system/getConf | grep kernel
Post-upgrade verification:
- Confirm version shows 3.7.3 or later
- Test API access with valid credentials
- Verify password-protected documents are inaccessible without password
- Review API logs for any errors
- Notify users that upgrade is complete
Frequently Asked Questions
Q: Can attackers access the actual content of password-protected documents?
A: No. This vulnerability only exposes the existence of references to protected blocks, not their content. However, reference IDs can be used to probe other endpoints for additional information. The actual document content remains protected by the password tier.
Q: Do I need administrator access to exploit this vulnerability?
A: No. The vulnerability can be exploited by anonymous users or users with minimal reader-level permissions, making it highly accessible. This is one of the most concerning aspects of this flaw—no special privileges are required.
Q: How can I determine if my SiYuan instance has been exploited?
A: Review API access logs for unusual /api/block/getRefIDs requests from anonymous or reader-role users, particularly those accessing references to password-protected documents. Look for patterns of systematic enumeration or high-volume requests from single IP addresses.
Q: What should I do while waiting for a patch?
A: Implement network-level access controls to restrict API endpoint access, enable comprehensive logging, and monitor for suspicious activity targeting the getRefIDs endpoint. Consider temporarily disabling API access if not essential for operations.
Q: Are earlier versions of SiYuan also vulnerable?
A: The vulnerability is confirmed in kernel version 3.7.2. Earlier versions may be affected if they contain the same code pattern. Review your version and apply patches accordingly. Contact SiYuan support if you need clarification on specific versions.
Q: Does this vulnerability affect offline SiYuan instances?
A: Only SiYuan instances with API access enabled are vulnerable. Offline or air-gapped deployments are not at risk from remote exploitation. However, local access could still pose a risk if the vulnerability exists in the codebase.
Q: Can I disable the getRefIDs endpoint to prevent exploitation?
A: While disabling the endpoint would prevent exploitation, it may break legitimate functionality. Instead, implement proper authorization checks (via patching) and restrict API access through network controls.
Q: How does this vulnerability relate to other SiYuan security issues?
A: This is an authorization bypass specific to the getRefIDs endpoint. It should be addressed independently from other security concerns, though it highlights the importance of comprehensive security review across all API endpoints.
Q: What is the recommended timeline for patching?
A: Apply patches within 7 days for instances containing sensitive documents. Instances with non-sensitive content can follow standard patch management timelines. Prioritize based on your risk assessment and data sensitivity.
References
Official Resources:
Security Standards:
- OWASP API Security Top 10
- OWASP Authorization Cheat Sheet
- CWE-639: Authorization Bypass Through User-Controlled Key
Related CVEs:
Additional Reading:
- NIST Cybersecurity Framework: Authentication and Authorization
- SANS Institute: API Security Best Practices
- PortSwigger Web Security Academy: Authorization

Document Information:
- Advisory ID: SYN-2024-001
- Publication Date: January 15, 2024
- Last Updated: January 15, 2024
- Classification: Security Advisory
- Distribution: Public
For Questions or Additional Information:
Contact your SiYuan support representative or security team. Organizations requiring additional technical assistance should consult with qualified cybersecurity professionals.