diff --git a/system/Session/Session.php b/system/Session/Session.php index 1c3824928775..c1db491cb4d1 100644 --- a/system/Session/Session.php +++ b/system/Session/Session.php @@ -303,6 +303,14 @@ public function set($data, $value = null) } foreach ($data as $sessionKey => $sessionValue) { + if (is_string($sessionKey) && str_starts_with($sessionKey, '__ci_')) { + log_message('warning', 'Session key "{key}" is reserved for framework use and was not set.', [ + 'key' => $sessionKey, + ]); + + continue; + } + $_SESSION[$sessionKey] = $sessionValue; } } @@ -370,6 +378,10 @@ public function remove($key) */ public function __set(string $key, $value) { + if (str_starts_with($key, '__ci_')) { + return; + } + $_SESSION[$key] = $value; } diff --git a/tests/system/Session/SessionTest.php b/tests/system/Session/SessionTest.php index 3b7cd3860ccd..e53a44a6b61e 100644 --- a/tests/system/Session/SessionTest.php +++ b/tests/system/Session/SessionTest.php @@ -328,6 +328,30 @@ public function testSetMagicMethod(): void $this->assertSame('bar', $_SESSION['foo']); } + public function testSetIgnoresCiVars(): void + { + $session = $this->getInstance(); + $session->start(); + + $session->set('__ci_vars', 'malicious'); + $session->set('__ci_last_regenerate', 'malicious'); + + $this->assertArrayNotHasKey('__ci_vars', $_SESSION); + $this->assertNotSame('malicious', $_SESSION['__ci_last_regenerate']); + } + + public function testSetMagicMethodIgnoresCiVars(): void + { + $session = $this->getInstance(); + $session->start(); + + $session->__ci_vars = 'malicious'; // @phpstan-ignore property.notFound + $session->__ci_last_regenerate = 'malicious'; // @phpstan-ignore property.notFound + + $this->assertArrayNotHasKey('__ci_vars', $_SESSION); + $this->assertNotSame('malicious', $_SESSION['__ci_last_regenerate']); + } + public function testCanFlashData(): void { $session = $this->getInstance();