The most common security vulnerability in CGI programs is that the remote user is able to trick the CGI into running programs by cleverly entering them in the WWW Form. The best way to illustrate the problem is with a few different examples. C example --------- The most well-known example exploits a common implementation of the UNIX popen() call, and affects primarily C programs. popen() allows the programmer to start up a command, and read from or write to it as if it were a file. The most common implementation of popen() starts a shell program and passes the entire command to that shell to be run. Now imagine a CGI that uses popen to process user input. This simple example is a portion of the code to provide web access to the finger program: sprintf(command, "finger %s", userinput); fp=popen(command,"r"); /* "r" means we will read from the command */ The person on the web enters a local username, and finger will be run on that person. If they enter "joe", then "finger joe" will be run and the results returned. If they enter "joe; cd /; /bin/rm -rf *", then the command that will be run is "finger joe; cd /; /bin/rm -rf *" If the web server is running as root, your entire local file system is destroyed. Carriage returns or line feeds may be substituted for the semicolons to achieve the same affect. Or pipe symbols, or ampersands. Depending on implementation of the popen() call, other special shell characters may also be interpreted, for instance the user could enter "joe `xterm -display foo:0`" with the hope of having everything inside of the backticks executed. popen() is not the only problem - be careful of using user input anywhere, and think of how the user might exploit the situation. For instance, if the user input is used as a directory path element in an open() call then the user could enter "../../../../../etc/passwd", and end up with a copy of the password file, instead of the intended file. Perl Script example ------------------- Perl has the same problem with it's open command the C has with popen. The perl open allows pipes to be opened, and will gladly interpret user input as if it were perl syntax. The set of problem characters is similar. In addition, perl has a very handy eval statement. eval lets you take a string and execute it as if it were perl instructions. Bourne Shell example -------------------- Approaches to dealing with the problem -------------------------------------- One approach would be to come up with a list of all possible trouble makers, and strip them out or reject requests that include them. One problem with this approach is you might tend to forget one of them, because the list is not trivial. Depending on circumstances, slashes, backslashes, quotes, the question mark, even the comma may cause unexpected behaviour in a program that didn't plan for it. You could approach it from the other end - make the screening specific to it's intended use - for instance only allow numbers in a numeric field, or only allow letters in names. This is fine, if the field doesn't need to have special characters, but what if you have a form where the user needs those characters? The best approach is simply to avoid at all cost calling outside programs or performing evals anywhere in a CGI.