From 35a86c413c3651db6ffd1bb3413cd2113328c146 Mon Sep 17 00:00:00 2001 From: nexxo Date: Sat, 25 Jul 2026 18:38:44 +0200 Subject: [PATCH] =?UTF-8?q?fix(auth):=20throttle=20Fortify=20endpoints=20(?= =?UTF-8?q?registration=20had=20no=20limiter=20=E2=80=94=20signup-spam=20g?= =?UTF-8?q?uard)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- config/fortify.php | 5 ++++- tests/Feature/Auth/RegisterTest.php | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/config/fortify.php b/config/fortify.php index e53bbb2..0681407 100644 --- a/config/fortify.php +++ b/config/fortify.php @@ -101,7 +101,10 @@ return [ | */ - 'middleware' => ['web'], + // Throttle all Fortify endpoints (registration has no built-in limiter) to + // blunt signup spam / CPU-exhaustion via repeated password hashing. Login + // keeps its own stricter 'login' limiter on top. + 'middleware' => ['web', 'throttle:20,1'], /* |-------------------------------------------------------------------------- diff --git a/tests/Feature/Auth/RegisterTest.php b/tests/Feature/Auth/RegisterTest.php index 567edf4..97afdfc 100644 --- a/tests/Feature/Auth/RegisterTest.php +++ b/tests/Feature/Auth/RegisterTest.php @@ -39,6 +39,21 @@ it('refuses to register with an existing customer email (account-claim guard)', expect(User::query()->where('email', 'claim@signup.test')->exists())->toBeFalse(); }); +it('throttles repeated registration attempts', function () { + $hit429 = false; + for ($i = 0; $i < 24; $i++) { + $res = $this->post(route('register.store'), [ + 'name' => 'S', 'email' => "spam{$i}@signup.test", + 'password' => 'password1234', 'password_confirmation' => 'password1234', + ]); + if ($res->status() === 429) { + $hit429 = true; + break; + } + } + expect($hit429)->toBeTrue(); +}); + it('rejects a mismatched password confirmation', function () { $this->post(route('register.store'), [ 'name' => 'X',