Why is it insecure to use the combination of -execdir
action of find while using -exec
isn't?
When I'm running the below command I'm getting the following prompt message:
/path/to/currentDir/$ find . -type f -name 'partOfFileNames*' -execdir rm -- {} +
find: The current directory is included in the PATH environment variable, which is insecure
in combination with the -execdir action of find. Please remove the current directory
from your $PATH (that is, remove "." or leading or trailing colons)
What may caused this prompt appearing?
You could run the wrong program. Someone could make you run their program.
The
-execdir
action runs your command from the directory that contains the file(s) found. When$PATH
contains relative paths, such as.
or anything that doesn't start with/
,-execdir
is insecure because a directory where a file is found (or another directory resolved relative to it) could also contain an executable of the same name as the one you are trying to run. That potentially untrusted executable would then get run instead.This could be deliberately exploited by another user to cause you to run their program, which might cause harm or breach data security, instead of the program you are trying to run. Or, less often, it might simply result in the wrong program inadvertently being run, even without anyone trying to make the problem happen.
If everything in your
PATH
environment variable is an absolute path, this error should not occur, even if the directory you're searching and-execdir
ing from is contained inPATH
. (I've checked that this works.) If you believe you don't have any relative directories in$PATH
but are still getting this error, please update your question with details including the output ofecho "$PATH"
.A concrete example.
As an example of what could go wrong, suppose:
.
in her$PATH
because she wants to be able to run programs in whatever directory she'scd
'd to, without bothering to prepend their names with./
./home/eve/shared
with Alice..c
files Eve has shared with her.So Alice runs:
Unfortunately for Alice, Eve has created her own script, named it
wc
, set it executable (chmod +x
), and placed it clandestinely in one of the directories under/home/eve/shared
. Eve's script looks like this:So when Alice uses
find
with-execdir
to runwc
on the files Eve has shared, and it gets to files in the same directory as Eve's customwc
script, Eve'swc
runs--with all of Alice's privileges!(Being crafty, Eve has made her
wc
script act as a wrapper for the systemwc
, so Alice won't even know something has gone wrong, i.e., thatdo_evil
was run. However, simpler--and also more sophisticated--variations are possible.)How
find
prevents this.find
prevents this security problem from happening by refusing to take the-execdir
action when$PATH
contains a relative directory.find
offers two diagnostic messages depending on the specific situation.If
.
is in$PATH
, then (as you've seen) it says:find: The current directory is included in the PATH environment variable, which is insecure in combination with the -execdir action of find. Please remove the current directory from your $PATH (that is, remove "." or leading or trailing colons)
It probably has a special message for the
.
case as it's especially common.If a relative path other than
.
--say,foo
--appears in$PATH
and you runfind
with-execdir
, it says:find: The relative path `foo' is included in the PATH environment variable, which is insecure in combination with the -execdir action of find. Please remove that entry from $PATH
It's better not to have relative paths in
$PATH
at all.The risk of having
.
or other relative paths in$PATH
is especially heightened when using a utility that automatically changes the directory, which is whyfind
won't let you use-execdir
in this situation.But having relative paths, especially
.
, in your$PATH
is inherently risky and is really best avoided anyway. Consider the fictional situation in the example above. Suppose instead of runningfind
, Alice simplycd
s to~eve/shared/blah
and runswc *.c
. Ifblah
contains Eve'swc
script,do_evil
runs as Alice.There is a much detailed information here. Another excellent reference is here. To quote from the first reference:
From second reference:
The main problem is with the value of system variable
PATH
which contains relative folders in it, so for security reasonsfind
command won't allow you to execute binaries, because potentially it can execute wrong programs.So for example, if you have your current dir in your PATH as per warning which you get:
and you'll run your command:
in case you'll have local script (
rm
with executable flags) containingrm -fr /
in it, it can remove all your files, because instead of executing expected/bin/rm
, you'll executerm
from the current dir, so probably it's not what you wanted.As a side note, this is known issue in Travis CI (GH #2811) when it fails with the error:
So the solution is to remove affected entry from PATH variable, e.g.
as proposed by drogus. The progress of this bug, can be followed at GH #4862.
Here is Bash version workaround:
Example usage (passing filtered
PATH
to specific command):Set
PATH=/usr/bin
This is not ideal, but it tends to solve most use cases, supposing both
find
and the program to be used (rm
here) are in that directory:You can just add any missing PATHs as needed.
xargs
andbash -c cd
workaroundOK, I give up:
sed
workaroundA bit less nice than the previous workaround:
A testcase:
For
rename
specifically, you can also work around with some Perl regex-fu: https://stackoverflow.com/questions/16541582/finding-multiple-files-recursively-and-renaming-in-linux/54163971#54163971RTFS hope crushing
For those who have hopes that there exists a way to ignore
find
's opinionatedness, let me crush that with some source:From that we see that there seems to be no way to turn off the path checking.
The exact rule it checks is: fail if the
PATH
is either empty or does not start with/
.The workaround is to pass custom PATH before the command, e.g.
Above workaround will prevent loading the global
$PATH
, but our own.Here is another example (more flexible), assuming we want to run
cat
command:or:
by running
$(dirname $(which cat))
we calculate where our command to run is located.