Skip to content

fix: keep a master password off the command line - #906

Merged
blaipr merged 1 commit into
mainfrom
fix/a-master-password-is-not-passed-on-the-command-line
Sep 3, 2026
Merged

fix: keep a master password off the command line#906
blaipr merged 1 commit into
mainfrom
fix/a-master-password-is-not-passed-on-the-command-line

Conversation

@blaipr

@blaipr blaipr commented Sep 3, 2026

Copy link
Copy Markdown
Member

sp:updateMasterPassword takes --masterPassword and --currentMasterPassword; sp:install takes
--adminPassword, --masterPassword and --databasePassword. A value passed that way is in
argv, and argv is /proc/<pid>/cmdline, which every other local user on the host can read for
as long as the command runs
.

This is a different threat from the one the CLI is otherwise exempt from, and the distinction is
worth being precise about. sp:backup deliberately has no demo guard because whoever can run it
already has config/config.xml — the database credentials and the crypto keys — so a guard there
protects nothing. The users this is about have neither that file nor any way to read the
environment of a process they do not own. And sp:updateMasterPassword re-encrypts every account,
history row and custom field, so the window is minutes, not an instant.

Both commands already accept the same values through an environment variable, and both fall back to
a hidden prompt. Those are the two ways to hand a command a secret that other local users cannot
read, and neither is any harder to use.

The change

CommandBase gains two helpers, called once at the start of each command:

  • the value is taken out of what ps shows. cli_set_process_title() rewrites that memory, so
    it is gone for the rest of the run. The title is rebuilt from the real command line with only the
    named options replaced by ***, rather than replaced wholesale, so a process being looked at
    still says what it is — and so the test runner does not lose its own name when the CLI tests
    exercise these commands.
  • the operator is told. Nothing is said when the value came from the environment or the prompt.

Called at the start rather than beside each password so the secret is gone before the work begins.

What it does not do

It shrinks the window to the moment before the command starts; it cannot close it — the shell forks
with the full argv before PHP runs — and it does nothing about shell history or a script with the
password written into it. That is what the warning is for. The options are kept: they are
documented, and removing them would break existing automation for no gain the environment variable
does not already offer.

Tests

Asserted against /proc/self/cmdline directly, because the whole point is what another process can
see, and because the platform could stop honouring cli_set_process_title() without anything else
noticing. Both spellings the console accepts — --option=value and --option value — are covered,
along with a non-secret option being left alone, and a negative control showing the secret is
plainly visible without the call.

sp:updateMasterPassword takes --masterPassword and --currentMasterPassword; sp:install
takes --adminPassword, --masterPassword and --databasePassword. A value passed that way is
in argv, and argv is /proc/<pid>/cmdline, which every other local user on the host can read
for as long as the command runs — minutes, for a rotation that re-encrypts every account.

This is a different threat from the one the CLI is exempt from elsewhere: sp:backup needs
no demo guard because whoever runs it already has config/config.xml, but the users this is
about have neither that file nor any way to read the environment of a process they do not
own. Both commands already take the same values from an environment variable and fall back
to a hidden prompt.

CommandBase gains two helpers, called once at the start of each command so the value is
gone before the work begins: cli_set_process_title() rewrites the argv memory, and the
operator is warned. The title is rebuilt from the real command line with only the named
options masked, rather than replaced wholesale, so a process still says what it is — and
the test runner does not lose its own name when the CLI tests exercise these commands.

It shrinks the window rather than closing it: the shell forks with the full argv before PHP
runs, and nothing here touches shell history. The options stay; removing them would break
documented automation for no gain the environment variable does not already offer.
@blaipr
blaipr merged commit 72ee3dd into main Sep 3, 2026
8 checks passed
@blaipr
blaipr deleted the fix/a-master-password-is-not-passed-on-the-command-line branch September 3, 2026 02:05
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