From 98a39e1257218be7e14c980fd33ef6df29d28da8 Mon Sep 17 00:00:00 2001 From: boban Date: Sun, 14 Jun 2026 18:35:25 +0200 Subject: [PATCH] fix(webauthn): validate the key label before the browser ceremony options() now validates the label before returning creation options, so clicking Add with a blank/invalid name aborts before navigator.credentials.create() and never leaves an orphaned credential on the authenticator. Co-Authored-By: Claude Opus 4.8 (1M context) --- app/Livewire/Settings/WebauthnKeys.php | 3 +++ tests/Feature/WebauthnKeysTest.php | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/app/Livewire/Settings/WebauthnKeys.php b/app/Livewire/Settings/WebauthnKeys.php index b622e26..5624e17 100644 --- a/app/Livewire/Settings/WebauthnKeys.php +++ b/app/Livewire/Settings/WebauthnKeys.php @@ -18,6 +18,9 @@ class WebauthnKeys extends Component public function options(WebauthnService $webauthn): array { abort_unless($webauthn->available(), 404); + // Validate the label BEFORE the browser ceremony, so an invalid name never + // leaves an orphaned credential on the authenticator. + $this->validate(); return $webauthn->registrationOptions(Auth::user()); } diff --git a/tests/Feature/WebauthnKeysTest.php b/tests/Feature/WebauthnKeysTest.php index 7c75798..816f5e7 100644 --- a/tests/Feature/WebauthnKeysTest.php +++ b/tests/Feature/WebauthnKeysTest.php @@ -32,6 +32,18 @@ class WebauthnKeysTest extends TestCase $this->assertDatabaseHas('webauthn_credentials', ['user_id' => $user->id, 'name' => 'YubiKey 5C']); } + public function test_options_validate_label_before_ceremony(): void + { + $user = User::factory()->create(); + $this->actingAs($user); + $this->mock(WebauthnService::class)->shouldReceive('available')->andReturn(true); + + Livewire::test(WebauthnKeys::class) + ->set('newName', '') + ->call('options') + ->assertHasErrors('newName'); + } + public function test_remove_deletes_credential(): void { $user = User::factory()->create();