Skip to content

Path traversal in `make:controller` CLI creates arbitrary directories outside project root

Moderate
n0nag0n published GHSA-3xjv-pmf2-gf2q Apr 29, 2026

Package

composer flightphp/core (Composer)

Affected versions

< 3.18.1

Patched versions

3.18.1

Description

Summary

The make:controller CLI command calls mkdir(..., recursive: true) on a path built from the user-supplied controller name, before Nette's class-name validation runs. The class-file write is correctly rejected by Nette when the name contains /, but the recursive directory creation side effect is already committed — including directories located outside the project root through ../ traversal.

Affected code

flight/commands/ControllerCommand.php (≈ 63-66):

if (is_dir(dirname($controllerPath)) === false) {
    $io->info('Creating directory ' . dirname($controllerPath), true);
    mkdir(dirname($controllerPath), 0755, true);   // un-normalized, runs before validation
}

Proof of concept

$ php vendor/flightphp/runway/runway make:controller '../../../../tmp/CONTROLLER_TRAVERSAL_TEST/pwn'
Creating directory .../app/controllers/../../../../tmp/CONTROLLER_TRAVERSAL_TEST
Nette\InvalidArgumentException: Value '../../../../tmp/CONTROLLER_TRAVERSAL_TEST/pwnController' is not valid class name.

$ ls /home/user/tmp/CONTROLLER_TRAVERSAL_TEST
(directory exists — created before the exception was thrown)

Impact

  • Arbitrary directory creation outside the project root, executable by any local actor that can run the Flight CLI (developer machine, shared CI build agent, compromised dev container).
  • Primes log-file planting for chained LFI exploitation (e.g. creating a directory where an attacker can later drop a .php file to be included via a distinct template-include weakness).
  • On Windows, the \ separator opens additional traversal surface.

Patch (fixed in 3.18.1, commit b8dd23a)

The controller name is now normalized with basename() and validated against ^[A-Za-z_][A-Za-z0-9_]*$ before any mkdir side effect runs.

Credit

Discovered by @Rootingg.

Severity

Moderate

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Local
Attack complexity
Low
Privileges required
Low
User interaction
None
Scope
Unchanged
Confidentiality
None
Integrity
Low
Availability
Low

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L

CVE ID

CVE-2026-42549

Weaknesses

Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')

The product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory. Learn more on MITRE.

Credits