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