Subject: | File::Temp and unsafe shell characters |
The File::Temp documentation doesn't mention anything about the
characters used in the generated temporary file, and whether they
might be unsafe to use in shell commands or single-argument open().
This matters because it's often a tempting thing to say
# Create a temporary file with some content.
my ($fh, $filename) = File::Temp::tempfile;
print $fh 'some text' or die $!;
close $fh or die $!;
# Now for whatever reason we re-open the file.
open FH, $filename or die $!;
# Alternatively, we might do something like this:
system("gzip $filename") && die;
However, the above code is buggy; File::Temp doesn't make any
guarantee that the filename returned will be shell-safe. For example
% mkdir '>'
% mkdir '>/etc';
% TMPDIR='>/etc' perl -MFile::Temp -e '($fh, $filename) = File::Temp::tempfile; print $filename'
In this scenario, if an attacker can create a directory containing
shell characters and then set TMPDIR, he can cause the above program
to write a file in /etc or another directory of his choice. Or he
could put backticks into the directory name to run an arbitrary
command when it is used in system(), etc.
This is not strictly a bug in File::Temp because the documentation
does not make any promise that the filename returned will be safe.
But in the absence of an explicit warning programmers might assume so;
I know I did.
So I would like to request one of three things:
- Update the File::Temp documentation to note that the filename
returned is not guaranteed shell-safe and you should check it first
before using it in one-argument system(), open() etc.
- Consider adding a safe mode where the filename returned is
guaranteed not to contain any nasty characters. Presumably if the
tempdir returned by File::Spec contains these characters then
File::Temp should die rather than return an unsafe filename to the
user, if safe mode is on.
- Consider making safe mode the default.
A quick search for vulnerable code found this example from Bioperl:
($tfh,$tfile) = $obj->tempfile();
print $tfh ("test1");
close($tfh);
open(IN, $tfile) or die("cannot open $tfile");
I am sure there are many other instances of the same bug, which will
sometimes be exploitable.