How to pass a password to a child process?

Process arguments are visible to all users, but the environment is only visible to the same user (at least on Linux, and I think on every modern unix variant). So passing a password through an environment variable is safe. If someone can read your environment variables, they can execute processes as you, so it's game over already.

The contents of the environment is at some risk of leaking indirectly, for example if you run ps to investigate something and accidentally copy-paste the result including confidential environment variables in a public place. Another risk is that you pass the environment variable to a program that doesn't need it (including children of the process that needs the password) and that program exposes its environment variables because it didn't expect them to be confidential. How bad these risks of secondary leakage are depends on what the process with the password does (how long does it run? does it run subprocesses?).

It's easier to ensure that the password won't leak accidentally by passing it through a channel that is not designed to be eavesdropped, such as a pipe. This is pretty easy to do on the sending side. For example, if you have the password in a shell variable, you can just do

echo "$password" | theprogram

if theprogram expects the password on its standard input. Note that this is safe because echo is a builtin; it would not be safe with an external command since the argument would be exposed in ps output. Another way to achieve the same effect is with a here document:

theprogram <<EOF
$password
EOF

Some programs that require a password can be told to read it from a specific file descriptor. You can use a file descriptor other than standard input if you need standard input for something else. For example, with gpg:

get-encrypted-data | gpg --passphrase-fd 3 --decrypt … 3<<EOP >decrypted-data
$password
EOP

If the program can't be told to read from a file descriptor but can be told to read from a file, you can tell it to read from a file descriptor by using a file name like `/dev/fd/3.

theprogram --password-from-file=/dev/fd/3 3<<EOF
$password
EOF

In ksh, bash or zsh, you can do this more concisely through process substitution.

theprogram --password-from-file=<(echo "$password")

Instead of passing the password directly through an argument or an environment variable

#!/bin/bash
#filename: passwd_receiver
echo "The password is: $1"

use the same argument or environment variable to pass a filename:

#!/bin/bash
#filename: passwd_receiver
echo "The password is: $(< "$1")"

Then you can pass either a permission-protected regular file (though that won't protect you from other processes running under the same user), or /dev/stdin and pipe it in (which AFAIK will protect you from other processes running under the same user):

 echo PASSWORD | ./passwd_receiver /dev/stdin 

If you use /dev/stdin here, it's imperative that it's a pipe. If it's a terminal, it'll be readable by other processes running under the same user.

If you already need to use your /dev/stdin for something else, you could use process substitution if you're on a shell that supports it, which is essentially equivalent to using pipes:

./passwd_receiver <(echo PASSWORD)

Named pipes (FIFOs) might look like they're the same, but they're interceptable.

These solutions are not perfectly secure either, but they might be close enough provided you're not on a memory constrained system that swaps a lot.

Ideally, you'd read these files (pipe is a file too) into memory marked with mlock(2) as nonswappable, which is what password handling programs such as gnupg generally do.

Notes:

  1. Passing filedescriptor numbers is theoretically just good as file as passing filenames, but filenames are more practical, because <() gives you a filename, not a filedescriptor number (and coprocs give you filedescriptors marked FD_CLOEXEC, which makes those filedescriptors unusable in this context).

  2. If you're on a Linux system where
    /proc/sys/kernel/yama/ptrace_scope is set to 0, then AFAIK, there's no bulletproof way of protecting yourself from other processes running under the same user (they can use ptrace to attach to your process and read your memory)

  3. If you only need to keep your password away from processes running under different (nonroot) users, then arguments, environment variables, pipes and permission protected files will all do.


No, environment variables are easily read too, and leak to child processes. pass it using a pipe.