public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/perl-HTML-FormFu] f45: Modernize spec file and apply fix to CVE-2026-19873
@ 2026-09-20 10:02 Emmanuel Seyman
  0 siblings, 0 replies; only message in thread
From: Emmanuel Seyman @ 2026-09-20 10:02 UTC (permalink / raw)
  To: git-commits

A new commit has been pushed.

Repo   : rpms/perl-HTML-FormFu
Branch : f45
Commit : cd312e2672a148d82517854a1bae6642ace0b0d9
Author : Emmanuel Seyman <emmanuel@seyman.fr>
Date   : 2026-09-20T12:02:39+02:00
Stats  : +303/-11 in 2 file(s)
URL    : https://src.fedoraproject.org/rpms/perl-HTML-FormFu/c/cd312e2672a148d82517854a1bae6642ace0b0d9?branch=f45

Log:
Modernize spec file and apply fix to CVE-2026-19873

---
diff --git a/HTML-FormFu-CVE-2026-19873.patch b/HTML-FormFu-CVE-2026-19873.patch
new file mode 100644
index 0000000..b1f70e3
--- /dev/null
+++ b/HTML-FormFu-CVE-2026-19873.patch
@@ -0,0 +1,286 @@
+commit 0480f51ab3d4283e64c645bd15bea1348f1ffc76
+Author: Dean Hamstead <dean@fragfest.com.au>
+Date:   Wed Aug 26 21:55:57 2026 +1000
+
+    Bound Repeatable counter_name to prevent CPU/memory DoS (CVE-2026-19873)
+    
+    Add max_counter attribute to Repeatable elements that caps the
+    client-supplied repeat count from the query string. Default is 100,
+    inherited from a new form-level repeatable_max_counter attribute.
+    
+    Additional hardening beyond the base patch:
+    - counter_clamped read-only flag signals when clamping occurred
+    - max_counter=0 means unlimited (safer than undef escape hatch)
+    - Form-level repeatable_max_counter sets the default for all
+      Repeatable elements in the form
+
+diff --git a/lib/HTML/FormFu.pm b/lib/HTML/FormFu.pm
+index b94d5047..733c0069 100644
+--- a/lib/HTML/FormFu.pm
++++ b/lib/HTML/FormFu.pm
+@@ -111,6 +111,13 @@ has form_error_message_class => (
+     lazy    => 1,
+ );
+ 
++has repeatable_max_counter => (
++    is      => 'rw',
++    default => 100,
++    lazy    => 1,
++    traits  => ['Chained'],
++);
++
+ our @MULTIFORM_SHARED = ( qw(
+         javascript
+         javascript_src
+@@ -1485,6 +1492,19 @@ used as the return value for L</submitted>.
+ If L</indicator> is not set, L</submitted> will return true if a value for
+ any known fieldname was submitted.
+ 
++=head2 repeatable_max_counter
++
++Arguments: $number
++
++Default Value: C<100>
++
++The default L<max_counter|HTML::FormFu::Element::Repeatable/max_counter>
++for all L<Repeatable|HTML::FormFu::Element::Repeatable> elements in this
++form. Individual Repeatable elements can override this by setting their own
++L<max_counter|HTML::FormFu::Element::Repeatable/max_counter>.
++
++Set to C<0> to disable clamping form-wide.
++
+ =head2 auto_fieldset
+ 
+ Arguments: 1
+diff --git a/lib/HTML/FormFu/Element/Repeatable.pm b/lib/HTML/FormFu/Element/Repeatable.pm
+index 1769e547..cb60b23a 100644
+--- a/lib/HTML/FormFu/Element/Repeatable.pm
++++ b/lib/HTML/FormFu/Element/Repeatable.pm
+@@ -14,6 +14,23 @@ use Carp qw( croak );
+ 
+ has counter_name => ( is => 'rw', traits => ['Chained'] );
+ 
++has max_counter => (
++    is      => 'rw',
++    default => sub {
++        my $form = $_[0]->form;
++        return $form->repeatable_max_counter if $form;
++        return 100;
++    },
++    lazy    => 1,
++    traits  => ['Chained'],
++);
++
++has counter_clamped => (
++    is      => 'ro',
++    default => 0,
++    writer  => '_set_counter_clamped',
++);
++
+ has _original_elements => ( is => 'rw' );
+ 
+ has increment_field_names => (
+@@ -261,6 +278,8 @@ sub process {
+     my $form         = $self->form;
+     my $count        = 1;
+ 
++    $self->_set_counter_clamped(0);
++
+     if ( defined $counter_name && defined $form->query ) {
+ 
+         # are we in a nested-repeatable?
+@@ -279,7 +298,15 @@ sub process {
+         my $input = $form->query->param($counter_name);
+ 
+         if ( defined $input && $input =~ /^[1-9][0-9]*\z/ ) {
+-            $count = $input;
++            my $max = $self->max_counter;
++
++            if ( defined $max && $max > 0 && $input > $max ) {
++                $count = $max;
++                $self->_set_counter_clamped(1);
++            }
++            else {
++                $count = $input;
++            }
+         }
+     }
+ 
+@@ -426,6 +453,31 @@ present on the form during L<HTML::FormFu/process>, no Processors
+ (Constraints, etc.) will be run on the fields, and their values will not
+ be returned by L<HTML::FormFu/params> or L<HTML::FormFu/param>.
+ 
++=head2 max_counter
++
++Arguments: $number
++
++Default Value: C<100>
++
++The largest repeat count that will be accepted from the L</counter_name>
++query parameter. A larger client-supplied value is clamped to this number.
++
++The default is inherited from L<HTML::FormFu/repeatable_max_counter>, so
++setting that on the form sets the default for all its Repeatable elements.
++
++Set to C<0> to accept any client-supplied count without clamping. Doing so
++lets a single request drive an unbounded number of element clones.
++
++Calling L</repeat> from application code is not affected by this setting,
++so a form repeated once per database row is unaffected however many rows
++there are.
++
++=head2 counter_clamped
++
++Read-only boolean. True if the most recent L<HTML::FormFu/process> call
++clamped the client-supplied count to L</max_counter>. Reset to false at the
++start of each L<HTML::FormFu/process> call.
++
+ =head2 increment_field_names
+ 
+ Arguments: $bool
+diff --git a/t/repeatable/max_counter.t b/t/repeatable/max_counter.t
+new file mode 100644
+index 00000000..ba51f325
+--- /dev/null
++++ b/t/repeatable/max_counter.t
+@@ -0,0 +1,123 @@
++use strict;
++use warnings;
++
++use Test::More tests => 13;
++
++use HTML::FormFu;
++use lib 't/lib';
++use HTMLFormFu::TestLib;
++
++# Test that max_counter defaults to 100 and clamps large values
++{
++    my $form = HTML::FormFu->new(
++        { tt_args => { INCLUDE_PATH => 'share/templates/tt/xhtml' } } );
++
++    $form->load_config_file('t/repeatable/max_counter.yml');
++
++    my $repeatable = $form->get_element( { type => 'Repeatable' } );
++
++    is( $repeatable->max_counter, 100, 'default max_counter is 100' );
++
++    $form->process( { count => 200 } );
++
++    my @blocks = @{ $repeatable->get_elements };
++    is( scalar @blocks, 100, '200 repeats clamped to 100' );
++    ok( $repeatable->counter_clamped, 'counter_clamped is true after clamping' );
++}
++
++# Test that max_counter can be set lower
++{
++    my $form = HTML::FormFu->new(
++        { tt_args => { INCLUDE_PATH => 'share/templates/tt/xhtml' } } );
++
++    $form->load_config_file('t/repeatable/max_counter.yml');
++
++    my $repeatable = $form->get_element( { type => 'Repeatable' } );
++    $repeatable->max_counter(5);
++
++    $form->process( { count => 10 } );
++
++    my @blocks = @{ $repeatable->get_elements };
++    is( scalar @blocks, 5, '10 repeats clamped to 5' );
++    ok( $repeatable->counter_clamped, 'counter_clamped is true' );
++}
++
++# Test that max_counter=0 means unlimited (not clamped)
++{
++    my $form = HTML::FormFu->new(
++        { tt_args => { INCLUDE_PATH => 'share/templates/tt/xhtml' } } );
++
++    $form->load_config_file('t/repeatable/max_counter.yml');
++
++    my $repeatable = $form->get_element( { type => 'Repeatable' } );
++    $repeatable->max_counter(0);
++
++    $form->process( { count => 3 } );
++
++    my @blocks = @{ $repeatable->get_elements };
++    is( scalar @blocks, 3, 'max_counter=0 allows 3 repeats unclamped' );
++    ok( !$repeatable->counter_clamped, 'counter_clamped is false' );
++}
++
++# Test that normal small values are unaffected
++{
++    my $form = HTML::FormFu->new(
++        { tt_args => { INCLUDE_PATH => 'share/templates/tt/xhtml' } } );
++
++    $form->load_config_file('t/repeatable/max_counter.yml');
++
++    $form->process( { count => 3 } );
++
++    my $repeatable = $form->get_element( { type => 'Repeatable' } );
++    my @blocks = @{ $repeatable->get_elements };
++    is( scalar @blocks, 3, '3 repeats below default max_counter' );
++    ok( !$repeatable->counter_clamped, 'counter_clamped is false' );
++}
++
++# Test that calling repeat() directly is unaffected by max_counter
++{
++    my $form = HTML::FormFu->new(
++        { tt_args => { INCLUDE_PATH => 'share/templates/tt/xhtml' } } );
++
++    $form->load_config_file('t/repeatable/max_counter.yml');
++
++    my $repeatable = $form->get_element( { type => 'Repeatable' } );
++    $repeatable->repeat(200);
++
++    my @blocks = @{ $repeatable->get_elements };
++    is( scalar @blocks, 200, 'direct repeat(200) unaffected by max_counter' );
++}
++
++# Test form-level repeatable_max_counter
++{
++    my $form = HTML::FormFu->new(
++        {   tt_args               => { INCLUDE_PATH => 'share/templates/tt/xhtml' },
++            repeatable_max_counter => 50,
++        } );
++
++    $form->load_config_file('t/repeatable/max_counter.yml');
++
++    my $repeatable = $form->get_element( { type => 'Repeatable' } );
++
++    is( $repeatable->max_counter, 50,
++        'max_counter inherits form repeatable_max_counter' );
++
++    $form->process( { count => 200 } );
++
++    my @blocks = @{ $repeatable->get_elements };
++    is( scalar @blocks, 50, '200 clamped to form-level 50' );
++}
++
++# Test chained method works
++{
++    my $form = HTML::FormFu->new(
++        { tt_args => { INCLUDE_PATH => 'share/templates/tt/xhtml' } } );
++
++    $form->load_config_file('t/repeatable/max_counter.yml');
++
++    my $repeatable = $form->get_element( { type => 'Repeatable' } );
++
++    $repeatable->max_counter(10)->max_counter(20);
++
++    is( $repeatable->max_counter, 20, 'chained max_counter setter works' );
++}
+diff --git a/t/repeatable/max_counter.yml b/t/repeatable/max_counter.yml
+new file mode 100644
+index 00000000..2166822b
+--- /dev/null
++++ b/t/repeatable/max_counter.yml
+@@ -0,0 +1,11 @@
++---
++elements:
++  - type: Hidden
++    name: count
++
++  - type: Repeatable
++    nested_name: rep
++    increment_field_names: 1
++    counter_name: count
++    elements:
++      - name: foo

diff --git a/perl-HTML-FormFu.spec b/perl-HTML-FormFu.spec
index 9ae26e5..6999e22 100644
--- a/perl-HTML-FormFu.spec
+++ b/perl-HTML-FormFu.spec
@@ -2,10 +2,11 @@ Name:           perl-HTML-FormFu
 Version:        2.07
 Release:        23%{?dist}
 Summary:        HTML Form Creation, Rendering and Validation Framework
-# Automatically converted from old format: GPL+ or Artistic - review is highly recommended.
+# lib/HTML/FormFu.pm
 License:        GPL-1.0-or-later OR Artistic-1.0-Perl
-URL:            https://metacpan.org/release/HTML-FormFu
+URL:            https://metacpan.org/dist/HTML-FormFu
 Source0:        https://cpan.metacpan.org/authors/id/C/CF/CFRANKS/HTML-FormFu-%{version}.tar.gz
+Patch0:         HTML-FormFu-CVE-2026-19873.patch
 BuildArch:      noarch
 BuildRequires:  coreutils
 BuildRequires:  findutils
@@ -97,31 +98,36 @@ anything else you might want to do (as long as it involves forms).
 
 %prep
 %setup -q -n HTML-FormFu-%{version}
+%patch -P 0 -p1
 
 find examples -type f | xargs chmod 644
 find examples -type f | xargs sed -i -e 's/\r//'
 
 %build
-%{__perl} Makefile.PL INSTALLDIRS=vendor NO_PACKLIST=1
-make %{?_smp_mflags}
+perl Makefile.PL INSTALLDIRS=vendor NO_PACKLIST=1 NO_PERLLOCAL=1
+%{make_build}
 
 %install
-make pure_install PERL_INSTALL_ROOT=$RPM_BUILD_ROOT
+%{make_install}
 rm -rf $RPM_BUILD_ROOT/blib
-
 %{_fixperms} $RPM_BUILD_ROOT/*
 
 %check
-make test
+%{make_build} test
 
 %files
 %doc Changes README examples
-%{perl_vendorlib}/*
-%{_bindir}/*.pl
-%{_mandir}/man1/*
-%{_mandir}/man3/*
+%{perl_vendorlib}/auto/share/dist/HTML-FormFu
+%{perl_vendorlib}/HTML*
+%{_bindir}/html_formfu_*.pl
+%{_mandir}/man1/html_formfu_*
+%{_mandir}/man3/HTML::FormFu*
 
 %changelog
+* Sun Sep 20 2026 Emmanuel Seyman <emmanuel@seyman.fr> - 2.07-24
+- Modernize spec file
+- Apply fix to CVE-2026-19873
+
 * Thu Jul 16 2026 Fedora Release Engineering <releng@fedoraproject.org> - 2.07-23
 - Rebuilt for https://fedoraproject.org/wiki/Fedora_45_Mass_Rebuild
 

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-09-20 10:02 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-20 10:02 [rpms/perl-HTML-FormFu] f45: Modernize spec file and apply fix to CVE-2026-19873 Emmanuel Seyman

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox