PST-060: Database, media and log files are created world-readable on a bare-metal install #789
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
performance
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo#789
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found in the security audit of 2026-10-10 (
SECURITY-AUDIT-2026-10-10.md), run againstmainatc30851bfrom 8 to 10 October 2026, as PST-060. Severity: Low.The text below is the audit's entry, unchanged apart from links to the other issues it names. The finding was produced by automated review and checked by a second automated pass; re-check it before acting on it.
src/postulo/config/settings/base.py(148-173)Who can do it, and what they need. Another local user on a shared host where Postulo is installed outside the container. Precondition: a multi-user host and a default umask of 022.
How it works.
_db_path.parent.mkdir/os.makedirs(place)create data/ and data/logs at 0755.Impact. Confidentiality of personal documents on shared hosts. Inside the published image everything is owned by the postulo user in a root-only volume, so this concerns the pip/source install path only.
Evidence.
Verification (verdict: confirmed; severity after verification: Low; first-pass claim: Informational). Raise from informational to low: there is a measured local-read path, but it needs a multi-user bare-metal host, umask 022 and a traversable install directory. Add the backup archives in POSTULO_BACKUP_DIR (data/backups) to the affected list, as they hold the whole DB plus media. Also note the data/ directory lives inside the checkout (REPO_DIR/data) and the secret key file written by dev.py (_key_file.write_text) gets the same default mode. Not affected: the published container image. Remediation: create data, media, backups and logs with 0700 (os.makedirs(mode=0o700) and chmod), set FILE_UPLOAD_PERMISSIONS = 0o600 and FILE_UPLOAD_DIRECTORY_PERMISSIONS = 0o700, wrap the process in os.umask(0o077) for the web/worker/manage entry points, create the SQLite file and backups with 0600, and document it on the wiki's install page. I could not read that page (it is not in the repo), so I cannot say whether it already tells bare-metal operators to set a umask.
Suggested remediation. Set FILE_UPLOAD_PERMISSIONS = 0o600 and FILE_UPLOAD_DIRECTORY_PERMISSIONS = 0o700, create data/, data/logs and the SQLite directory with mode 0o700, and open the log handler with a restrictive mode (RotatingFileHandler subclass overriding _open with os.open(..., 0o600)).