This is an automated email from the git hooks/post-receive script.

Git pushed a commit to branch master
in repository fateserver.

The following commit(s) were added to refs/heads/master by this push:
     new 00eebe3  Escape HTML by default in the output helpers
00eebe3 is described below

commit 00eebe33b75caa8b7426514c914393db9727b987
Author:     Kacper Michajłow <[email protected]>
AuthorDate: Sat Aug 15 15:24:17 2026 +0200
Commit:     Kacper Michajłow <[email protected]>
CommitDate: Sat Aug 15 15:37:29 2026 +0200

    Escape HTML by default in the output helpers
    
    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';

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

Reply via email to