Skip to content

[6.x] Give precognitive form requests a separate rate limit bucket#14810

Merged
jasonvarga merged 1 commit into
6.xfrom
fix/forms-precognition-rate-limit
Jun 11, 2026
Merged

[6.x] Give precognitive form requests a separate rate limit bucket#14810
jasonvarga merged 1 commit into
6.xfrom
fix/forms-precognition-rate-limit

Conversation

@jasonvarga

Copy link
Copy Markdown
Member

Fixes #14807.

Since #14475 (v6.15.0) the frontend form submission route is throttled via the statamic.forms limiter — a flat 10/min keyed on IP. That single bucket is shared between two very different kinds of traffic:

  • Precognitive validation pings — the documented live-validation pattern fires one POST per field on @change.
  • The actual submission.

Validation volume scales with field count and editing behaviour; submission volume doesn't. So a perfectly ordinary contact form can exhaust the 10/min budget on validation pings alone and get the real submission rejected with a 429.

This splits the limiter into two buckets with distinct keys:

  • Precognitive validation → 30/min, keyed precognition:<ip>
  • Submissions → 10/min (unchanged), keyed submission:<ip>

On spoofing the Precognition header

A request only lands in the higher bucket if it sends Precognition: true — and the moment it does, HandlePrecognitiveRequests short-circuits with a 204 before FormController::submit() runs, so nothing is stored, no emails, no events. To actually submit (the thing worth attacking) a request must be non-precognitive, which puts it right back in the unchanged 10/min submission bucket.

So the header gates less capability, not more. The worst a spoofer gets is more runs of the validator — kept bounded by sizing the precognitive limit at 30/min rather than generously.

No upgrade step needed — it's a bug fix; the submission limit is unchanged.

🤖 Generated with Claude Code

The statamic.forms limiter shared a single 10/min budget between live
validation pings and actual submissions, so a normal contact form could
exhaust the budget on validation alone and 429 the real submission.

Split into distinct buckets: precognitive validation at 30/min,
submissions unchanged at 10/min. Spoofing the Precognition header only
gates validation (short-circuited before any submission side-effects),
so the submission ceiling is unaffected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@jasonvarga jasonvarga merged commit 3f106fc into 6.x Jun 11, 2026
19 checks passed
@jasonvarga jasonvarga deleted the fix/forms-precognition-rate-limit branch June 11, 2026 14:50
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.

Default statamic.forms rate limiter conflicts with Precognition live validation — Simple Contact Forms are broken.

1 participant