[6.x] Give precognitive form requests a separate rate limit bucket#14810
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #14807.
Since #14475 (v6.15.0) the frontend form submission route is throttled via the
statamic.formslimiter — a flat 10/min keyed on IP. That single bucket is shared between two very different kinds of traffic:@change.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:
precognition:<ip>submission:<ip>On spoofing the
PrecognitionheaderA request only lands in the higher bucket if it sends
Precognition: true— and the moment it does,HandlePrecognitiveRequestsshort-circuits with a 204 beforeFormController::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