Security advisory GHSA-w6jr-wj64-mc9x: Deserialization of Untrusted Data in Codeigniter4
Package: codeigniter4/framework (composer), vulnerable version: v4.1.5, fixed in: 4.1.6
CWE: CWE-502
Files changed by the fix:
system/Common.php

Fix diff:
diff --git a/SECURITY.md b/SECURITY.md
index 7879188492b5..87b894ee713c 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -20,6 +20,7 @@ This person will coordinate the fix and release process, involving the following
 - Confirm the problem and determine the affected versions.
 - Audit code to find any potential similar problems.
 - Prepare fixes for all releases still under maintenance. These fixes will be released as fast as possible.
+- Publish security advisories at https://github.com/codeigniter4/CodeIgniter4/security/advisories
 
 ## Comments on this Policy
 
diff --git a/system/Common.php b/system/Common.php
index 567135babe1f..e132d982b7d4 100644
--- a/system/Common.php
+++ b/system/Common.php
@@ -810,11 +810,6 @@ function old(string $key, $default = null, $escape = 'html')
             return $default;
         }
 
-        // If the result was serialized array or string, then unserialize it for use...
-        if (is_string($value) && (strpos($value, 'a:') === 0 || strpos($value, 's:') === 0)) {
-            $value = unserialize($value);
-        }
-
         return $escape === false ? $value : esc($value, $escape);
     }
 }
diff --git a/tests/system/CommonFunctionsTest.php b/tests/system/CommonFunctionsTest.php
index b7f4f381c233..3916a1ab785f 100644
--- a/tests/system/CommonFunctionsTest.php
+++ b/tests/system/CommonFunctionsTest.php
@@ -301,7 +301,7 @@ public function testOldInput()
         $_GET     = ['foo' => 'bar'];
         $_POST    = [
             'bar'    => 'baz',
-            'zibble' => serialize('fritz'),
+            'zibble' => 'fritz',
         ];
 
         $response = new RedirectResponse(new App());
@@ -309,7 +309,40 @@ public function testOldInput()
 
         $this->assertSame('bar', old('foo')); // regular parameter
         $this->assertSame('doo', old('yabba dabba', 'doo')); // non-existing parameter
-        $this->assertSame('fritz', old('zibble')); // serialized parameter
+        $this->assertSame('fritz', old('zibble'));
+    }
+
+    /**
+     * @runInSeparateProcess
+     * @preserveGlobalState  disabled
+     */
+    public function testOldInputSerializeData()
+    {
+        $this->injectSessionMock();
+        // setup from RedirectResponseTest...
+        $_SERVER['REQUEST_METHOD'] = 'GET';
+
+        $this->config          = new App();
+        $this->config->baseURL = 'http://example.com/';
+
+        $this->routes = new RouteCollection(Services::locator(), new Modules());
+        Services::injectMock('routes', $this->routes);
+
+        $this->request = new MockIncomingRequest($this->config, new URI('http://example.com'), null, new UserAgent());
+        Services::injectMock('request', $this->request);
+
+        // setup & ask for a redirect...
+        $_SESSION = [];
+        $_GET     = [];
+        $_POST    = [
+            'zibble' => serialize('fritz'),
+        ];
+
+        $response = new RedirectResponse(new App());
+        $response->withInput();
+
+        // serialized parameters are only HTML-escaped.
+        $this->assertSame('s:5:&quot;fritz&quot;;', old('zibble'));
     }
 
     /**
diff --git a/tests/system/HTTP/IncomingRequestTest.php b/tests/system/HTTP/IncomingRequestTest.php
index 4229d5d264ec..e8c91268a8e2 100644
--- a/tests/system/HTTP/IncomingRequestTest.php
+++ b/tests/system/HTTP/IncomingRequestTest.php
@@ -107,8 +107,10 @@ public function testMissingOldInput()
         $this->assertNull($this->request->getOldInput('pineapple.name'));
     }
 
-    // Reference: https://github.com/codeigniter4/CodeIgniter4/issues/1492
-    public function testCanGetOldInputArray()
+    /**
+     * @see https://github.com/codeigniter4/CodeIgniter4/issues/1492
+     */
+    public function testCanGetOldInputArrayWithSESSION()
     {
         $_SESSION['_ci_old_input'] = [
             'get'  => ['apple' => ['name' => 'two']],
@@ -119,13 +121,13 @@ public function testCanGetOldInputArray()
         $this->assertSame(['name' => 'foo'], $this->request->getOldInput('banana'));
     }
 
-    // Reference: https://github.com/codeigniter4/CodeIgniter4/issues/1492
-
     /**
+     * @see https://github.com/codeigniter4/CodeIgniter4/issues/1492
+     *
      * @runInSeparateProcess
      * @preserveGlobalState  disabled
      */
-    public function testCanSerializeOldArray()
+    public function testCanGetOldInputArrayWithSessionService()
     {
         $locations = [
             'AB' => 'Alberta',
diff --git a/user_guide_src/source/changelogs/v4.1.6.rst b/user_guide_src/source/changelogs/v4.1.6.rst
index 61214596ea97..cdbb08cb8e97 100644
--- a/user_guide_src/source/changelogs/v4.1.6.rst
+++ b/user_guide_src/source/changelogs/v4.1.6.rst
@@ -9,6 +9,11 @@ Release Date: Not released
     :local:
     :depth: 2
 
+SECURITY
+********
+
+- *Deserialization of Untrusted Data* found in the ``old()`` function was fixed. See the `Security advisory <https://github.com/codeigniter4/CodeIgniter4/security/advisories/GHSA-w6jr-wj64-mc9x>`_ for more information.
+
 BREAKING
 ********