perl -pe 's/abc/$ARGV[0]/ge'
Are there any security concerns with this approach? I mean is it possible to give such positional parameter value which causes perl to execute an unwanted function?
In
perldoc perlop
in the section
Regexp Quote-Like Operators
it explains
- e Evaluate the right side as an expression
- ee Evaluate the right side as a string then
eval
the result.
But this isn't entirely true. In both cases the "right side"—the replacement—is evaluated as if it were a do
block†. In the first case the result provides the replacement string, while in the second the result is passed to eval
and the result of that provides the replacement string. There is no distinction whereby the replacement is evaluated as an "expression" in the first place and as a "string" in the second.
Both /e
and /ee
allow for any valid Perl code sequence, including loops, conditionals, and multiple statements, and aren't limited to a single expression
There's never anything wrong with $ARGV[0]
in isolation. Tainted strings become dangerous only if you execute them, either as Perl, using eval
, or as shell code using system
, qx//
, or backticks. So it's fine in the replacement part of a substitution with a single /e
modifier
But if you use something else in the replacement, for instance
perl -pe 's/abc/qx{$ARGV[0]}/eg'
then that parameter will be executed as a shell command, so it clearly isn't safe. But then nor is
perl -pe 's/abc/unlink glob "*.*"/eg'
so you have to be sensible about it
What is dangerous is the double-e modifier /ee
, which treats the replacement as a Perl do
block and then does an eval
on the result. So something like
s/abc/$ARGV[0]/eeg
is very unsafe, because you could run your code like this
perl -pe 's/abc/$ARGV[0]/eeg' 'unlink glob *.*'
With just a single /e
this would just replace abc
with the string
unlink glob *.*
in $ARGV[0]
. But using /ee
, the string is passed to eval
and all your files are deleted!
Remember this:
†
This is why I choose to use braces to delimit substitutions that use one of the /e
modes. With
s{abc}{ $ARGV[0] }ge
the replacement looks much more like the block of code that it is than if I had used the usual slashes