I'm building a number of automated scripts that will run within an encrypted environment (full disk encryption).

Many commands in both Windows and *nix have two ways of entering sensitive information such as passwords. In one mode, the program prompts the user for the password, and in the other, the password is specified using an option argument.

When writing a shell script, the command can be automated using either of these processes. In the first case, the command is executed, then standard in (stdin) is redirected and the password is piped into the program when prompted. In the second case, the password is specified as an argument to the program.

Is one of these inherently more risky than the other? Are there any trade-offs to be aware of? In either case, I'm asking specifically about the method of supplying the password, not the riskiness or vulnerability associated with storing the password on disk.

Here is an example in Python, using the CLI versio of VeraCrypt:

Redirecting stdin:

cmd = ['veracrypt', "--text", partition, mount_point]
input_file = open_file()
vc_call = subprocess.run(cmd, stdin=input_file)

Passing the password as an argument:

password = get_password_from_file():
cmd = ['veracrypt', "--text", "--non-interactive", "--password", password, partition, mount_point]
vc_call = subprocess.run(cmd)


I'm not sure if it matters, but on *nix, commands can be executed directly as system calls. In the above code, neither of the calls to subprocess.run() were given a shell=True option, which would cause the command to be executed within the default shell. My understanding is that on Windows, all commands must be run through the cmd shell. This could make a difference between the the two options, but I'm not sure how.


Passing it via stdin is more secure, since arguments are visible in the process tree.

Passing a secret value as an argument is typically more risky. Whenever something is passed as an argument, all other processes running under the same user (and sometimes all other users' processes, period) will be able to view the arguments for each process. This is why you can see arguments by running ps aux. Passing a value via stdin, on the other hand, sends it through a file descriptor. This descriptor will not be readable by unprivileged processes. If your threat model involves other malicious, local processes, you should send the sensitive material through stdin.

Passing data through stdin involves passing it through a file descriptor which the program can read using standard IO calls. In this case, it will be just as secure as opening a file to read from it. Command line arguments, on the other hand, are kept in a process' argv in memory. A program simply has to access that address of memory to view the arguments. This data is, however, visible to other users via that process' /proc/<pid>/cmdline. This is actually also the case for environmental variables on some systems (especially older *nix systems), so passing secrets through the environment is not necessarily a good idea either.

| improve this answer | |
  • 2
    Great answer covering all bases with specific examples. Personally never realized that ps directly exposes all arguments originally fed to processes... Pretty wild in this context and very good to know. – AJAr Jul 21 '18 at 8:56

On Unix-like systems, command line arguments can leak in various ways. They are usually visible to other processes, even processes that are not running as the same user. (Some Unix variants, e.g. certain hardened Linux configurations, can hide command line arguments to other users.) They may be stored in audit logs.

I don't know for sure about Windows but the risks are about the same.

Passing information through a pipe (so that the process receives it on a standard input) will not leak outside the sending and receiving process unless you take special steps like running your script in a debugger.

Given a choice, there is a very clear order of disminishing risks of data leakage: pipes are safe, environment variables are usually safe if the subprocess doesn't spawn other subprocesses, command line arguments should not be treated as confiential.

| improve this answer | |
  • 1
    Environmental variables are not safe on most Linux systems, since they are exposed in proc via /proc/<pid>/environ. Sometimes it is visible only to the same user (not just the same process), other times it is visible to every process. The environment should never contain secrets. – forest Jul 21 '18 at 8:29
  • @forest On any remotely modern unix system, environment variables are never visible to different users, unlike command line arguments. – Gilles 'SO- stop being evil' Jul 21 '18 at 8:32
  • Yeah I think you're right. I'm just going off of conventional wisdom from the days when ps was setgid and those times are indeed behind us. Perhaps it's superstition, but I still consider the environment a very risky place to pass secrets, merely because it was never intended to be secure (so caveats could be lurking around any corner, especially on other modern *nix systems). – forest Jul 21 '18 at 8:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.