@@ -271,12 +271,18 @@ sub draw {
271271
272272sub use_svgMethod {
273273 my ($self , $working_dir ) = @_ ;
274- if ($self -> svgMethod eq ' dvisvgm' ) {
275- system WeBWorK::PG::IO::externalCommand(' dvisvgm' )
276- . " $working_dir /image.dvi --no-fonts --output=$working_dir /image.svg > /dev/null 2>&1" ;
274+
275+ # Validate svgMethod against known SVG converters to prevent command injection.
276+ my $method = $self -> svgMethod;
277+ if ($method eq ' dvisvgm' ) {
278+ my $cmd = WeBWorK::PG::IO::externalCommand(' dvisvgm' );
279+ system {$cmd } $cmd , " $working_dir /image.dvi" , ' --no-fonts' , " --output=$working_dir /image.svg" ;
280+ } elsif ($method eq ' pdf2svg' ) {
281+ my $cmd = WeBWorK::PG::IO::externalCommand(' pdf2svg' );
282+ system {$cmd } $cmd , " $working_dir /image.pdf" , " $working_dir /image.svg" ;
277283 } else {
278- system WeBWorK::PG::IO::externalCommand( $self -> svgMethod)
279- . " $working_dir /image.pdf $working_dir /image.svg > /dev/null 2>&1 " ;
284+ warn " Unknown svgMethod ' $method '. Must be 'dvisvgm' or 'pdf2svg'. " ;
285+ return ;
280286 }
281287 warn " Failed to generate svg file." unless -r " $working_dir /image.svg" ;
282288
@@ -285,11 +291,24 @@ sub use_svgMethod {
285291
286292sub use_convert {
287293 my ($self , $working_dir , $ext ) = @_ ;
288- system WeBWorK::PG::IO::externalCommand(' convert' )
289- . join (' ' , map { " -$_ " . $self -> convertOptions-> {input }-> {$_ } } (keys %{ $self -> convertOptions-> {input } }))
290- . " $working_dir /image.pdf"
291- . join (' ' , map { " -$_ " . $self -> convertOptions-> {output }-> {$_ } } (keys %{ $self -> convertOptions-> {output } }))
292- . " $working_dir /image.$ext > /dev/null 2>&1" ;
294+
295+ # Validate convertOptions keys and values to prevent shell injection.
296+ # Only alphanumeric option names and simple values are permitted.
297+ my @args ;
298+ for my $phase (qw( input output) ) {
299+ my $opts = $self -> convertOptions-> {$phase } // {};
300+ for my $key (keys %$opts ) {
301+ warn (" Invalid convert option name: $key " ), next unless $key =~ / ^[a-zA-Z][a-zA-Z0-9\- ]*$ / ;
302+ my $val = $opts -> {$key };
303+ warn (" Invalid convert option value for $key " ), next unless defined $val && $val =~ / ^[a-zA-Z0-9.\- +:x%]+$ / ;
304+ push @args , " -$key " , $val ;
305+ }
306+ push @args , " $working_dir /image.pdf" if $phase eq ' input' ;
307+ }
308+ push @args , " $working_dir /image.$ext " ;
309+
310+ my $convert = WeBWorK::PG::IO::externalCommand(' convert' );
311+ system {$convert } $convert , @args ;
293312 warn " Failed to generate $ext file." unless -r " $working_dir /image.$ext " ;
294313
295314 return ;
0 commit comments