Let's say I have a bash script that acts as a config file for another bash script:
config.sh:
verbose=yes
echo "Malicious code!"
name=test
script.sh:
source config.sh
echo "After sourcing: verbose='$verbose', name='$name'"
The problem is, this isn't very secure, as anything put in config.sh gets run:
$ ./script.sh
Malicious code!
After sourcing: verbose='yes', name='test'
To make it more secure, I thought I'd grep out assignment operations and only execute those. I would accomplish by passing source
a "here document":
script.sh:
source <<EOF
$(grep -P '^\s*\w+=' test.sh)
EOF
echo "After sourcing: verbose='$verbose', name='$name'"
(Yes, I know the regex isn't that strong; it's just a placeholder.) Sadly, source doesn't seem to play well with here docs:
./script.sh: line 1: source: filename argument required
source: usage: source filename [arguments]
After sourcing: verbose='', name=''
Obviously I could do any number of things to get config data from a file, and that's likely more secure anyways.
But I'm still left with this itch; I want to figure out if what I've tried can work. Any suggestions?
<<EOF
) acts like an ordinary input redirection (< file
), andsource < file
doesn't work --source
needs to have a filename argument. Therefore, you need process substitution (<(command)
), which looks like a filename argument.while IFS== read -r var value; do case $var in |*[!0-9A-Z_a-z]*) complain;; *) eval "config_$var=\$value";; esac; done <config
(warning: typed in my browser, test it!) Don't forget not to allow importing variables likePATH
,IFS
, … A prefix likeconfig_
is a safe approach./dev/fd/[num]
. Emulating this is simple:3<<HEREDOC . /dev/fd/3\n*file contents*\nHEREDOC\n
. Process substitution usually is a pipe, whereas heredocs are usually tmpfiles the shell deletes before handing them off - so they only exist as descriptors. indash
they are pipes. the other big difference is you can specify fd[num]
for heredocs.