Bugzilla – Attachment 185797 Details for
Bug 40579
CSV formula injection protection
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 40579: Fix CSV formula injection vulnerabilities
Bug-40579-Fix-CSV-formula-injection-vulnerabilitie.patch (text/plain), 4.32 KB, created by
Paul Derscheid
on 2025-08-26 15:59:33 UTC
(
hide
)
Description:
Bug 40579: Fix CSV formula injection vulnerabilities
Filename:
MIME Type:
Creator:
Paul Derscheid
Created:
2025-08-26 15:59:33 UTC
Size:
4.32 KB
patch
obsolete
>From cb67d1c228d708b56fd414c22d6320bdc3e8d763 Mon Sep 17 00:00:00 2001 >From: Tomas Cohen Arazi <tomascohen@theke.io> >Date: Fri, 1 Aug 2025 12:03:17 -0300 >Subject: [PATCH] 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> >--- > Koha/BackgroundJob/ImportKBARTFile.pm | 3 ++- > Koha/ERM/EUsage/CounterFile.pm | 6 +++--- > Koha/Patrons/Import.pm | 2 +- > 3 files changed, 6 insertions(+), 5 deletions(-) > >diff --git a/Koha/BackgroundJob/ImportKBARTFile.pm b/Koha/BackgroundJob/ImportKBARTFile.pm >index 890a3c926a8..a8793d24998 100644 >--- a/Koha/BackgroundJob/ImportKBARTFile.pm >+++ b/Koha/BackgroundJob/ImportKBARTFile.pm >@@ -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); >diff --git a/Koha/ERM/EUsage/CounterFile.pm b/Koha/ERM/EUsage/CounterFile.pm >index 0836455251b..5c41a1ea948 100644 >--- a/Koha/ERM/EUsage/CounterFile.pm >+++ b/Koha/ERM/EUsage/CounterFile.pm >@@ -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] ); >diff --git a/Koha/Patrons/Import.pm b/Koha/Patrons/Import.pm >index f4b5c2538e7..c1543ec46ca 100644 >--- a/Koha/Patrons/Import.pm >+++ b/Koha/Patrons/Import.pm >@@ -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) = @_; >-- >2.51.0
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 40579
:
185034
|
185035
|
185078
|
185079
|
185737
|
185738
|
185783
|
185784
|
185785
|
185796
|
185797
|
185798
|
185799
|
185800
|
185801