Apache > HTTP Server > Documentation > Version 2.5 > Modules

Apache Module mod_taint

Available Languages:  en 

Description:Perl-like taint checking and untainting of HTTP request data, including defence against "Shell Shock" environment variables reaching bash.
Module Identifier:taint_module
Source File:mod_taint.c


Perl's concept of tainted (untrusted) data and of proactively untainting it is a powerful security tool, and is strongly recommended in all Web-facing Perl applications. This module provides a similar capability within the web server, and may be useful in protecting web applications that don't have untainting built in.

mod_taint untaints request headers and other fields in the HTTP or HTTPS request. It does not currently understand Form data (though you can use it to check unparsed data in a Query String), nor does it touch a request body (as sent in POST and PUT requests). These capabilities and others are available from third-party solutions such as Ironbee.




Shell Shock

mod_taint was updated in September 2014 to provide an additional option to apply an untainting rule to all request headers, and a special option "shellshock" to defend specifically against the possibility of Shell Shock attacks reaching a shell where they might compromise the system. By sanitising input, it protects equally against different attack paths such as CGI, SSI, external filters, scripting modules, etc. The server will reply with 400 (Bad Request) to any request that gives rise to a potential shell shock attack.

Untaint shellshock



The Untaint applies an untainting rule to a specified Request field or header. An untainting rule applies a Perl-compatible regular expression match to a request field. The rule may either modify (or replace) an unacceptable input, or reject the entire request.

For example, to verify that the request is an acceptable filename according to a simple naming convention limited to alphanumeric characters, "/" separator, and an optional ".extension":

Untaint File ^(/\w+)*/\w*(\.\w+)?$

This rule will return HTTP status 400 (Bad Request) if the filename contains any 'interesting' characters. We can then use an ErrorDocument for 400 to tell any human user what's wrong.

We could also return a different error status. In this case we are checking the filename, so we might prefer to reply with 404 (Not Found) on failure, even if the request is a valid but unacceptable filename:

#Return Not Found for "/foo/../bar/index.html"
#even if /bar/index.html is a perfectly good file and allowed
Untaint File ^(/\w+)*/\w*(\.\w+)?$ 404

A second form of the directive doesn't reject the request outright, but modifies the request data to a form that's known to be acceptable to the application, using regular expression substitution. Instead of rejecting the request, we could strip out any disallowed characters, and allowing single but not consecutive dots:

Untaint File s#[^(\w/\.)+]##g
Untaint File s#\.\.+#.#g

We can also do exactly as Perl does, and actively untaint data by substituting input matched to a presceibed pattern. Suppose for example we have an application that expects a session ID in PATH_INFO. Other PATH_INFO components may exist but should be stripped. We do this by substituting a precisely-defined match. Since this is a substitution, we also have to specify that absence of a match is an error, which for our application is 403 (Forbidden):

Untaint PATH_INFO s#.*/(session=[A-Z]{2}\d{5}[A-Z])\b.*#$1#i 403


TaintInherit Directive

Description:Whether to inherit untainting rules into this context
Syntax:TaintInherit On|Off
Default:TaintInherit On
Context:server config, virtual host, directory, .htaccess

Where Untainting rules are defined in a context (e.g. a <Directory>), they will normally be used alongside those already defined before the context. Setting TaintInherit Off will change this to prevent pre-existing untainting rules being applied, so only those in the immediate context are used.


Untaint Directive

Description:Define an untainting rule
Syntax:Untaint request-field [regexp-operation] [status-code]
Context:server config, virtual host, directory, .htaccess

This directive defines an untainting rule that will be applied to request-field on every HTTP request.

The request-field argument may be any of the following fields of the HTTP request, or any HTTP request header. The latter are accessed in the same manner as in CGI and other scripting protocols, by prepending HTTP_ or HEADER: to the header name. For example,

Untaint HTTP_COOKIE /sessionid=\d+/
Untaint Header:COOKIE /sessionid=\d+/

enforces a numeric "sessionid" Cookie header.

Apart from the request headers, request fields that can be tested in an Untaint directive are:

Note that some of these fields may be NULL: this depends on your confiuration. If this happens, untainting rules may be applied to an empty string, which may not be what you want!

The second argument is a Perl-style regular expression operation. It takes one of two generic formats:

Match - m/regexp-pattern/flags
The Match operation enforces a match, and aborts the request if the match fails. An aborted request will by default return HTTP status 400 (Bad Request) to the Client. Note that the leading "m" is optional, and the delimiters may also be omitted if there are no flags.
Substitution - s/regexp-pattern/replacement-string/flags
A failed match in a substitution rule will not abort the request unless the optional final argument is set.

Flags supported are the characters imgsn^$. The first four are identical to their Perl usage (n.b. /s is not supported in HTTPD versions earlier than 2.3.9). The n flag suppresses support for backreferences, for a tiny performance boost. The ^ and $ flags set PCRE's NOTBOL and NOTEOL options respectively to say the match string is not the beginning/end of a line.

The optional third argument is an HTTP status code to return to the Client if an Untaint directive fails to match. The default is 400 (Bad Request) for a Match rule, and None for a Substitute rule. Do not use this in a multiple Substitution (i.e. with the /g flag).

Available Languages:  en 



This is not a Q&A section. Comments placed here should be pointed towards suggestions on improving the documentation or server, and may be removed again by our moderators if they are either implemented or considered invalid/off-topic. Questions on how to manage the Apache HTTP Server should be directed at either our IRC channel, #httpd, on Freenode, or sent to our mailing lists.