GHSA-cxf4-7mrp-vvpr

Suggest an improvement
Source
https://github.com/advisories/GHSA-cxf4-7mrp-vvpr
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/09/GHSA-cxf4-7mrp-vvpr/GHSA-cxf4-7mrp-vvpr.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-cxf4-7mrp-vvpr
Aliases
Published
2026-09-29T18:10:14Z
Modified
2026-09-29T18:15:05Z
Severity
  • 3.5 (Low) CVSS_V3 - CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:L/A:N CVSS Calculator
Summary
Flysystem: WhitespacePathNormalizer's control-character (CorruptedPathDetected) check is bypassed by malformed UTF-8 in the path, affecting every adapter
Details

Related public issue (context, not a duplicate)

Closed issue #1429 ("Handle non-UTF-8 paths", 2024-03-24) raised exactly this general concern and even suggested detection via preg_match('//u', $path) !== 1 -- note the reporter's suggested check explicitly compares !== 1, which would correctly treat PCRE's false return as "reject." The maintainer's reply pointed to the PathNormalizer interface as the place to implement this. The control-character check that ended up shipping in WhitespacePathNormalizer (if (preg_match('#\p{C}+#u', $unixPath))) addresses the general concern but does not use the !== 1-style comparison the original issue suggested -- it uses a bare truthy check, which is exactly the gap this report demonstrates. So this is not a duplicate of #1429; it's a concrete bypass surviving in the fix that issue's concern led to.

Vulnerability Details

File: src/WhitespacePathNormalizer.php, lines 22-28 (normalizePath()) -- the default PathNormalizer used by Filesystem for every adapter (Local, FTP, SFTP, S3, AsyncAwsS3, Azure, GCS, ZipArchive, GridFS, InMemory) unless the application supplies a custom one.

Root Cause

public function normalizePath(string $path): string
{
    $unixPath = str_replace('\\', '/', $path);

    if (preg_match('#\p{C}+#u', $unixPath)) {
        throw CorruptedPathDetected::forPath($path);
    }
    ...

preg_match() returns false (a PHP engine error) rather than 0 when the subject string is not valid UTF-8 and the pattern uses the /u modifier -- PCRE can't even attempt the match. false and 0 are both falsy in PHP, and if (preg_match(...)) does not distinguish them. So a path containing any single invalid UTF-8 byte anywhere in the string makes preg_match() fail with a "Malformed UTF-8 characters" engine error, the if evaluates false, and CorruptedPathDetected is silently not thrown -- even when the same string also contains literal control characters this exact check exists to catch.

the identical payload IS correctly rejected once it's valid UTF-8:

$n->normalizePath("foo\x1bbar");         // valid UTF-8, contains ESC -> throws CorruptedPathDetected (correct)
$n->normalizePath("foo\x80\x1bbar");    // 0x80 = invalid lone UTF-8 continuation byte -> NOT thrown (bypass)

The path-traversal protection is unaffected -- it's exact byte-string comparison on /-delimited segments, independent of UTF-8 validity:

$n->normalizePath("\x80/../../etc/passwd");   // still throws PathTraversalDetected

Recommended Fix

public function normalizePath(string $path): string
{
    $unixPath = str_replace('\\', '/', $path);
    $matched = preg_match('#\p{C}+#u', $unixPath);

    if ($matched !== 0) {
        // $matched === false means malformed UTF-8 -- must also be treated as corrupted,
        // not silently allowed through.
        throw CorruptedPathDetected::forPath($path);
    }
    ...

Verification

Dynamically confirmed on league/flysystem HEAD 6837e1d / tag 3.35.2, PHP 8.4.22 CLI, end-to-end through LocalFilesystemAdapter:

[1] write() succeeded -- normalizer did NOT reject the path.
[2] Actual bytes on disk: ...801b5b386d6e6f726d616c2d6c6f6f6b696e672d66696c652e7478741b5b306d...
[3] Filesystem::listContents() path contains raw ESC (0x1b): YES
[4] Raw terminal output (via `cat -v`): M-^@^[[8mnormal-looking-file.txt^[[0m^[[2K^[[1Aurgent-invoice.pdf
Database specific
{
    "cwe_ids":  [
        "CWE-150"
    ],
    "github_reviewed":  true,
    "github_reviewed_at":  "2026-09-29T18:10:14Z",
    "nvd_published_at":  null,
    "severity":  "LOW"
}
References

Affected packages

Packagist / league/flysystem

Package

Name
league/flysystem
Purl
pkg:composer/league/flysystem

Affected ranges

Type
ECOSYSTEM
Events
Introduced
0 Unknown introduced version / All previous versions are affected
Fixed
3.35.3

Affected versions

0.*
0.1.0
0.1.1
0.1.2
0.1.3
0.1.4
0.1.5
0.1.6
0.1.7
0.1.8
0.1.9
0.1.10
0.1.11
0.1.12
0.1.13
0.1.14
0.1.15
0.1.16
0.1.17
0.1.18
0.1.19
0.1.20
0.2.0
0.2.1
0.2.2
0.2.3
0.2.4
0.2.5
0.2.6
0.2.7
0.2.8
0.2.9
0.2.10
0.2.11
0.2.12
0.2.13
0.2.14
0.2.15
0.3.0
0.3.1
0.3.2
0.3.3
0.3.4
0.3.5
0.4.0
0.4.1
0.4.2
0.4.3
0.4.4
0.4.5
0.5.0
0.5.1
0.5.2
0.5.3
0.5.4
0.5.5
0.5.6
0.5.7
0.5.8
0.5.9
0.5.10
0.5.11
0.5.12
1.*
1.0.0-alpha1
1.0.0
1.0.1
1.0.2
1.0.3
1.0.4
1.0.5
1.0.6
1.0.7
1.0.8
1.0.9
1.0.10
1.0.11
1.0.12
1.0.13
1.0.14
1.0.15
1.0.16
1.0.17
1.0.18
1.0.19
1.0.20
1.0.21
1.0.22
1.0.23
1.0.24
1.0.25
1.0.26
1.0.27
1.0.28
1.0.29
1.0.30
1.0.31
1.0.32
1.0.33
1.0.34
1.0.35
1.0.36
1.0.37
1.0.38
1.0.39
1.0.40
1.0.41
1.0.42
1.0.43
1.0.44
1.0.45
1.0.46
1.0.47
1.0.48
1.0.49
1.0.50
1.0.51
1.0.52
1.0.53
1.0.54
1.0.55
1.0.56
1.0.57
1.0.58
1.0.59
1.0.60
1.0.61
1.0.62
1.0.63
1.0.64
1.0.65
1.0.66
1.0.67
1.0.68
1.0.69
1.0.70
1.1.0
1.1.1
1.1.2
1.1.3
1.1.4
1.1.5
1.1.6
1.1.7
1.1.8
1.1.9
1.1.10
2.*
2.0.0-alpha.1
2.0.0-alpha.2
2.0.0-alpha.3
2.0.0-alpha.4
2.0.0-beta.1
2.0.0-beta.2
2.0.0-beta.3
2.0.0-RC1
2.0.0
2.0.1
2.0.2
2.0.3
2.0.4
2.0.5
2.0.6
2.0.7
2.0.8
2.1.0
2.1.1
2.2.0
2.2.1
2.2.2
2.2.3
2.3.0
2.3.1
2.3.2
2.4.0
2.4.1
2.4.2
2.4.3
2.4.4
2.4.5
2.5.0
3.*
3.0.0
3.0.1
3.0.2
3.0.3
3.0.4
3.0.5
3.0.6
3.0.7
3.0.8
3.0.9
3.0.10
3.0.11
3.0.12
3.0.13
3.0.14
3.0.15
3.0.16
3.0.17
3.0.18
3.0.19
3.0.20
3.0.21
3.0.22
3.0.23
3.1.0
3.1.1
3.2.0
3.2.1
3.3.0
3.4.0
3.5.0
3.5.1
3.5.2
3.6.0
3.7.0
3.8.0
3.9.0
3.10.0
3.10.1
3.10.2
3.10.3
3.10.4
3.11.0
3.12.0
3.12.1
3.12.2
3.12.3
3.13.0
3.14.0
3.15.0
3.15.1
3.16.0
3.17.0
3.18.0
3.19.0
3.20.0
3.21.0
3.22.0
3.23.0
3.23.1
3.24.0
3.25.0
3.25.1
3.26.0
3.27.0
3.28.0
3.29.0
3.29.1
3.30.0
3.30.1
3.30.2
3.31.0
3.32.0
3.33.0
3.34.0
3.35.0
3.35.1
3.35.2

Database specific

last_known_affected_version_range
"<= 3.35.2"
source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/09/GHSA-cxf4-7mrp-vvpr/GHSA-cxf4-7mrp-vvpr.json"