From 0cacf30bc60cb893eff13dde0da6c3a70d007bec Mon Sep 17 00:00:00 2001 From: Duncan McClean Date: Mon, 27 Apr 2026 17:14:47 +0100 Subject: [PATCH 1/5] Check correct precognition header --- src/Fields/Validator.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Fields/Validator.php b/src/Fields/Validator.php index f4dec57d112..5a3bc202cee 100644 --- a/src/Fields/Validator.php +++ b/src/Fields/Validator.php @@ -186,12 +186,12 @@ public function filterPrecognitiveRules($rules) { $request = request(); - if (! $request->headers->has('Precognition-Validate-Only')) { + if (! $request->headers->has('Precognition')) { return $rules; } return Collection::make($rules) - ->only(explode(',', $request->header('Precognition-Validate-Only'))) + ->only(explode(',', $request->header('Precognition'))) ->all(); } } From ede33872f696d467ab90ece7ec0db9de4ed99608 Mon Sep 17 00:00:00 2001 From: Duncan McClean Date: Mon, 27 Apr 2026 17:22:41 +0100 Subject: [PATCH 2/5] Add test --- tests/Tags/Form/FormCreateAlpineTest.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/Tags/Form/FormCreateAlpineTest.php b/tests/Tags/Form/FormCreateAlpineTest.php index 5c7a345b39e..e6ed5c795d9 100644 --- a/tests/Tags/Form/FormCreateAlpineTest.php +++ b/tests/Tags/Form/FormCreateAlpineTest.php @@ -3,6 +3,7 @@ namespace Tests\Tags\Form; use PHPUnit\Framework\Attributes\Test; +use Statamic\Facades\Form; use Statamic\Statamic; class FormCreateAlpineTest extends FormTestCase @@ -932,6 +933,22 @@ public function it_dynamically_renders_precognition_text_field_x_on_change() $this->assertFieldRendersHtml([''], $config, [], ['js' => 'alpine_precognition']); } + #[Test] + public function it_wont_submit_form_when_precognition_validate_only_header_is_spoofed() + { + $this->assertEmpty(Form::find('contact')->submissions()); + + $this + ->withHeaders([ + 'Precognition-Validate-Only' => 'foo', + ]) + ->post('/!/forms/contact', []) + ->assertSessionHasErrors(['email'], null, 'form.contact') + ->assertLocation('/'); + + $this->assertEmpty(Form::find('contact')->submissions()); + } + private function jsonEncode($data) { return Statamic::modify($data)->toJson()->entities(); From a46a977dadc000d354ae9122e08feb1b6fc66404 Mon Sep 17 00:00:00 2001 From: Duncan McClean Date: Tue, 28 Apr 2026 08:45:55 +0100 Subject: [PATCH 3/5] Use isPrecognitive() and delegate filtering to Laravel Co-Authored-By: Claude Opus 4.6 (1M context) --- src/Fields/Validator.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Fields/Validator.php b/src/Fields/Validator.php index 5a3bc202cee..175fa13854a 100644 --- a/src/Fields/Validator.php +++ b/src/Fields/Validator.php @@ -2,7 +2,6 @@ namespace Statamic\Fields; -use Illuminate\Support\Collection; use Illuminate\Support\Facades\Validator as LaravelValidator; use Statamic\Support\Arr; use Statamic\Support\Str; @@ -186,12 +185,10 @@ public function filterPrecognitiveRules($rules) { $request = request(); - if (! $request->headers->has('Precognition')) { + if (! $request->isPrecognitive()) { return $rules; } - return Collection::make($rules) - ->only(explode(',', $request->header('Precognition'))) - ->all(); + return $request->filterPrecognitiveRules($rules); } } From 4717dcdfb43b571dd2ca4cc1df94caf9d22a106e Mon Sep 17 00:00:00 2001 From: Duncan McClean Date: Tue, 28 Apr 2026 08:46:13 +0100 Subject: [PATCH 4/5] Add precognition validation tests Co-Authored-By: Claude Opus 4.6 (1M context) --- tests/Tags/Form/FormCreateAlpineTest.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/Tags/Form/FormCreateAlpineTest.php b/tests/Tags/Form/FormCreateAlpineTest.php index e6ed5c795d9..f91157f0808 100644 --- a/tests/Tags/Form/FormCreateAlpineTest.php +++ b/tests/Tags/Form/FormCreateAlpineTest.php @@ -933,6 +933,18 @@ public function it_dynamically_renders_precognition_text_field_x_on_change() $this->assertFieldRendersHtml([''], $config, [], ['js' => 'alpine_precognition']); } + #[Test] + public function it_validates_precognitive_requests() + { + $this + ->withPrecognition() + ->withHeaders(['Precognition-Validate-Only' => 'email']) + ->postJson('/!/forms/contact', ['email' => '']) + ->assertStatus(422) + ->assertJsonValidationErrors(['email']) + ->assertJsonMissingValidationErrors(['message']); + } + #[Test] public function it_wont_submit_form_when_precognition_validate_only_header_is_spoofed() { From 1c9b9d0a03356be9fc64272e7dcc395e5f1180c4 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Tue, 28 Apr 2026 09:29:55 -0400 Subject: [PATCH 5/5] consistent withHeaders --- tests/Tags/Form/FormCreateAlpineTest.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/Tags/Form/FormCreateAlpineTest.php b/tests/Tags/Form/FormCreateAlpineTest.php index f91157f0808..bb2b56c327f 100644 --- a/tests/Tags/Form/FormCreateAlpineTest.php +++ b/tests/Tags/Form/FormCreateAlpineTest.php @@ -951,9 +951,7 @@ public function it_wont_submit_form_when_precognition_validate_only_header_is_sp $this->assertEmpty(Form::find('contact')->submissions()); $this - ->withHeaders([ - 'Precognition-Validate-Only' => 'foo', - ]) + ->withHeaders(['Precognition-Validate-Only' => 'foo']) ->post('/!/forms/contact', []) ->assertSessionHasErrors(['email'], null, 'form.contact') ->assertLocation('/');