Bug 40579: Fix CSV formula injection vulnerabilities
This patch addresses CSV formula injection vulnerabilities by ensuring all Text::CSV instances use formula protection. Changes made: * Add formula => 'empty' to all Text::CSV constructors in: - Koha::Patrons::Import - Koha::BackgroundJob::ImportKBARTFile - Koha::ERM::EUsage::CounterFile The 'empty' formula mode causes potentially dangerous formulas (starting with =, +, -, @) to be treated as empty strings rather than executed, preventing CSV injection attacks while maintaining data integrity. Security impact: * Prevents execution of malicious formulas in CSV imports * Protects against data exfiltration via CSV formula injection * Maintains backward compatibility for legitimate CSV data To test: 1. Apply the previous patch (author test) 2. Run: $ ktd --shell k$ prove xt/author/Text_CSV_Various.t => FAIL: Should show 3 files without formula protection 3. Apply this patch 4. Repeat 2 => SUCCESS: All tests should now pass 5. Try importing CSV with formula content (=cmd|"/c calc",test,data) => SUCCESS: Formula content is rejected/emptied, not executed 6. Import normal CSV data => SUCCESS: Normal data imports correctly 7. Sign off :-D Signed-off-by: David Cook <dcook@prosentient.com.au> Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de> Signed-off-by: Jesse Maseto <jesse@bywatersolutions.com>
This commit is contained in:
parent
a0ef38c4c3
commit
443c067d30
|
|
@ -235,7 +235,8 @@ sub read_file {
|
|||
sep_char => $delimiter,
|
||||
quote_char => $quote_char,
|
||||
binary => 1,
|
||||
allow_loose_quotes => 1
|
||||
allow_loose_quotes => 1,
|
||||
formula => 'empty'
|
||||
}
|
||||
);
|
||||
my $headers_to_check = $csv->getline($fh);
|
||||
|
|
|
|||
|
|
@ -302,7 +302,7 @@ sub validate {
|
|||
my ($self) = @_;
|
||||
|
||||
open my $fh, "<", \$self->file_content or die;
|
||||
my $csv = Text::CSV_XS->new( { binary => 1, always_quote => 1, eol => $/, decode_utf8 => 1 } );
|
||||
my $csv = Text::CSV_XS->new( { binary => 1, always_quote => 1, eol => $/, decode_utf8 => 1, formula => 'empty' } );
|
||||
|
||||
$csv->column_names(qw( header_key header_value ));
|
||||
my @header_rows = $csv->getline_hr_all( $fh, 0, 12 );
|
||||
|
|
@ -329,7 +329,7 @@ sub _set_report_type_from_file {
|
|||
my ($self) = @_;
|
||||
|
||||
open my $fh, "<", \$self->file_content or die;
|
||||
my $csv = Text::CSV_XS->new( { binary => 1, always_quote => 1, eol => $/, decode_utf8 => 1 } );
|
||||
my $csv = Text::CSV_XS->new( { binary => 1, always_quote => 1, eol => $/, decode_utf8 => 1, formula => 'empty' } );
|
||||
|
||||
$csv->column_names(qw( header_key header_value ));
|
||||
my @header_rows = $csv->getline_hr_all( $fh, 0, 12 );
|
||||
|
|
@ -352,7 +352,7 @@ sub _get_rows_from_COUNTER_file {
|
|||
my ($self) = @_;
|
||||
|
||||
open my $fh, "<", \$self->file_content or die;
|
||||
my $csv = Text::CSV_XS->new( { binary => 1, always_quote => 1, eol => $/, decode_utf8 => 1 } );
|
||||
my $csv = Text::CSV_XS->new( { binary => 1, always_quote => 1, eol => $/, decode_utf8 => 1, formula => 'empty' } );
|
||||
|
||||
my $header_columns = $csv->getline_all( $fh, 13, 1 );
|
||||
$csv->column_names( @{$header_columns}[0] );
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ has 'today_iso' => ( is => 'ro', lazy => 1,
|
|||
default => sub { output_pref( { dt => dt_from_string(), dateonly => 1, dateformat => 'iso' } ); }, );
|
||||
|
||||
has 'text_csv' => ( is => 'rw', lazy => 1,
|
||||
default => sub { Text::CSV->new( { binary => 1, } ); }, );
|
||||
default => sub { Text::CSV->new( { binary => 1, formula => 'empty' } ); }, );
|
||||
|
||||
sub import_patrons {
|
||||
my ($self, $params) = @_;
|
||||
|
|
|
|||
Loading…
Reference in New Issue