{"record":{"id":"535ff223efa397b2","repo":"JuliusBrussee/caveman","slug":"sqlite-parent-q-is-group-world-writable","errorCode":null,"errorMessage":"sqlite parent %q is group/world writable","messagePattern":"sqlite parent %q is group/world writable","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/ccr/sqlite_parent_security_posix.go","lineNumber":15,"sourceCode":"//go:build !windows && !js\n\npackage ccr\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\nfunc validateSQLiteParentSecurity(path string, info os.FileInfo) error {\n\t// Sticky shared temp directories (/tmp, macOS /private/tmp) prevent another\n\t// user from replacing the 0600 file. Other group/world-writable parents do not.\n\tif info.Mode().Perm()&0o022 != 0 && info.Mode()&os.ModeSticky == 0 {\n\t\treturn fmt.Errorf(\"sqlite parent %q is group/world writable\", path)\n\t}\n\treturn nil\n}\n\nfunc createSQLiteFile(path string) error {\n\t// Close before publishing: another Store in this process may open the\n\t// database as soon as its name exists. Closing even a creation descriptor\n\t// after that point would discard SQLite's process-wide POSIX locks.\n\tfile, err := os.CreateTemp(filepath.Dir(path), \".caveman-sqlite-*\")\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer os.Remove(file.Name())\n\tif err := file.Close(); err != nil {\n\t\treturn err\n\t}\n\t// Link is atomic and refuses to replace an existing file or symlink.\n\treturn os.Link(file.Name(), path)","sourceCodeStart":1,"sourceCodeEnd":33,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/engine/ccr/sqlite_parent_security_posix.go#L1-L33","documentation":"engine/ccr hardens its SQLite database by requiring the parent directory to prevent other local users from replacing the (0600) database file. On POSIX, a parent directory that is group- or world-writable throws this error unless it is sticky (like /tmp), where the sticky bit already blocks replacement by other users.","triggerScenarios":"Opening/creating a CCR SQLite store whose parent directory has write permission for group or other (perm bits & 0o022 nonzero) without the sticky bit — e.g. a shared /var/tmp-style directory or a data dir chmod'ed 0777 or 0775.","commonSituations":"Databases placed in shared temp directories lacking the sticky bit; deployment scripts chmod'ing data dirs 0777 'to fix permissions'; containers running with permissive umask; multi-user hosts where the app writes to a group-shared directory.","solutions":["Move the database into a private directory owned by the running user, e.g. chmod 700 ~/.local/state/myapp or the app's own data dir","Fix the parent directory permissions: chmod go-w <parent> (e.g. 0755 or 0700) before starting the store","If you intentionally use a shared dir like /tmp, ensure it has the sticky bit (chmod +t) or preferably use a per-user directory instead"],"exampleFix":"// before\nstore, _ := engine.OpenCCRStore(\"/var/tmp/shared/ccr.sqlite\") // /var/tmp/shared is 0777\n// after\nos.Chmod(\"/var/tmp/shared\", 0o700) // or use a per-user data dir\nstore, _ := engine.OpenCCRStore(\"/var/tmp/shared/ccr.sqlite\")","handlingStrategy":"validation","validationCode":"info, err := os.Stat(filepath.Dir(path))\nif err != nil { return err }\nperm := info.Mode().Perm()\nif perm&0o022 != 0 && info.Mode()&os.ModeSticky == 0 {\n\treturn fmt.Errorf(\"parent %s must not be group/world writable\", filepath.Dir(path))\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep app data in a 0700 directory owned by the running user","Avoid chmod 0777 'fixes' on data directories","Set a restrictive umask (077) in deployment scripts","If using shared temp dirs, ensure the sticky bit is set"],"tags":["go","posix","sqlite","security","permissions","filesystem"],"backgroundTag":"insufficient-permissions","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}