{"record":{"id":"ddd32788af512dbb","repo":"siyuan-note/siyuan","slug":"encrypted-document-is-a-symbolic-link-s","errorCode":null,"errorMessage":"encrypted document is a symbolic link [%s]","messagePattern":"encrypted document is a symbolic link \\[(.+?)\\]","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/encrypted_index.go","lineNumber":64,"sourceCode":"\nfunc authenticateEncryptedIndexDocuments(boxID string, dek []byte) error {\n\tboxDir := filepath.Join(util.DataDir, boxID)\n\tids := map[string]struct{}{}\n\treturn filepath.WalkDir(boxDir, func(filePath string, entry fs.DirEntry, walkErr error) error {\n\t\tif walkErr != nil {\n\t\t\treturn walkErr\n\t\t}\n\t\tif entry.IsDir() {\n\t\t\tif filePath != boxDir && !ast.IsNodeIDPattern(entry.Name()) {\n\t\t\t\treturn filepath.SkipDir\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\t\tif !strings.HasSuffix(entry.Name(), \".sy\") {\n\t\t\treturn nil\n\t\t}\n\t\tif entry.Type()&fs.ModeSymlink != 0 {\n\t\t\treturn fmt.Errorf(\"encrypted document is a symbolic link [%s]\", entry.Name())\n\t\t}\n\t\tdata, err := filelock.ReadFile(filePath)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tplain, err := DecryptFile(boxID, entry.Name(), dek, data)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttree, err := loadTreeByData0(plain)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif tree == nil || tree.Root == nil || tree.Root.ID+\".sy\" != entry.Name() {\n\t\t\treturn fmt.Errorf(\"encrypted document root ID does not match filename [%s]\", entry.Name())\n\t\t}\n\t\tif _, exists := ids[tree.Root.ID]; exists {\n\t\t\treturn fmt.Errorf(\"duplicate encrypted document ID [%s]\", tree.Root.ID)","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/encrypted_index.go#L46-L82","documentation":"While re-authenticating/rebuilding encrypted indexes, the walker rejects any *.sy entry whose filesystem mode reports a symbolic link. Encrypted notebooks require real regular files: a symlinked document would bypass the per-file encryption/authentication model and could point outside the box, so it is treated as an integrity violation and aborts the index rebuild.","triggerScenarios":"A .sy file inside the encrypted box's documents directory is replaced by (or is) a symlink — e.g. a user symlinked a document from elsewhere, a sync/restore tool created links, or a container mount produced link-style entries — while authenticateEncryptedIndexDocuments walks the tree.","commonSituations":"Manual workspace surgery where users link documents between notebooks; dotfile-managers or restore scripts that symlink data; copying a workspace with cp -s / rsync --link; Docker volume mounts exposing links.","solutions":["Replace the symlink with a real copy of the encrypted document file (cp -L) so it is a regular file inside the box.","Remove the symlink if it is not a valid document, then re-open/rebuild the indexes.","Avoid tools that create symlinks when copying or restoring workspace data; use full-copy modes (cp -a, rsync -a without --link)."],"exampleFix":"// before (shell)\nln -s /other/workspace/doc.sy data/boxes/<box>/doc.sy\n// after\ncp -L /other/workspace/doc.sy data/boxes/<box>/doc.sy","handlingStrategy":"validation","validationCode":"info, _ := os.Lstat(docPath)\nif info != nil && info.Mode()&os.ModeSymlink != 0 {\n    return fmt.Errorf(\"%s is a symlink; replace with a real copy\", docPath)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Copy workspace data with full-copy modes, never symlinks (avoid cp -s, rsync --link)","Audit data/boxes directories for symlinks before opening encrypted boxes","Keep documents physically inside the box directory"],"tags":["filesystem","symlink","encryption","integrity"],"backgroundTag":"path-traversal-blocked","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}