As I understand it, generally it is considered safe to let anyone provide information that will be stored in an environmental variable. The shellshock vulnerability is an issue here because it means that code at the end of a function definition inside an environmental variable will be executed when a new instance of bash launches and you obviously don't want anyone to run any code they please on your server. Function definitions themselves are apparently not a security risk though and are allowed because they have to be explicitly called for their code to be executed.

My question is why can't a malicious user simply define a function, containing their malicious code as a common command like ls and then hope that the script (or whatever is being run) will use this command at some point?

An example of what I have in mind:

$ export ls='() { echo "doing bad things..."; }'
$ bash -c ls
doing bad things...

2 Answers 2


It is a security risk. That's generally why you can't do it when switching to another context (remote control of a system, changing users, etc).

If you have the ability to create any environment variable you want, there are any number of potential ways you can execute arbitrary code.
Take $LD_PRELOAD as an example. If you have the ability to set that variable, you can replace library functions, and stick your code in there. You can set the $DISPLAY variable, and redirect the X display the program connects to so that you get control of the app.

This is why things like sudo strip the environment of all variables. sudo only allows a few select variables through. And of those variables, it sanitizes them (it passes through the $TERM variable, but it won't if it contains unusual characters).

  • Wow, i'd always wondered why some huge scripts I do in BASH would have weird arcane failures when started with sudo, particularly around paths, which led me to check for sudo starts and block them, but I never knew why that happened and was a problem, thanks for the good explanation re sudo stripping out environmental variables.
    – Lizardx
    Dec 31, 2016 at 1:24

I'd say it is, when bash is your /bin/sh. It's a not feature of bourne shell, and I'd bet it's not a feature of posix shell either, in fact they might want to expressly forbid it.

Bash is really more of korn derivative shell, than a bourne shell, despite its name, and its the only Korn like shell that has the feature, and in my opinion it's kitchensink feature that has no practical virtues. Developers who avoid bash features for standards, like the bourne shell, the posix shell, or the ksh88 subset that modern shells have in common, or in other words, committed themselves to good practices, and standard idioms, are shocked when their software is on linux and mac and now potentially vulnerable, since the exploit authors are free to use the 'bashisms', despite their intents. As far improved compatibility, when invoked as /bin/sh, over other korn shell derivatives, it's only if /bin/sh is your login shell, or interactive shell, when bash behaves more like a bourne shell, than a korn shell, but when used in scripts you're free to do anything that bash can do, and it never complains or warns you that you are using features that really korn shell features, or unique to bash.

I'll try to persuade you that it's kitchen-sink feature, with 2 cases: you're an embedded dev, who makes devices like routers, network-attached-storage 1st bigger env, means more , memory, so, more cost, so less profits, so, if this was a reason to consider to using this feature of bash, shouldn't you instead use FPATH and autoload, ksh88 features instead? instead of passing the whole function byte for byte in the environment? You could even consider parsing and the pruning the environment wholesale, before it it gets to a shellscript that could misparse a variable, like just filter out ^$(.*)$ , and the like...

That does underscore what's unique about this, it doesn't matter what the variable is, and the script doesn't have to reference or use the variable, it could still be vulnerable.

exec /usr/local/myapp/support/someperlscript.pl

For everthing else under the sun, the above is should as safe as the perl script, you're not using the any variables how could you misparse any? Changing to

#!/bin/bash -norc
exec /usr/local/myapp/support/someperlscript.pl

Doesn't help either, this had nothing to with ENV or anything like it -- everybody gets burned because bash needs to be unique. The fact that bash version 2 has the issue, to me proves that nobody ever uses this feature for their applications, because otherwise it should not have lurked around this long. And what's worse there's basically no avoiding this feature . Here's an example with: with 'su -', which if you would ask someone, the explanation would be it discards the environment, check the man page, and you'll find just 99.9% . I tested that right way, since on this system /bin/sh is root's login shell, and /bin/sh is bash BUT, in this example I try to harden my .bash_profile. I renamed my existing for root (which is enabled), but my thinking was if su, then possibly sudo, anyway, I changed to this:

exec env -i TERM=vt102 LOGNAME=root USER=root HOME=/var/root /bin/ksh -i

So, I'm actually tossing the environment completely, and use a minimal env, and then running a shell that shouldn't have the issue, in place of current process. Then in place of the standard example try:

%dock='() { echo -e "\e[2t\c"; echo dockshock;} ; dock' su 

This illustrates how it has nothing to do with parsing any particular function, and an exploit can refer to and use, the function. You can imagine the function having logic to test if root, etc. In this case, it's just a modified form a function to iconify or dock a terminal window, using an escape sequence, that's pretty standard, so after I clicking to deiconify, I see dockshock -- but, so what? Now try this:

%TERM='() { echo -e "\e[2t\c"; echo dockshock;} ; TERM' su - 

And, guess what? The window gets sucked into the dock. Here's what it looks like afterwards..

%TERM='() { echo -e "\e[2t\c"; echo dockshock;} ; TERM' su -
# env
# echo $0

So, so, much for that! The exported functions actually have priority over rc scripts. You can't dodge it.

  • 1
    POSIX allowed exportable functions in draft 2, and disallowed them thereafter. The feature is insane.
    – mikeserv
    Sep 27, 2014 at 17:16

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.