From e765eb489ab337cbe3d8a3d3c7e58675c7029fc9 Mon Sep 17 00:00:00 2001
From: David Cook <dcook@prosentient.com.au>
Date: Fri, 21 Jun 2024 01:45:51 +0000
Subject: [PATCH] Bug 37146: Prevent path traversal by validating input

This patch validates the plugin_name passed to plugin_launcher.pl
against the base path containing the "value_builder" directory.

Test plan:
0. Apply the patch
1. koha-plack --reload kohadev
2. Go to http://localhost:8081/cgi-bin/koha/cataloguing/addbiblio.pl?biblionumber=29
3. Check that the tag editor for leader still works
4. Go to http://localhost:8081/cgi-bin/koha/cataloguing/additem.pl?biblionumber=29
5. Check that the pluginf or "Date acquired" still works

Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
---
 Koha/FrameworkPlugin.pm | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/Koha/FrameworkPlugin.pm b/Koha/FrameworkPlugin.pm
index 481bb5b2715..dab6c4f471d 100644
--- a/Koha/FrameworkPlugin.pm
+++ b/Koha/FrameworkPlugin.pm
@@ -111,6 +111,7 @@ Koha::FrameworkPlugin - Facilitate use of plugins in MARC/items editor
 =cut
 
 use Modern::Perl;
+use Cwd qw//;
 
 use base qw(Class::Accessor);
 
@@ -213,7 +214,16 @@ sub _load {
     my ( $rv, $file );
     return $self->_error( 'Plugin needs a name' ) if !$self->{name}; #2chk
     $self->{path} //= _valuebuilderpath();
+    #NOTE: Resolve symlinks and relative path components if present,
+    #so the base will compare correctly lower down
+    my $abs_base_path = Cwd::abs_path( $self->{path} );
     $file= $self->{path}. '/'. $self->{name};
+    #NOTE: Resolve relative path components to prevent loading files outside the base path
+    my $abs_file_path = Cwd::abs_path($file);
+    if ( $abs_file_path !~ /^\Q$abs_base_path\E/ ) {
+        warn "Attempt to load $file ($abs_file_path) in framework plugin!";
+        return $self->_error('File not found');
+    }
     return $self->_error( 'File not found' ) if !-e $file;
 
     # undefine oldschool subroutines before defining them again
-- 
2.39.2