It is sometimes necessary to create temporary files or directories while shell scripting. There are a lot of ways to do this, but arguably the safest and easiest is the mktemp utility. In this tutorial we will look at some of the security concerns that are introduced when using temporary files. We will also outline some best practices and how to use the mktemp utility to safely create temporary files to be used in shell scripts.

Jump directly to "How to Create Temporary Files with mktemp"

You may also enjoy "Managing Temporary Files & Directories with systemd-tmpfiles"

Security Concerns While Using Temporary Files

As you write more and more scripts it is inevitable that you will find a need for temporary files or directories. While they can be a useful tool, some care should be taken when creating temporary files.

Information disclosure, false data injection, race conditions and file clobbering are all very real threats when using temporary files.

A Simple Redirect is a Mistake

Simply redirecting output to a file (especially in tmp) is problematic. The tmp directory by default is insecure because it is world writable. If you simply redirect output to a file in the tmp directory, it will be world-readable by any user.

$ cat /etc/redhat-release > /tmp/release.txt
$ ls -lrt /tmp/
-rw-rw-r--. 1 savona savona 38 Apr 22 22:49 release.txt

Using simple redirects to directories other than tmp is safer, but can introduce other security and functionality concerns.

Known or Predictable Temporary File Names

If an adversary knows, or can reliably predict, the naming convention of your temporary file this creates an environment perfect for symlink attacks. This may allow for information disclosure or false data injection. Someone could potentially use symbolic links to cause denial of service (overwriting files the OS or services depend on), capture your data or feed your script some malicious data.

Using an unknown and unpredictable temporary file naming convention is imperative.

Cleanup of Residual Data

I have seen a lot of scripts end with the rm command used to clean up temporary files. This sounds like a good idea, but what if some error causes the script to exit prematurely? Also, long scripts often have several exit points where the script can end for a multitude of reasons. You would need to capture all of those exit points and ensure you have a cleanup command ready.

These are just some of the reasons you need a good cleanup function in your scripts. An inferior cleanup solution can leave temporary files unprotected.  These orphaned files may contain sensitive or otherwise valuable data and could be particularly susceptible to attacks by a variety of bad actors.

Best Practices for Using Temporary Files

  • Check if the file exists (or symlinked) before creation
  • Ensure the temporary file has been created successfully
  • Create a file with restrictive permissions
  • Use an unknown or unique naming convention
  • Delete your files on exit (trap)

Using mktemp will help follow best practices when creating temporary files or directories. It will not check if the file exists or symlinked before creation. But, the unique file name generation paired with an effective cleanup mechanism should be enough to mitigate the risk of symlink attacks and other security concerns.

Adding a check to ensure the temporary file is successfully created is a simple best practice to implement. If the file cannot be created for some reason (permissions, full file system, etc..) this check will save you from creating error conditions or other compounding issues.

Creating a file with correct permissions is key to securing your data in temporary files. The mktemp utility, by default, sets the permissions to be only read/writable by the owner. This removes the need to make umask changes or use chmod in your script, which are prone to errors and can possibly cause a race condition.

If mktemp can successfully generate a unique filename, the file (or directory) is created with file permissions such that it is only readable and writable by its owner (unless the -u flag is given) and the filename is printed to standard output.

- mktemp manual

Lastly, using an exit trap will ensure your cleanup function runs and all files are deleted regardless of the scripts exit status.

Implementing Best Practices for Temporary Files

In this section we will show you several ways to implement best practices when creating temporary files and directories.

Using mktemp can resolve three of the best practices we discussed above. It mitigates the need to check if the file exists because of it's random name generation, it sets restrictive permissions automatically and uses an unique and hard to predict naming convention.

Creating Temporary Files with mktemp

Creating a temporary file with mktemp is simple. You can test this on the command line by simply calling the binary.

$ mktemp 
/tmp/tmp.i2oiUVhHir

$ ls -l /tmp/tmp.i2oiUVhHir
-rw-------. 1 savona savona 0 Apr 22 19:57 /tmp/tmp.i2oiUVhHir

As you can see, a file has been created in /tmp named tmp.i2oiUVhHir and the permissions have been set to read and write access for only the owner (u+rw).

If you want to use this in a bash script, you can easily set a variable with the tmp file name.

#!/bin/bash
TMPFILE=$(mktemp)
echo "Our temp file is $TMPFILE"

Creating Temporary Directories with mktemp

If you want to create a directory instead of a file, simply add the -d (--directory) option.

$ mktemp -d
/tmp/tmp.Wcau5UjmN6

Specifying an Alternative Directory for mktemp

By default mktemp will use the directory specified in the $TMPDIR variable. If that variable is not set mktemp will use the /tmp directory.

You can override this functionality and specify the directory in which you want the temporary file created by using the -p (--tmpdir) option.

$ mktemp -p /home/savona/
/home/savona/tmp.FOKEtvs2H3

Specifying an Alternative Filename (Template) for mktemp

The mktemp utility will use tmp. (tmp-period) followed by ten random characters for it's file name. You can specify a template to use in file name creation. The template you specify must contain at least three consecutive X (capital X) characters at the end for randomization. We suggest using a minimum of six.

$ mktemp -t mytemp.XXXXXXXX
/tmp/mytemp.yZ1HgZV

Ensuring the File is Created

It is good form to tell the script to exit if it cannot safely create the temporary file for some reason. Here we will use the OR operator to exit the script if it fails to create the file.

#!/bin/bash
TMPFILE=$(mktemp)|| exit 1
echo "Our temp file is $TMPFILE"

This line will attempt to create a temporary file (mktemp) and store it in the variable $TMPFILE, if it is unsuccessful (|| = OR) it will exit with a code of 1 (exit 1) which is reserved for general errors.

Deleting the File After Script Exit

When creating temporary files it is usually desirable to automatically delete them after the script runs. We already spoke about why simply using the rm command is a bad idea (see Cleanup Residual Data section above). This is where traps come in. You can set a trap at the beginning of your script to run a command on exit.

#!/bin/bash
trap 'rm -f "$TMPFILE"' EXIT
TMPFILE=$(mktemp)|| exit 1
echo "Our temp file is $TMPFILE"

A trap is an effective way to ensure a cleanup routine is completed on script exit. You can set the trap to respond to different signals like SIGHUP, SIGINT, etc. A trap can be useful for many different functions that you would like to execute when a script exits. To learn more about trap and see examples read "Using Trap to Exit Bash Scripts Cleanly".

Conclusion

Safely creating temporary files is an important part of effective scripting. In this article we covered some of the security issues that can arise from using the incorrect form of temporary files and how to correct them.

I hope you enjoyed the read, please show your support by following us on Twitter and Facebook. We also have a newsletter if you want Linux articles in your inbox.

Further Reading