Filament's multi-factor authentication (app) recovery codes can be used multiple times
Description
Filament is a collection of full-stack components for accelerated Laravel development. Versions 4.0.0 through 4.3.0 contain a flaw in the handling of recovery codes for app-based multi-factor authentication, allowing the same recovery code to be reused indefinitely. This issue does not affect email-based MFA. It also only applies when recovery codes are enabled. This issue is fixed in version 4.3.1.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Filament versions 4.0.0-4.3.0 allow indefinite reuse of app-based MFA recovery codes, weakening security; fixed in 4.3.1.
Vulnerability
Overview
Filament, a full-stack component framework for Laravel, versions 4.0.0 through 4.3.0 contain a flaw in the handling of recovery codes for app-based multi-factor authentication (MFA). The recovery codes are not invalidated after a single use, allowing the same code to be reused indefinitely [1][4]. This issue does not affect email-based MFA and only applies when recovery codes are enabled [1].
Exploitation
An attacker who gains access to both a user's password and their recovery codes can repeatedly complete the MFA challenge without needing the user's app-based second factor [4]. The attack requires the attacker to have obtained the recovery codes (e.g., through a data breach or phishing) and the user's password. No additional authentication is needed after the first successful use of a recovery code [2].
Impact
The intended security of MFA is weakened because recovery codes become a static, long-term bypass method rather than a one-time-use fallback [4]. This effectively reduces the MFA to a single-factor password if recovery codes are compromised, undermining the protection that MFA is designed to provide.
Mitigation
The issue is fixed in Filament version 4.3.1 [1]. The fix, visible in commit 87ff60ad9b6e16d4e14ee36a220b8917dd7b0815, ensures that after a recovery code is verified, it is removed from the user's stored codes, preventing reuse [2]. Users should upgrade to version 4.3.1 or later to remediate the vulnerability.
AI Insight generated on May 19, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
filament/filamentPackagist | >= 4.0.0, < 4.3.1 | 4.3.1 |
Affected products
2v4.0.0, v4.0.1, v4.0.10, …+ 1 more
- (no CPE)range: v4.0.0, v4.0.1, v4.0.10, …
- (no CPE)range: >=4.0.0, <=4.3.0
Patches
187ff60ad9b6efix: Multi-factor recovery code reuse (#18672)
2 files changed · +71 −2
packages/panels/src/Auth/MultiFactor/App/AppAuthentication.php+13 −2 modified@@ -176,13 +176,24 @@ public function verifyRecoveryCode(string $recoveryCode, ?HasAppAuthenticationRe { $user ??= Filament::auth()->user(); + $remainingCodes = []; + $isValid = false; + foreach ($this->getRecoveryCodes($user) as $hashedRecoveryCode) { /** @phpstan-ignore-line */ if (Hash::check($recoveryCode, $hashedRecoveryCode)) { - return true; + $isValid = true; + + continue; } + + $remainingCodes[] = $hashedRecoveryCode; + } + + if ($isValid) { + $user->saveAppAuthenticationRecoveryCodes($remainingCodes); } - return false; + return $isValid; } /**
tests/src/Panels/Auth/MultiFactor/App/AppAuthenticationChallengeTest.php+58 −0 modified@@ -343,3 +343,61 @@ $this->assertGuest(); }); + +it('will not allow a recovery code to be used more than once', function (): void { + $appAuthentication = Arr::first(Filament::getCurrentOrDefaultPanel()->getMultiFactorAuthenticationProviders()); + + $userToAuthenticate = User::factory() + ->hasAppAuthentication($recoveryCodes = $appAuthentication->generateRecoveryCodes()) + ->create(); + + $recoveryCodeToUse = Arr::first($recoveryCodes); + + livewire(Login::class) + ->fillForm([ + 'email' => $userToAuthenticate->email, + 'password' => 'password', + ]) + ->call('authenticate') + ->assertNotSet('userUndertakingMultiFactorAuthentication', null) + ->assertNoRedirect() + ->callAction(TestAction::make('useRecoveryCode') + ->schemaComponent("{$appAuthentication->getId()}.code", schema: 'multiFactorChallengeForm')) + ->fillForm([ + $appAuthentication->getId() => [ + 'recoveryCode' => $recoveryCodeToUse, + ], + ], 'multiFactorChallengeForm') + ->call('authenticate') + ->assertHasNoErrors() + ->assertRedirect(Filament::getUrl()); + + $this->assertAuthenticatedAs($userToAuthenticate); + + auth()->logout(); + + $this->assertGuest(); + + livewire(Login::class) + ->fillForm([ + 'email' => $userToAuthenticate->email, + 'password' => 'password', + ]) + ->call('authenticate') + ->assertNotSet('userUndertakingMultiFactorAuthentication', null) + ->assertNoRedirect() + ->callAction(TestAction::make('useRecoveryCode') + ->schemaComponent("{$appAuthentication->getId()}.code", schema: 'multiFactorChallengeForm')) + ->fillForm([ + $appAuthentication->getId() => [ + 'recoveryCode' => $recoveryCodeToUse, + ], + ], 'multiFactorChallengeForm') + ->call('authenticate') + ->assertHasFormErrors([ + "{$appAuthentication->getId()}.recoveryCode", + ], 'multiFactorChallengeForm') + ->assertNoRedirect(); + + $this->assertGuest(); +});
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4- github.com/advisories/GHSA-pvcv-q3q7-266gghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-67507ghsaADVISORY
- github.com/filamentphp/filament/commit/87ff60ad9b6e16d4e14ee36a220b8917dd7b0815ghsax_refsource_MISCWEB
- github.com/filamentphp/filament/security/advisories/GHSA-pvcv-q3q7-266gghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.