@@ -271,12 +271,19 @@ 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' ,
280+ " --output=$working_dir /image.svg" ;
281+ } elsif ($method eq ' pdf2svg' ) {
282+ my $cmd = WeBWorK::PG::IO::externalCommand(' pdf2svg' );
283+ system { $cmd } $cmd , " $working_dir /image.pdf" , " $working_dir /image.svg" ;
277284 } else {
278- system WeBWorK::PG::IO::externalCommand( $self -> svgMethod)
279- . " $working_dir /image.pdf $working_dir /image.svg > /dev/null 2>&1 " ;
285+ warn " Unknown svgMethod ' $method '. Must be 'dvisvgm' or 'pdf2svg'. " ;
286+ return ;
280287 }
281288 warn " Failed to generate svg file." unless -r " $working_dir /image.svg" ;
282289
@@ -285,11 +292,24 @@ sub use_svgMethod {
285292
286293sub use_convert {
287294 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" ;
295+
296+ # Validate convertOptions keys and values to prevent shell injection.
297+ # Only alphanumeric option names and simple values are permitted.
298+ my @args ;
299+ for my $phase (qw( input output) ) {
300+ my $opts = $self -> convertOptions-> {$phase } // {};
301+ for my $key (keys %$opts ) {
302+ warn (" Invalid convert option name: $key " ), next unless $key =~ / ^[a-zA-Z][a-zA-Z0-9\- ]*$ / ;
303+ my $val = $opts -> {$key };
304+ warn (" Invalid convert option value for $key " ), next unless defined $val && $val =~ / ^[a-zA-Z0-9.\- +:x%]+$ / ;
305+ push @args , " -$key " , $val ;
306+ }
307+ push @args , " $working_dir /image.pdf" if $phase eq ' input' ;
308+ }
309+ push @args , " $working_dir /image.$ext " ;
310+
311+ my $convert = WeBWorK::PG::IO::externalCommand(' convert' );
312+ system { $convert } $convert , @args ;
293313 warn " Failed to generate $ext file." unless -r " $working_dir /image.$ext " ;
294314
295315 return ;
0 commit comments