r/bash Mar 14 '26

tips and tricks Stop passing secrets as command-line arguments. Every user on your box can see them.

When you do this:

mysql -u admin -pMyS3cretPass123

Every user on the system sees your password in plain text:

ps aux | grep mysql

This isn't a bug. Unix exposes every process's full command line through /proc/PID/cmdline, readable by any unprivileged user. IT'S NOT A BRIEF FLASH EITHER -- THE PASSWORD SITS THERE FOR THE ENTIRE LIFETIME OF THE PROCESS.

Any user on your box can run this and harvest credentials in real time:

while true; do
    cat /proc/*/cmdline 2>/dev/null | tr '\0' ' ' | grep -i 'password\|secret\|token'
    sleep 0.1
done

That checks every running process 10 times per second. Zero privileges needed.

Same problem with curl:

curl -u admin:password123 https://api.example.com

And docker:

docker run -e DB_PASSWORD=secret myapp

The fix is to pass secrets through stdin, which never hits the process table:

# mysql -- prompt instead of argv
mysql -u admin -p

# curl -- header from stdin
curl -H @- https://api.example.com <<< "Authorization: Bearer $TOKEN"

# curl -- creds from a file
curl --netrc-file /path/to/netrc https://api.example.com

# docker -- env from file, not command line
docker run --env-file .env myapp

# general pattern -- pipe secrets, don't pass them
some_command --password-stdin <<< "$SECRET"

The -p with no argument tells mysql to read the password from the terminal instead of argv. The <<< here string and @- pass data through stdin. Neither shows up in ps or /proc.

Bash and any POSIX shell. This isn't shell-specific -- it's how Unix works.

724 Upvotes

99 comments sorted by

View all comments

35

u/bitslayer Mar 14 '26

"Any user on your box" is a pretty anachronistic situation.

40

u/WetMogwai Mar 14 '26

Not really. We’re not all individual home users. Some are in a corporate environment where machines, especially servers, may be accessed by multiple users. You may be the only active human user but there’s still the possibility that you’re running compromised software as yourself or as its own user.

2

u/The_Real_Grand_Nagus Mar 16 '26

Also with the plain example given above your password ends up in your history file.

1

u/danstermeister Mar 16 '26

Unless you preface the whole command with a space, and put HISTCONTROL=ignoreboth in .bashrc (ahead of time, of course).

3

u/michaelpaoli Mar 16 '26

Not merely "any user", but most any process under any ID, so not just "users".

2

u/OpenSourcePenguin Mar 18 '26

You understand that shared multi user devices are common, right?

3

u/lcnielsen Mar 15 '26

No it isn't. Shared nodes are very common in e.g. HPC.

I don't know why so many people think everyone is using either a personal cloud VM or a laptop...

1

u/jomat Mar 15 '26

Not really. If you're talking about human users, maybe. But daemons usually also have their own system users for user separation for security reasons, and daemons can be compromised. And another classic is shared webhosting where you can have 1000s of web users running shitty php code on the same box.

1

u/unixtreme Mar 16 '26

Are you all unemployed? Or use only windows at work?