From a fundamental viewpoint the architectural design here is braindead.
Apache has all the environment variables you're going to need and it just gave them do you Mr. CGI program.
Now, you involve a shell and the shell interpreter, before doing what you told it to do, is gong to evaluate some essentially Unix command line environment variables first - that you don't know about and affect every single website on that machine which could conceivably be in the tens of thousands. Here's where it gets ugly - if one of those Unix command line environment variables is, instead of s string of letters, if rather is is a piece of codes stored in an environment variable (turns out you can do this) then when the shell interpreter evacuates that particular environment variable, it end up running whatever code somebody stored in that envirnoement variable.
But this is not appropriate for being called from within a CGI program, this is only appropriate from being called from the command line (there are some who disagree and would perhaps say they're never appropriate).
The problem there is the web programmer handling both sides of the CGI interface has no control over environment variables added by shell preprocessing of environment variables. So, shut it off. No environment variables for you if you've been called by a CGI program, that functionality is not available do you.
If a shell is being called from a CGI, it needs to ignore any environment variables. They'll have to be passed specifically as parameters to the target.
Fotunately it's just bash:
Sun Sep 28 18:19:20 ~/ % env 'x=() { :;}; echo vulnerable' 'BASH_FUNC_x()=() { :;}; echo vulnerable' csh -c 'echo test' test Sun Sep 28 19:08:08 ~/ % env 'x=() { :;}; echo vulnerable' 'BASH_FUNC_x()=() { :;}; echo vulnerable' sh -c 'echo test' test
/bin/sh
and /bin/csh
are safe.