perlstricttaint

Perl setting value of a variable in strict -T mode errors


I have a script running strict with the -T parameter or 'taint' mode. If I try to set the value of a variable already defined, it craps out. I didn't make much of it, I'm just trying to modify it and don't know why it's breaking. Here's the gist of what it looks like:

#!/usr/bin/perl -T

use 5.010;
use CGI;
use CGI::Carp qw/fatalsToBrowser/;

use strict;
use warnings;
use localtime;


my @months = qw(january february march april may june july august september october november december);

my $q = CGI->new();
say $q->header(), $q->start_html(-title=>'Calendar');

for my $param ($q->param()) {
    my $safe_param = $q->escapeHTML($param);

    for my $value ($q->param($param)) {
                my $params = $q->escapeHTML($value);
                {
                        local $ENV{"PATH"} = "/bin:/usr/local/bin:/usr/bin";
                        local $ENV{"BASH_ENV"}="";
                        my $date = "";

                        my $white = /^\s*$/;
                        my $singleyear = /^\d{2,4}$/;
                        my $nummonth = /^\d{1,2}\s\d{1,4}$/;
                        # If $params is empty or all white space, set $date to a single space
                        if ($params =~ $white) {
                                my($day, $month, $year)=(localtime)[3,4,5];
                                my $monthname = $months[$month];
                                $date = "$monthname $year"
                        }
                        # If $params is only a single 1-4 digit year, set $date to year
                        if ($params =~ $singleyear) {
                                $date = $params;
                        }
                        # If $params is a 1-2 digit month and a 1-4 digit year set $date to month and year
                        if ($params =~ $nummonth) {
                                my $monthnumber = $params =~ /^\d{1,2}/;
                                my $monthstring = $months[$monthnumber];
                                my $yearnumber = $params =~ /(\d{1,4})$/;
                                $date = "$monthstring $yearnumber";
                        }

                        if  ($date eq "") {
                                say "<h1>Invalid Parameters: $params</h1>";
                        } else {
                                say "<h1>Parameters: $params</h1>";
                        }
                        my $cmds = "cal -h " . $date;
                        my @lines = `$cmds`;
                        say ("<pre>");
                        for my $line (@lines) {
                                print ("$line");
                        }
                        say ("</pre>");
                }
    }
    say '</p>';
}

say $q->end_html();

At any point I set the value of $date it throws the error:

Insecure dependency in `` while running with -T switch

if I set my $date it throws no error, but doesn't actually update the value of date.

Also, I'm pretty sure all my regex is wrong, because I did some testing, and all of those cases evaluate to true for some reason, regardless of the user input. But that's not really the problem I'm facing now.

Example user input for $params

02 1999

Solution

  • $date = $params;

    Such code assigns the tainted $params value to $date without untainting it.

    Instead: Match the exact data you want with a regex, and use regex captures to extract an untainted value. For example:

    if ($params =~ /^(\d{2,4})$/) {
        $date = $1;
    }
    

    And so on for the other cases.

    Note that assigning a regex $foo = /bar/ does not assign a regex object, but assigns the result of matching that regex against the $_ variable! If you need to create regex objects, use the qr/.../ operator. However, using regex objects seems unnecessary in your program – just write down the regex in each condition in order to avoid problems.