Skip to content

Bound Repeatable counter_name to prevent CPU/memory DoS (CVE-2026-19873) - #72

Open
djzort wants to merge 1 commit into
masterfrom
CVE-2026-19873
Open

djzort wants to merge 1 commit into
masterfrom
CVE-2026-19873

Conversation

@djzort

@djzort djzort commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator

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

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

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens HTML::FormFu::Element::Repeatable against CPU/memory DoS by bounding the client-supplied repeat count (from the query param named by counter_name) and adding a form-level default for that bound.

Changes:

  • Add max_counter to Repeatable (defaulting to form-level repeatable_max_counter, otherwise 100) and clamp the query-driven repeat count to that maximum.
  • Add counter_clamped read-only flag to indicate clamping occurred during the most recent process.
  • Add regression tests and config covering default clamping, override behavior, unlimited mode (0), and form-level default inheritance.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
t/repeatable/max_counter.yml Adds a minimal Repeatable config used by the new max-counter test suite.
t/repeatable/max_counter.t Adds tests validating clamping behavior, unlimited mode, inheritance, and chaining.
lib/HTML/FormFu/Element/Repeatable.pm Implements max_counter/counter_clamped and clamps query-driven repeat counts in process.
lib/HTML/FormFu.pm Adds form-level repeatable_max_counter attribute and documentation.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +17 to +26
has max_counter => (
is => 'rw',
default => sub {
my $form = $_[0]->form;
return $form->repeatable_max_counter if $form;
return 100;
},
lazy => 1,
traits => ['Chained'],
);
Comment thread lib/HTML/FormFu.pm
Comment on lines +114 to +119
has repeatable_max_counter => (
is => 'rw',
default => 100,
lazy => 1,
traits => ['Chained'],
);
plicease added a commit to uperl/HTML-FormFu that referenced this pull request Sep 21, 2026
Element::Repeatable::process read its repeat count straight from the
query string via counter_name with only a positive-integer check, then
passed it to repeat(), which deep-clones the whole child subtree once
per iteration with no upper bound. This was reachable via a plain
unauthenticated GET request and cost super-linear CPU due to
constraint field lookups, with nested Repeatables multiplying the
effect further.

Add a max_counter attribute on Repeatable (default 100) that clamps
the client-supplied count instead of trusting it unbounded, with a
counter_clamped flag to signal when clamping occurred. The default is
inherited from a new form-level repeatable_max_counter attribute, and
max_counter => 0 disables clamping for callers who need it. Direct
application calls to repeat() are unaffected.

Mirrors the design from FormFu/HTML-FormFu#72.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants