help-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

How to safely print a variable with secret value to stdout?


From: Philippe Cerfon
Subject: How to safely print a variable with secret value to stdout?
Date: Thu, 12 May 2022 02:36:20 +0200

Hey.

How can one safely print the contents of a shell variable to stdout,
when the variable might contain secret data (e.g. a passphrase)?


I know that keeping secrets in variables can be problematic, but the
assumption is, that root on the system can be trusted, as can the user
itself (so /proc/*/environ, memory debuggers and the like shouldn't be
a problem) - but other users can't be.

Other ways of keeping the secret data are also no alternative here,
the secret data comes as a variable and I have to live with that.


1. Doing something like:

foo --password "$secret"

where foo is program and not a function or so, is obviously bad, as
other users would see the secret data in the process list.


2. When printf is a shell built-in doing:

printf '%s' "$secret" | foo --password-from-stdin

should be safe and not show up in the process list or so.

The problem is that the code might be run on shells where this isn't
guaranteed and then printf could end up being /usr/bin/printf and
again show up in the process list.
Therefore, bash's "builtin" cannot be used either.

Is there another way to guarantee that only built-in printf would be
used (so to at least fail, instead of leaking the secret data)?

I was thinking about something like:

PATH='' printf '%s' "$secret" | foo --password-from-stdin

but I'm not sure whether this portably works as I'd intend? As far as
I understood, the standards leave some freedom of what shells do
there.
E.g. if printf was implemented as a function, then that may see the
PATH='' but internally just call /usr/bin/printf "$@"


3. I was thinking about doing something like:

FOO="$secret" python3 -c "import os; print(os.environ['FOO'])"
or
FOO="$secret" perl -E 'print $ENV{FOO}'
or
FOO="$secret" awk 'BEGIN{print ENVIRON["FOO"]}'

As far as I can tell, these should also be safe - but are quite ugly.


4. Not sure whether heredocs do it e.g.
instead of:

printf '%s' "$secret" | foo | bar

something like:

{ foo | bar } <<EOF
$secret
EOF

As I understand, it shouldn't matter when $secret contains EOF, but I
read it's not even guaranteed to be expanded at all (depending on the
shell used). Plus I'm not so sure whether that would mangle up any
escape sequences or if non-text characters are used.


Any further ways that would work in bash and others? Or which is the
recommended one?


(3.) and (4.) are somewhat ugly, what I'd prefer was if (2.), the
built-in case, would work as I presume.

Is there a portable way to check whether printf was built-in or not?
'type' cannot be used because it's output is not portable, just as
with 'command -V'.


Is it safe to assume that 'command -v printf' is portably telling that
printf is built-in when it's output doesn't start with a forward
slash?

I found: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/command.html
which says:
|* Utilities, regular built-in utilities, command_names including a
|<slash> character, and any implementation-defined functions that are
|found using the PATH variable (as described in Command Search and
|Execution), shall be written as absolute pathnames.
|
|* Shell functions, special built-in utilities, regular built-in
|utilities not associated with a PATH search, and shell reserved words
|shall be written as just their names.

But I don't quite understand how that applies to printf. I'd assume
it's a regular built-in utility (if at all) but one with or without
PATH search?
How could a built-in utility use PATH search at all, doesn't seem to
make sense to me.


Thanks for any help!

Regards,
Philippe



reply via email to

[Prev in Thread] Current Thread [Next in Thread]