Authors Top

If you have a few years of experience in the Linux ecosystem, and you’re interested in sharing that experience with the community, have a look at our Contribution Guidelines.

1. Introduction

In the Bash programming language, the eval built-in has a wide range of applications. That is, it can execute other commands, set shell environment, and perform variables substitution and indirection.

However, such a powerful tool should be used with care. We should be aware that its ability to parse arbitrary input as Bash commands may cause severe security issues.

2. Basic Use of eval

Let’s run Bash commands through eval:

$ eval "pwd; echo Hello $USER; date"

/home/joe
Hello joe
Sun Mar 27 01:01:06 PM EDT 2022

Let’s notice the expansion of the environment variable ‘USER’.

For more information, we should type help eval in the terminal.

3. Setting Variables in Current Shell

The eval built-in doesn’t spawn a child process. Therefore, we’re going to set variables for the current shell with it.

Let’s assume that the file ‘vars’ contains variable definitions:

echo "Setting variables"
foo=FOO
bar=BAR

Now, let’s put these variables into the current shell:

$ eval "$(cat vars)"
Setting variables

$ echo $foo $bar
FOO BAR

The quotes around the cat‘s output save newlines which play the role of the command separator.

We can use source for the same purpose instead.

4. Variable Expansion in String

Now, let’s substitute Bash variables embedded in a greeting template hello.txt:

Hello $USER! Welcome to $HOSTNAME.

So let’s check:

$ eval echo \"$(cat hello.txt)\"

The output of echo is wrapped in quotes. Thus, Bash doesn’t interpret it as commands.

However, variable substitution still takes place:

Hello joe! Welcome to fedora.

Let’s notice that we can use envsubst as well.

5. Variable Indirection With eval

We’re going to define a Bash variable dynamically without knowing its name ahead.

So, let’s print the value of the last argument passed to the script last_arg:

#!/bin/bash

echo echo \"\${$#\}\"  # just for test
eval echo \"\${$#\}\"

Now, let’s test it:

$ ./last_arg foo bar foobar

echo "${3}"
foobar

Let’s catch that firstly we substitute the variable ‘#’. Its value is the number of arguments, 3 in our case.

Then, we create a new variable ${3} which refers to the third script’s argument.

6. Security Issues

When using eval, we should be aware of security issues it brings about.

Let’s consider a not safe variable indirection:

$ foo=bar bar="Hello all *"
$ eval echo \$$foo

Hello all hello_from_evil.txt hello.txt vars

Instead of just printing the bar‘s value, we accidentally evaluated echo * and listed files in the working directory.

As another example, let’s change our greetings slightly to hello_from_evil.txt:

Hello $USER! Welcome to $HOSTNAME. The system is up to ";date"

Now the output of eval echo \”$(cat hello_from_evil.txt)\” is different:

Hello joe! Welcome to fedora. The system is up to
Sun Apr  3 08:00:32 AM EDT 2022

Here date is a mock-up of an ‘evil’ command.

Undoubtedly, it’s not our intention to run this or any other command in this case.

7. Basic String Sanitization With Double Quotes

In the variable indirection cases, we should use double quotes as must-be protection:

$ foo=bar; bar="Hello all *"
$ eval echo \"\$$foo\"
Hello all *

8. More Sanitization by Removing Content’s Quotes

Now let’s safely process the string from the hello_from_evil file.

First, let’s examine the eval‘s argument using echo instead:

$ content="$(echo \"$(cat hello_from_evil.txt)\")"
$ echo "$content"
"Hello $USER! Welcome to $HOSTNAME. The system is up to ";date""

So the culprit is a freed command separator.

Therefore, we’re going to remove all quotes using the replacement pattern ${content//\”}:

$ eval echo \""${content//\"}"\"
Hello joe! Welcome to fedora. The system is up to ;date

9. Security Bottom Line

For security reasons, we should never pass raw users’ input to eval. It opens wide our script for uncareful or malicious actions.

Next, we should not overestimate string sanitization because it might lead to a false sense of safety.

Finally, we should ensure that eval‘s input is limited to remaining under our control data with well-defined corner cases.

10. Conclusion

In this article, we looked through the applications of eval. First, we just run the Bash commands from a string.

Then we played with Bash variables. First, we learned how to substitute variables inside a string. Then, we populated Bash environment with variables collected in the file.

Next, we performed variable indirection creating Bash variables in runtime.

Finally, we blew the whistle on security issues related to the uncareful use of eval.

Authors Bottom

If you have a few years of experience in the Linux ecosystem, and you’re interested in sharing that experience with the community, have a look at our Contribution Guidelines.

Comments are closed on this article!