Skip to content

fix: create the runtime directories without world access - #902

Closed
blaipr wants to merge 1 commit into
mainfrom
fix/runtime-directories-are-not-world-readable
Closed

fix: create the runtime directories without world access#902
blaipr wants to merge 1 commit into
mainfrom
fix/runtime-directories-are-not-world-readable

Conversation

@blaipr

@blaipr blaipr commented Sep 2, 2026

Copy link
Copy Markdown
Member

The entrypoint creates four runtime directories, chowns them to www-data, and then chmods exactly
one of them. Measured on the running container:

drwxr-x---  config
drwxr-xr-x  var/backup
drwxr-xr-x  var/cache
drwxr-xr-x  var/temp

var/backup holds the backup archives — the database dump and config.xml — and the XML export,
which carries every account's encrypted secret and key, and when no export password was given the
name, login, URL and notes of every account in the clear.

Those files are restricted to their owner, but only once they are fully written:
ArchiveHandler::compressDirectory() and XmlExport::export() both chmod 0600 after the
write completes, and compressDirectory() walks the whole application tree first, so the window is
not instantaneous. A world-traversable parent directory is what makes that window reachable —
anybody else on the host can enter and read during it. var/temp holds the intermediates on the
way there.

This is also the mode the application itself would have chosen: DirectoryHandler::create()
defaults to 0750. It never gets the chance, because checkOrCreate() only creates a directory that
is not already there, and the entrypoint has already made it.

Verified on the running container

at 0755:      nobody → /var/www/html/var/backup ... CAN-ENTER
back at 0750: nobody → ls: cannot open directory ... Permission denied

and the application still serves (HTTP 200 on the login page), with both suites green.

Not in scope

The chmod-after-write ordering in the archive and export handlers is the other half of this, and it
is worth fixing on its own — FileBackupHandlersFactory already shows the right shape, opening
database.sql and restricting it before any write. This PR closes the directory, which is what
makes the window reachable at all.

The entrypoint creates four runtime directories, chowns them to www-data, and chmods
exactly one. Measured on the running container: config is 0750, var/backup, var/cache and
var/temp are 0755.

var/backup holds the backup archives — the database dump and config.xml — and the XML
export, which carries every account's encrypted secret and key, and with no export
password the name, login, URL and notes of every account in the clear. Those files are
restricted to their owner, but only once fully written: the archive and export handlers
chmod 0600 after the write, and compressDirectory() walks the whole application tree
first. A world-traversable parent is what makes that window reachable.

0750 is also what the application itself would have chosen — DirectoryHandler::create()
defaults to it, and never gets the chance because checkOrCreate() only creates a directory
that is not already there.

Verified on the container: at 0755 'nobody' can enter var/backup, at 0750 it cannot, and
the login page still serves 200.
@blaipr

blaipr commented Sep 2, 2026

Copy link
Copy Markdown
Member Author

Closing in favour of fixing the root cause.

Tightening var/backup, var/cache and var/temp to 0750 does close the window, and it is verified working on the container — at 0755 nobody can enter var/backup, at 0750 it cannot, and the application still serves. But each of those three directories holds a tracked .blank file, and once the directory is 0750 owned by www-data, host-side git cannot stat them:

warning: could not open directory 'var/backup/': Permission denied
var/backup/.blank: Permission denied

That breaks git status, git add and git checkout for every developer whose uid is not the container's www-data, which is the whole point of the bind-mounted dev environment.

The directory mode was never the defect anyway — it is what makes the defect reachable. The defect is that ArchiveHandler and XmlExport write the whole file and restrict it afterwards. FileBackupHandlersFactory already shows the right shape, opening database.sql and restricting it before any write. Fixing that makes the directory mode irrelevant to confidentiality, and costs the dev environment nothing.

@blaipr blaipr closed this Sep 2, 2026
@blaipr
blaipr deleted the fix/runtime-directories-are-not-world-readable branch September 2, 2026 23:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant