PR #6 opened by Kacper Michajłow (kasper93)
URL: https://code.ffmpeg.org/FFmpeg/fateserver/pulls/6
Patch URL: https://code.ffmpeg.org/FFmpeg/fateserver/pulls/6.patch

Report fields were printed into HTML as they came. Escape things
before output. Reports are only from trusted sources, but still it's
good hygiene to sanitize the external data, even if for the unintended
corruption that could happen.


From 00eebe33b75caa8b7426514c914393db9727b987 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= <[email protected]>
Date: Sat, 15 Aug 2026 15:24:17 +0200
Subject: [PATCH] Escape HTML by default in the output helpers
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Report fields were printed into HTML as they came. Escape things
before output. Reports are only from trusted sources, but still it's
good hygiene to sanitize the external data, even if for the unintended
corruption that could happen.

Signed-off-by: Kacper Michajłow <[email protected]>
---
 FATE.pm    | 30 ++++++++++++++++++++----------
 index.cgi  | 15 ++++++++-------
 report.cgi | 19 ++++++++++---------
 3 files changed, 38 insertions(+), 26 deletions(-)

diff --git a/FATE.pm b/FATE.pm
index 3c79ac5..a06f249 100644
--- a/FATE.pm
+++ b/FATE.pm
@@ -20,6 +20,7 @@ use warnings;
 
 use POSIX qw/asctime mktime/;
 use CGI ();
+use HTML::Entities ();
 
 BEGIN {
     use Exporter;
@@ -29,6 +30,7 @@ BEGIN {
     @EXPORT  = qw/split_header split_config split_rec parse_date agestr
                   split_stats load_summary load_report load_lastpass
                   start end tag h1 span trow trowa trowh th td anchor
+                  esc
                   head1 head2 head3 footer href
                   fail
                   ready_for_gzip end_headers_and_compress
@@ -259,6 +261,13 @@ sub agestr {
 
 # HTML helpers
 
+sub esc {
+    my ($t) = @_;
+    return '' if not defined $t;
+    return $$t if ref $t;
+    return HTML::Entities::encode_entities($t, '<>&"');
+}
+
 my %block_tags;
 my @block_tags = ('html', 'head', 'style', 'body', 'table');
 $block_tags{$_} = 1 for @block_tags;
@@ -268,7 +277,8 @@ my @tags;
 sub opentag {
     my ($tag, %attrs) = @_;
     print qq{<$tag};
-    print qq{ $_="$attrs{$_}"} for grep defined $attrs{$_}, keys %attrs;
+    print ' ', $_, '="', esc($attrs{$_}), '"'
+        for grep defined $attrs{$_}, keys %attrs;
 }
 
 sub start {
@@ -297,7 +307,7 @@ sub tag {
 sub h1 {
     my ($text, %attrs) = @_;
     start 'h1', %attrs;
-    print $text;
+    print esc $text;
     end;
     print "\n";
 }
@@ -305,20 +315,20 @@ sub h1 {
 sub span {
     my ($text, %attrs) = @_;
     start 'span', %attrs;
-    print $text;
+    print esc $text;
     end;
 }
 
 sub trow {
     start 'tr';
-    print "<td>$_</td>" for @_;
+    print '<td>', esc($_), '</td>' for @_;
     end;
     print "\n";
 }
 
 sub trowh {
     start 'tr';
-    print "<th>$_</th>" for @_;
+    print '<th>', esc($_), '</th>' for @_;
     end;
     print "\n";
 }
@@ -326,7 +336,7 @@ sub trowh {
 sub trowa {
     my $attrs = shift;
     start 'tr', %{$attrs};
-    print "<td>$_</td>" for @_;
+    print '<td>', esc($_), '</td>' for @_;
     end;
     print "\n";
 }
@@ -334,21 +344,21 @@ sub trowa {
 sub th {
     my ($text, %attrs) = @_;
     start 'th', %attrs;
-    print $text;
+    print esc $text;
     end;
 }
 
 sub td {
     my ($text, %attrs) = @_;
     start 'td', %attrs;
-    print $text;
+    print esc $text;
     end;
 }
 
 sub anchor {
     my ($text, %attrs) = @_;
     start 'a', %attrs;
-    print $text;
+    print esc $text;
     end;
 }
 
@@ -359,7 +369,7 @@ sub href {
         return '/' . join '/', grep defined $_, @href{@parts};
     } else {
         my $cgi = defined $href{log}? 'log': defined $href{time}? 'report': 
'history';
-        return sprintf '/%s.cgi?%s', $cgi, join '&amp;', map "$_=$href{$_}", 
keys %href;
+        return sprintf '/%s.cgi?%s', $cgi, join '&', map "$_=$href{$_}", keys 
%href;
     }
 }
 
diff --git a/index.cgi b/index.cgi
index 40401da..36dc5e1 100755
--- a/index.cgi
+++ b/index.cgi
@@ -103,10 +103,11 @@ for my $slot (@slots) {
     }
 }
 
-my $clear = '?' . join '&amp;', other_params();
+my $clear = '?' . join '&', other_params();
 
 @reps or fail @queries ? 'No items matching search criteria. ' .
-                         "<a href=\"$clear\">Clear all search criteria.</a>" :
+                         '<a href="' . esc($clear) . '">' .
+                         'Clear all search criteria.</a>' :
                          'No data in $fatedir.';
 
 # Percentage of $n out of $total, rounded to one decimal for display.
@@ -182,7 +183,7 @@ sub lsort {
 
     $key = $newkey if $newkey ne '';
     push @params, "sort=$key";
-    anchor $text, href => '?' . join '&amp;', @params;
+    anchor $text, href => '?' . join '&', @params;
 }
 
 sub category {
@@ -195,7 +196,7 @@ sub category {
                                [$category, $$rep{$category}]));
 
     start 'td';
-    anchor $$rep{$category}, href => '?' . join '&amp;', @params;
+    anchor $$rep{$category}, href => '?' . join '&', @params;
     end 'td';
 }
 
@@ -248,10 +249,10 @@ if (@branches > 1) {
         my @rest = grep $$_[0] ne 'branch', @queries;
         my $active = defined $cur_branch ? $branch eq $cur_branch : $branch eq 
'all';
         if ($active) {
-            span encode_entities($branch, '<>&"'), class => 'branch-active';
+            span $branch, class => 'branch-active';
         } else {
-            anchor encode_entities($branch, '<>&"'),
-                href => '?' . join '&amp;', other_params(),
+            anchor $branch,
+                href => '?' . join '&', other_params(),
                     query_params(@rest, $branch eq 'all' ? () : ['branch', 
$branch]);
         }
         print "\n";
diff --git a/report.cgi b/report.cgi
index d7fcc3f..d2a6ed6 100755
--- a/report.cgi
+++ b/report.cgi
@@ -62,7 +62,7 @@ print "Content-type: text/html\r\n";
 end_headers_and_compress;
 
 head1;
-print "<title>FATE: $$hdr{slot} $$hdr{rev}</title>\n";
+print '<title>FATE: ', esc("$$hdr{slot} $$hdr{rev}"), "</title>\n";
 print <<EOF;
 <script type="text/javascript">
   function toggle(id) {
@@ -84,7 +84,7 @@ print <<EOF;
 </script>
 EOF
 head2;
-print "$$hdr{slot} $$hdr{rev}";
+print esc("$$hdr{slot} $$hdr{rev}");
 head3;
 
 start 'table', id => 'config';
@@ -94,7 +94,7 @@ trow 'CPU',           $$conf{cpu};
 trow 'OS',            $$conf{os};
 trow 'Owner',         $$rep{owner};
 trow 'Compiler',      $$conf{cc};
-trow 'Configuration', '<code>' . $$conf{config} . '</code>';
+trow 'Configuration', \('<code>' . esc($$conf{config}) . '</code>');
 trow 'Comment',       $$hdr{comment};
 start 'tr';
 td   'Revision';
@@ -145,6 +145,7 @@ if ($nfail) {
     for my $n (sort keys %fail) {
         my $rec = $fail{$n};
         my $test = $$rec{name};
+        (my $testid = $test) =~ s/[^A-Za-z0-9_-]/_/g;
         my $diff = encode_entities decode_base64($$rec{diff}), '<>&"';
         my $err  = encode_entities decode_base64($$rec{stderr}), '<>&"';
         if ($diff =~ /^--- /) {
@@ -159,8 +160,8 @@ if ($nfail) {
             $diff = '<em>No diff output recorded</em>';
         }
         start 'tr', class => 'alt hilight';
-        td "diff",    class => 'toggle', onclick => "show_diff('$test')";
-        td "stderr",  class => 'toggle', onclick => "show_err('$test')";
+        td "diff",    class => 'toggle', onclick => "show_diff('$testid')";
+        td "stderr",  class => 'toggle', onclick => "show_err('$testid')";
         td $test;
         td $$rec{status}, class => 'errcode';
         if ($$lastpass{$n}) {
@@ -176,12 +177,12 @@ if ($nfail) {
         }
         end 'tr';
         trowa { style => 'display: none' }, ''; # nee
-        start 'tr', id => "$test-diff", class => 'diff';
-        td "<pre>$diff</pre>", colspan => 5;
+        start 'tr', id => "$testid-diff", class => 'diff';
+        td \"<pre>$diff</pre>", colspan => 5;
         end 'tr';
         trowa { style => 'display: none' }, '';
-        start 'tr', id => "$test-err",  class => 'diff';
-        td "<pre>$err</pre>",  colspan => 5;
+        start 'tr', id => "$testid-err",  class => 'diff';
+        td \"<pre>$err</pre>",  colspan => 5;
         end 'tr';
     }
     end 'tbody';
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to