CVE-2024-24754: Interpretation Conflict (CWE-436)
value: Bref enable serverless PHP on AWS Lambda. When Bref is used with the Event-Driven Function runtime and the handler is a `RequestHandlerInterface`, then the Lambda event is converted to a PSR7 object. During the conversion process, if the request is a MultiPart, each part is parsed and its content added in the `$files` or `$parsedBody` arrays. The conversion process produces a different output compared to the one of plain PHP when keys ending with and open square bracket ([) are used. Based on the application logic the difference in the body parsing might lead to vulnerabilities and/or undefined behaviors. This vulnerability is patched in 2.1.13.
CWE description: Product A handles inputs or steps differently than Product B, which causes A to perform incorrect actions based on its perception of B's state.
CVSS v3 base score: 9.8
Published: 2024-02-01T16:17Z
Repository: https://github.com/brefphp/bref
Language: PHP
Files changed: src/Event/Http/Psr15Handler.php, src/Event/Http/Psr7Bridge.php
Commit date: 2024-01-29 10:20:41 +0100
Commit message: Cleanup uploaded files for PSR-15 handlers

Diff: diff --git a/src/Event/Http/Psr15Handler.php b/src/Event/Http/Psr15Handler.php
index 79ea99e1..b263ef92 100644
--- a/src/Event/Http/Psr15Handler.php
+++ b/src/Event/Http/Psr15Handler.php
@@ -14,10 +14,12 @@ class Psr15Handler extends HttpHandler
         $this->psr15Handler = $psr15Handler;
     }
 
     public function handleRequest(HttpRequestEvent $event, Context $context): HttpResponse
     {
+        Psr7Bridge::cleanupUploadedFiles();
+
         $request = Psr7Bridge::convertRequest($event, $context);
 
         $response = $this->psr15Handler->handle($request);
 
         return Psr7Bridge::convertResponse($response);
diff --git a/src/Event/Http/Psr7Bridge.php b/src/Event/Http/Psr7Bridge.php
index 2db1406d..05532bd0 100644
--- a/src/Event/Http/Psr7Bridge.php
+++ b/src/Event/Http/Psr7Bridge.php
@@ -16,10 +16,12 @@ use function str_starts_with;
 /**
  * Bridges PSR-7 requests and responses with API Gateway or ALB event/response formats.
  */
 final class Psr7Bridge
 {
+    private const UPLOADED_FILES_PREFIX = 'bref_upload_';
+
     /**
      * Create a PSR-7 server request from an AWS Lambda HTTP event.
      */
     public static function convertRequest(HttpRequestEvent $event, Context $context): ServerRequestInterface
     {
@@ -104,11 +106,11 @@ final class Psr7Bridge
                 $document = new Part("Content-type: $contentType\r\n\r\n" . $bodyString);
                 if ($document->isMultiPart()) {
                     $parsedBody = [];
                     foreach ($document->getParts() as $part) {
                         if ($part->isFile()) {
-                            $tmpPath = tempnam(sys_get_temp_dir(), 'bref_upload_');
+                            $tmpPath = tempnam(sys_get_temp_dir(), self::UPLOADED_FILES_PREFIX);
                             if ($tmpPath === false) {
                                 throw new RuntimeException('Unable to create a temporary directory');
                             }
                             file_put_contents($tmpPath, $part->getBody());
                             $file = new UploadedFile($tmpPath, filesize($tmpPath), UPLOAD_ERR_OK, $part->getFileName(), $part->getMimeType());
@@ -164,6 +166,21 @@ final class Psr7Bridge
             }
         }
 
         $pointer = $value;
     }
+
+    /**
+     * Cleanup previously uploaded files.
+     */
+    public static function cleanupUploadedFiles(): void
+    {
+        $tmpFiles = glob(sys_get_temp_dir() . '/' . self::UPLOADED_FILES_PREFIX . '*');
+        if ($tmpFiles !== false) {
+            foreach ($tmpFiles as $file) {
+                if(is_file($file)) {
+                    unlink($file);
+                }
+            }
+        }
+    }
 }

Vulnerable code:                             $tmpPath = tempnam(sys_get_temp_dir(), 'bref_upload_');
Fixed code:         Psr7Bridge::cleanupUploadedFiles();

    private const UPLOADED_FILES_PREFIX = 'bref_upload_';

                            $tmpPath = tempnam(sys_get_temp_dir(), self::UPLOADED_FILES_PREFIX);

    /**
     * Cleanup previously uploaded files.
     */
    public static function cleanupUploadedFiles(): void
    {
        $tmpFiles = glob(sys_get_temp_dir() . '/' . self::UPLOADED_FILES_PREFIX . '*');
        if ($tmpFiles !== false) {
            foreach ($tmpFiles as $file) {
                if(is_file($file)) {
                    unlink($file);
                }
            }
        }
    }