GHSA-HHMC-Q9HP-R662
Vulnerability from github – Published: 2026-08-07 18:23 – Updated: 2026-08-07 18:23Impact
In affected versions, calling UploadedFile::move() without a second argument uses the client-provided filename without sanitization. Depending on the destination path and server configuration, an attacker can supply a filename containing path traversal sequences (e.g. ../../public/shell.php) to write uploaded content outside the intended upload directory.
The patch sanitizes this default (no-argument) path.
Note: The patch only sanitizes the filename when no second argument is passed. If your application explicitly passes a client-provided name as the second argument, you remain responsible for sanitizing it - the patch does not (and cannot) sanitize a caller-supplied filename:
// Unsafe - even after upgrading:
$file->move(WRITEPATH . 'uploads', $file->getName());
$file->move(WRITEPATH . 'uploads', $file->getClientName());
Patches
Upgrade to v4.7.4 or later.
Workarounds
If you cannot upgrade immediately, use a generated filename or sanitize the client filename before passing it to move().
Use a generated filename:
$file->move(WRITEPATH . 'uploads', $file->getRandomName());
Or sanitize the client filename before passing it to move():
helper('security');
$name = sanitize_filename($file->getClientName());
$file->move(WRITEPATH . 'uploads', $name);
{
"affected": [
{
"package": {
"ecosystem": "Packagist",
"name": "codeigniter4/framework"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.7.4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-63222"
],
"database_specific": {
"cwe_ids": [
"CWE-22"
],
"github_reviewed": true,
"github_reviewed_at": "2026-08-07T18:23:46Z",
"nvd_published_at": "2026-07-31T06:16:31Z",
"severity": "HIGH"
},
"details": "### Impact\nIn affected versions, calling `UploadedFile::move()` **without a second argument** uses the client-provided filename without sanitization. Depending on the destination path and server configuration, an attacker can supply a filename containing path traversal sequences (e.g. `../../public/shell.php`) to write uploaded content outside the intended upload directory.\n\nThe patch sanitizes this default (no-argument) path.\n\n**Note:** The patch only sanitizes the filename when no second argument is passed. If your application **explicitly** passes a client-provided name as the second argument, you remain responsible for sanitizing it - the patch does not (and cannot) sanitize a caller-supplied filename:\n```php\n// Unsafe - even after upgrading:\n$file-\u003emove(WRITEPATH . \u0027uploads\u0027, $file-\u003egetName());\n$file-\u003emove(WRITEPATH . \u0027uploads\u0027, $file-\u003egetClientName());\n```\n\n### Patches\nUpgrade to v4.7.4 or later.\n\n### Workarounds\nIf you cannot upgrade immediately, use a generated filename or sanitize the client filename before passing it to `move()`.\n\nUse a generated filename:\n```php\n$file-\u003emove(WRITEPATH . \u0027uploads\u0027, $file-\u003egetRandomName());\n```\nOr sanitize the client filename before passing it to `move()`:\n```php\nhelper(\u0027security\u0027);\n\n$name = sanitize_filename($file-\u003egetClientName());\n$file-\u003emove(WRITEPATH . \u0027uploads\u0027, $name);\n```",
"id": "GHSA-hhmc-q9hp-r662",
"modified": "2026-08-07T18:23:46Z",
"published": "2026-08-07T18:23:46Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/codeigniter4/CodeIgniter4/security/advisories/GHSA-hhmc-q9hp-r662"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-63222"
},
{
"type": "WEB",
"url": "https://github.com/codeigniter4/CodeIgniter4/commit/20ebcf4694d96d3c97fbc3938e360730e4f54618"
},
{
"type": "PACKAGE",
"url": "https://github.com/codeigniter4/CodeIgniter4"
},
{
"type": "WEB",
"url": "https://github.com/codeigniter4/CodeIgniter4/releases/tag/v4.7.4"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N",
"type": "CVSS_V3"
}
],
"summary": "CodeIgniter: Path traversal in UploadedFile::move() when using client-provided filenames"
}
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.