CVE-2021-32708 (published 2021-06-24T17:15Z)

Flysystem is an open source file storage library for PHP. The whitespace normalisation using in 1.x and 2.x removes any unicode whitespace. Under certain specific conditions this could potentially allow a malicious user to execute code remotely. The conditions are: A user is allowed to supply the path or filename of an uploaded file, the supplied path or filename is not checked against unicode chars, the supplied pathname checked against an extension deny-list, not an allow-list, the supplied path or filename contains a unicode whitespace char in the extension, the uploaded file is stored in a directory that allows PHP code to be executed. Given these conditions are met a user can upload and execute arbitrary code on the system under attack. The unicode whitespace removal has been replaced with a rejection (exception). For 1.x users, upgrade to 1.1.4. For 2.x users, upgrade to 2.1.1.

Severity: HIGH
CVSS v2 base score: 9.3 (AV:N/AC:M/Au:N/C:C/I:C/A:C)
CVSS v3 base score: 8.1, HIGH (CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-367
cwe_name: Time-of-check Time-of-use (TOCTOU) Race Condition
description: The product checks the state of a resource before using that resource, but the resource's state can change between the check and the use in a way that invalidates the results of the check. This can cause the product to perform invalid actions when the resource is in an unexpected state.
extended_description: This weakness can be security-relevant when an attacker can influence the state of the resource between check and use. This can happen with shared resources such as files, memory, or even variables in multithreaded programs.
         

Fix information:
repo_url: https://github.com/thephpleague/flysystem
commit_details: repo_url: https://github.com/thephpleague/flysystem
author: Frank de Jonge
author_date: 2021-06-24 00:07:10+02:00
msg: Reject funky whitspace paths.
repository: repo_url: https://github.com/thephpleague/flysystem
repo_name: thephpleague/flysystem
description: Abstraction for local and remote filesystems
repo_language: PHP
owner: thephpleague
file_changes: filename: CorruptedPathDetected.php
change_type: ModificationType.ADD
diff: @@ -0,0 +1,13 @@
+<?php
+
+namespace League\Flysystem;
+
+use RuntimeException;
+
+final class CorruptedPathDetected extends RuntimeException implements FilesystemException
+{
+    public static function forPath(string $path): CorruptedPathDetected
+    {
+        return new CorruptedPathDetected("Corrupted path detected: " . $path);
+    }
+}

programming_language: PHP
filename: WhitespacePathNormalizer.php
change_type: ModificationType.MODIFY
diff: @@ -9,21 +9,16 @@ class WhitespacePathNormalizer implements PathNormalizer
     public function normalizePath(string $path): string
     {
         $path = str_replace('\\', '/', $path);
-        $path = $this->removeFunkyWhiteSpace($path);
+        $this->rejectFunkyWhiteSpace($path);
 
         return $this->normalizeRelativePath($path);
     }
 
-    private function removeFunkyWhiteSpace(string $path): string
+    private function rejectFunkyWhiteSpace(string $path): void
     {
-        // Remove unprintable characters and invalid unicode characters.
-        // We do this check in a loop, since removing invalid unicode characters
-        // can lead to new characters being created.
-        while (preg_match('#\p{C}+|^\./#u', $path)) {
-            $path = (string) preg_replace('#\p{C}+|^\./#u', '', $path);
+        if (preg_match('#\p{C}+#u', $path)) {
+            throw CorruptedPathDetected::forPath($path);
         }
-
-        return $path;
     }
 
     private function normalizeRelativePath(string $path): string

programming_language: PHP
filename: WhitespacePathNormalizerTest.php
change_type: ModificationType.MODIFY
diff: @@ -55,7 +55,6 @@ class WhitespacePathNormalizerTest extends TestCase
             ['example/path/..txt', 'example/path/..txt'],
             ['\\example\\path.txt', 'example/path.txt'],
             ['\\example\\..\\path.txt', 'path.txt'],
-            ["some\0/path.txt", 'some/path.txt'],
         ];
     }
 
@@ -69,6 +68,21 @@ class WhitespacePathNormalizerTest extends TestCase
         $this->normalizer->normalizePath($input);
     }
 
+    /**
+     * @test
+     * @dataProvider dpFunkyWhitespacePaths
+     */
+    public function rejecting_funky_whitespace(string $path): void
+    {
+        self::expectException(CorruptedPathDetected::class);
+        $this->normalizer->normalizePath($path);
+    }
+
+    public function dpFunkyWhitespacePaths(): iterable
+    {
+        return [["some\0/path.txt"], ["s\x09i.php"]];
+    }
+
     /**
      * @return array<array<string>>
      */

programming_language: PHP