Insertion of Sensitive Information into Log in codeigniter4/shield
Description
CodeIgniter Shield is an authentication and authorization provider for CodeIgniter 4. In affected versions successful login attempts are recorded with the raw tokens stored in the log table. If a malicious person somehow views the data in the log table they can obtain a raw token which can then be used to send a request with that user's authority. This issue has been addressed in version 1.0.0-beta.8. Users are advised to upgrade. Users unable to upgrade should disable logging for successful login attempts by the configuration files.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
codeigniter4/shieldPackagist | < 1.0.0-beta.8 | 1.0.0-beta.8 |
Affected products
1- Range: < 1.0.0-beta.8
Patches
17e84c3fb3411Merge pull request from GHSA-j72f-h752-mx4w
12 files changed · +174 −70
docs/addons/jwt.md+26 −2 modified@@ -34,9 +34,9 @@ To use JWT Authentication, you need additional setup and configuration. ```php <?php - + // app/Config/AuthJWT.php - + declare(strict_types=1); namespace Config; @@ -128,6 +128,19 @@ php -r 'echo base64_encode(random_bytes(32));' The secret key is used for signing and validating tokens. +### Login Attempt Logging + +By default, only failed login attempts are recorded in the `auth_token_logins` table. + +```php +public int $recordLoginAttempt = Auth::RECORD_LOGIN_ATTEMPT_FAILURE; +``` + +If you don't want any logs, set it to `Auth::RECORD_LOGIN_ATTEMPT_NONE`. + +If you want to log all login attempts, set it to `Auth::RECORD_LOGIN_ATTEMPT_ALL`. +It means you log all requests. + ## Issuing JWTs To use JWT Authentication, you need a controller that issues JWTs. @@ -351,3 +364,14 @@ It uses the `secret` and `alg` in the `Config\AuthJWT::$keys['default']`. It sets the `Config\AuthJWT::$defaultClaims` to the token, and sets `"iat"` (Issued At) and `"exp"` (Expiration Time) claims automatically even if you don't pass them. + +## Logging + +Login attempts are recorded in the `auth_token_logins` table, according to the +configuration above. + +When a failed login attempt is logged, the raw token value sent is saved in +the `identifier` column. + +When a successful login attempt is logged, the SHA256 hash value of the token +sent is saved in the `identifier` column.
docs/getting_started/configuration.md+3 −15 modified@@ -8,20 +8,8 @@ If you have completed the setup according to this documentation, you will have the following configuration files: - **app/Config/Auth.php** -- **app/Config/AuthGroups.php** - For Authorization -- **app/Config/AuthToken.php** - For AccessTokens and HmacSha256 Authentication -- **app/Config/AuthJWT.php** - For JWT Authentication +- **app/Config/AuthGroups.php** - For [Authorization](../references/authorization.md) +- **app/Config/AuthToken.php** - For [AccessTokens](../references/authentication/tokens.md#configuration) and [HmacSha256](../references/authentication/hmac.md#configuration) Authentication +- **app/Config/AuthJWT.php** - For [JWT Authentication](../addons/jwt.md#configuration) Note that you do not need to have configuration files for features you do not use. - -This section describes the major Config items that are not described elsewhere. - -## AccessTokens Authenticator - -### Access Token Lifetime - -By default, Access Tokens can be used for 1 year since the last use. This can be easily modified in the **app/Config/AuthToken.php** config file. - -```php -public int $unusedTokenLifetime = YEAR; -```
docs/references/authentication/hmac.md+47 −14 modified@@ -112,20 +112,6 @@ $token = $user->getHmacTokenById($id); $tokens = $user->hmacTokens(); ``` -## HMAC Keys Lifetime - -HMAC Keys/Tokens will expire after a specified amount of time has passed since they have been used. -This uses the same configuration value as AccessTokens. - -By default, this is set to 1 year. You can change this value by setting the `$unusedTokenLifetime` -value in the **app/Config/AuthToken.php** config file. This is in seconds so that you can use the -[time constants](https://codeigniter.com/user_guide/general/common_functions.html#time-constants) -that CodeIgniter provides. - -```php -public $unusedTokenLifetime = YEAR; -``` - ## HMAC Keys Scopes Each token (set of keys) can be given one or more scopes they can be used within. These can be thought of as @@ -219,3 +205,50 @@ authtoken.hmacEncryptionCurrentKey = k2 Depending on the set length of the Secret Key and the type of encryption used, it is possible for the encrypted value to exceed the database column character limit of 255 characters. If this happens, creation of a new HMAC identity will throw a `RuntimeException`. + +## Configuration + +Configure **app/Config/AuthToken.php** for your needs. + +!!! note + + Shield does not expect you use the Access Token Authenticator and HMAC Authenticator + at the same time. Therefore, some Config items are common. + +### HMAC Keys Lifetime + +HMAC Keys/Tokens will expire after a specified amount of time has passed since they have been used. + +By default, this is set to 1 year. You can change this value by setting the `$unusedTokenLifetime` +value. This is in seconds so that you can use the +[time constants](https://codeigniter.com/user_guide/general/common_functions.html#time-constants) +that CodeIgniter provides. + +```php +public $unusedTokenLifetime = YEAR; +``` + +### Login Attempt Logging + +By default, only failed login attempts are recorded in the `auth_token_logins` table. +This can be modified by changing the `$recordLoginAttempt` value. + +```php +public int $recordLoginAttempt = Auth::RECORD_LOGIN_ATTEMPT_FAILURE; +``` + +If you don't want any logs, set it to `Auth::RECORD_LOGIN_ATTEMPT_NONE`. + +If you want to log all login attempts, set it to `Auth::RECORD_LOGIN_ATTEMPT_ALL`. +It means you log all requests. + +## Logging + +Login attempts are recorded in the `auth_token_logins` table, according to the +configuration above. + +When a failed login attempt is logged, the raw token value sent is saved in +the `identifier` column. + +When a successful login attempt is logged, the token name is saved in the +`identifier` column.
docs/references/authentication/tokens.md+49 −12 modified@@ -83,18 +83,6 @@ $token = $user->getAccessTokenById($id); $tokens = $user->accessTokens(); ``` -## Access Token Lifetime - -Tokens will expire after a specified amount of time has passed since they have been used. -By default, this is set to 1 year. You can change this value by setting the `$unusedTokenLifetime` -value in the **app/Config/AuthToken.php** config file. This is in seconds so that you can use the -[time constants](https://codeigniter.com/user_guide/general/common_functions.html#time-constants) -that CodeIgniter provides. - -```php -public $unusedTokenLifetime = YEAR; -``` - ## Access Token Scopes Each token can be given one or more scopes they can be used within. These can be thought of as @@ -125,3 +113,52 @@ if ($user->tokenCant('forums.manage')) { // do something.... } ``` + +## Configuration + +Configure **app/Config/AuthToken.php** for your needs. + +!!! note + + Shield does not expect you use the Access Token Authenticator and HMAC Authenticator + at the same time. Therefore, some Config items are common. + +### Access Token Lifetime + +Tokens will expire after a specified amount of time has passed since they have been used. + +By default, this is set to 1 year. +You can change this value by setting the `$unusedTokenLifetime` value. This is +in seconds so that you can use the +[time constants](https://codeigniter.com/user_guide/general/common_functions.html#time-constants) +that CodeIgniter provides. + +```php +public $unusedTokenLifetime = YEAR; +``` + +### Login Attempt Logging + +By default, only failed login attempts are recorded in the `auth_token_logins` table. + +This can be modified by changing the `$recordLoginAttempt` value. + +```php +public int $recordLoginAttempt = Auth::RECORD_LOGIN_ATTEMPT_FAILURE; +``` + +If you don't want any logs, set it to `Auth::RECORD_LOGIN_ATTEMPT_NONE`. + +If you want to log all login attempts, set it to `Auth::RECORD_LOGIN_ATTEMPT_ALL`. +It means you log all requests. + +## Logging + +Login attempts are recorded in the `auth_token_logins` table, according to the +configuration above. + +When a failed login attempt is logged, the raw token value sent is saved in +the `identifier` column. + +When a successful login attempt is logged, the token name is saved in the +`identifier` column.
phpstan-baseline.php+0 −5 modified@@ -361,11 +361,6 @@ 'count' => 1, 'path' => __DIR__ . '/src/Models/UserModel.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Call to method PHPUnit\\\\Framework\\\\Assert\\:\\:assertInstanceOf\\(\\) with \'CodeIgniter\\\\\\\\Shield\\\\\\\\Result\' and CodeIgniter\\\\Shield\\\\Result will always evaluate to true\\.$#', - 'count' => 2, - 'path' => __DIR__ . '/tests/Authentication/Authenticators/AccessTokenAuthenticatorTest.php', -]; $ignoreErrors[] = [ 'message' => '#^Call to method PHPUnit\\\\Framework\\\\Assert\\:\\:assertInstanceOf\\(\\) with \'CodeIgniter\\\\\\\\Shield\\\\\\\\Result\' and CodeIgniter\\\\Shield\\\\Result will always evaluate to true\\.$#', 'count' => 3,
src/Authentication/Authenticators/AccessTokens.php+5 −6 modified@@ -77,14 +77,15 @@ public function attempt(array $credentials): Result return $result; } - $user = $result->extraInfo(); + $user = $result->extraInfo(); + $token = $user->getAccessToken($this->getBearerToken()); if ($user->isBanned()) { if ($config->recordLoginAttempt >= Auth::RECORD_LOGIN_ATTEMPT_FAILURE) { // Record a banned login attempt. $this->loginModel->recordLoginAttempt( self::ID_TYPE_ACCESS_TOKEN, - $credentials['token'] ?? '', + $token->name ?? '', false, $ipAddress, $userAgent, @@ -100,17 +101,15 @@ public function attempt(array $credentials): Result ]); } - $user = $user->setAccessToken( - $user->getAccessToken($this->getBearerToken()) - ); + $user = $user->setAccessToken($token); $this->login($user); if ($config->recordLoginAttempt === Auth::RECORD_LOGIN_ATTEMPT_ALL) { // Record a successful login attempt. $this->loginModel->recordLoginAttempt( self::ID_TYPE_ACCESS_TOKEN, - $credentials['token'] ?? '', + $token->name ?? '', true, $ipAddress, $userAgent,
src/Authentication/Authenticators/HmacSha256.php+5 −6 modified@@ -78,14 +78,15 @@ public function attempt(array $credentials): Result return $result; } - $user = $result->extraInfo(); + $user = $result->extraInfo(); + $token = $user->getHmacToken($this->getHmacKeyFromToken()); if ($user->isBanned()) { if ($config->recordLoginAttempt >= Auth::RECORD_LOGIN_ATTEMPT_FAILURE) { // Record a banned login attempt. $this->loginModel->recordLoginAttempt( self::ID_TYPE_HMAC_TOKEN, - $credentials['token'] ?? '', + $token->name ?? '', false, $ipAddress, $userAgent, @@ -101,17 +102,15 @@ public function attempt(array $credentials): Result ]); } - $user = $user->setHmacToken( - $user->getHmacToken($this->getHmacKeyFromToken()) - ); + $user = $user->setHmacToken($token); $this->login($user); if ($config->recordLoginAttempt === Auth::RECORD_LOGIN_ATTEMPT_ALL) { // Record a successful login attempt. $this->loginModel->recordLoginAttempt( self::ID_TYPE_HMAC_TOKEN, - $credentials['token'] ?? '', + $token->name ?? '', true, $ipAddress, $userAgent,
src/Authentication/Authenticators/JWT.php+2 −2 modified@@ -103,7 +103,7 @@ public function attempt(array $credentials): Result // Record a banned login attempt. $this->tokenLoginModel->recordLoginAttempt( self::ID_TYPE_JWT, - $credentials['token'] ?? '', + 'sha256:' . hash('sha256', $credentials['token'] ?? ''), false, $ipAddress, $userAgent, @@ -125,7 +125,7 @@ public function attempt(array $credentials): Result // Record a successful login attempt. $this->tokenLoginModel->recordLoginAttempt( self::ID_TYPE_JWT, - $credentials['token'] ?? '', + 'sha256:' . hash('sha256', $credentials['token']), true, $ipAddress, $userAgent,
src/Config/AuthToken.php+1 −1 modified@@ -46,7 +46,7 @@ class AuthToken extends BaseAuthToken /** * -------------------------------------------------------------------- - * Unused Token Lifetime + * Unused Token Lifetime for Token Auth and HMAC Auth * -------------------------------------------------------------------- * Determines the amount of time, in seconds, that an unused token can * be used.
tests/Authentication/Authenticators/AccessTokenAuthenticatorTest.php+32 −3 modified@@ -17,11 +17,11 @@ use CodeIgniter\Shield\Authentication\Authentication; use CodeIgniter\Shield\Authentication\Authenticators\AccessTokens; use CodeIgniter\Shield\Config\Auth; +use CodeIgniter\Shield\Config\AuthToken; use CodeIgniter\Shield\Entities\AccessToken; use CodeIgniter\Shield\Entities\User; use CodeIgniter\Shield\Models\UserIdentityModel; use CodeIgniter\Shield\Models\UserModel; -use CodeIgniter\Shield\Result; use CodeIgniter\Test\Mock\MockEvents; use Config\Services; use Tests\Support\DatabaseTestCase; @@ -182,7 +182,6 @@ public function testAttemptCannotFindUser(): void 'token' => 'abc123', ]); - $this->assertInstanceOf(Result::class, $result); $this->assertFalse($result->isOK()); $this->assertSame(lang('Auth.badToken'), $result->reason()); @@ -205,7 +204,6 @@ public function testAttemptSuccess(): void 'token' => $token->raw_token, ]); - $this->assertInstanceOf(Result::class, $result); $this->assertTrue($result->isOK()); $foundUser = $result->extraInfo(); @@ -222,6 +220,37 @@ public function testAttemptSuccess(): void ]); } + public function testAttemptSuccessLog(): void + { + // Change $recordLoginAttempt in Config. + /** @var AuthToken $config */ + $config = config('AuthToken'); + $config->recordLoginAttempt = Auth::RECORD_LOGIN_ATTEMPT_ALL; + + /** @var User $user */ + $user = fake(UserModel::class); + $token = $user->generateAccessToken('foo'); + $this->setRequestHeader($token->raw_token); + + $result = $this->auth->attempt([ + 'token' => $token->raw_token, + ]); + + $this->assertTrue($result->isOK()); + + $foundUser = $result->extraInfo(); + $this->assertInstanceOf(User::class, $foundUser); + $this->assertSame($user->id, $foundUser->id); + $this->assertInstanceOf(AccessToken::class, $foundUser->currentAccessToken()); + $this->assertSame($token->token, $foundUser->currentAccessToken()->token); + + $this->seeInDatabase($this->tables['token_logins'], [ + 'id_type' => AccessTokens::ID_TYPE_ACCESS_TOKEN, + 'identifier' => 'foo', + 'success' => 1, + ]); + } + protected function setRequestHeader(string $token): void { $request = service('request');
tests/Authentication/Authenticators/HmacAuthenticatorTest.php+2 −2 modified@@ -273,7 +273,7 @@ public function testAttemptSuccess(): void // A login attempt should have been recorded $this->seeInDatabase($this->tables['token_logins'], [ 'id_type' => HmacSha256::ID_TYPE_HMAC_TOKEN, - 'identifier' => $rawToken, + 'identifier' => 'foo', 'success' => 1, ]); @@ -310,7 +310,7 @@ public function testAttemptBanned(): void // A login attempt should have been recorded $this->seeInDatabase($this->tables['token_logins'], [ 'id_type' => HmacSha256::ID_TYPE_HMAC_TOKEN, - 'identifier' => $rawToken, + 'identifier' => 'foo', 'success' => 0, ]); }
tests/Authentication/Authenticators/JWTAuthenticatorTest.php+2 −2 modified@@ -226,7 +226,7 @@ public function testAttemptBannedUser(): void // The login attempt should have been recorded $this->seeInDatabase('auth_token_logins', [ 'id_type' => JWT::ID_TYPE_JWT, - 'identifier' => $token, + 'identifier' => 'sha256:' . hash('sha256', $token), 'success' => 0, 'user_id' => $this->user->id, ]); @@ -256,7 +256,7 @@ public function testAttemptSuccess(): void // A login attempt should have been recorded $this->seeInDatabase('auth_token_logins', [ 'id_type' => JWT::ID_TYPE_JWT, - 'identifier' => $token, + 'identifier' => 'sha256:' . hash('sha256', $token), 'success' => 1, ]); }
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-j72f-h752-mx4wghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2023-48708ghsaADVISORY
- codeigniter4.github.io/shield/getting_started/authenticatorsghsaWEB
- codeigniter4.github.io/shield/getting_started/authenticators/mitrex_refsource_MISC
- github.com/codeigniter4/shield/commit/7e84c3fb3411294f70890819bfe51781bb9dc8e4ghsax_refsource_MISCWEB
- github.com/codeigniter4/shield/security/advisories/GHSA-j72f-h752-mx4wghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.