CVE-2023-40033: Server-Side Request Forgery (SSRF) (CWE-918)
value: Flarum is an open source forum software. Flarum is affected by a vulnerability that allows an attacker to conduct a Blind Server-Side Request Forgery (SSRF) attack or disclose any file on the server, even with a basic user account on any Flarum forum. By uploading a file containing a URL and spoofing the MIME type, an attacker can manipulate the application to execute unintended actions. The vulnerability is due to the behavior of the `intervention/image` package, which attempts to interpret the supplied file contents as a URL, which then fetches its contents. This allows an attacker to exploit the vulnerability to perform SSRF attacks, disclose local file contents, or conduct a blind oracle attack. This has been patched in Flarum version 1.8.0. Users are advised to upgrade. Users unable to upgrade may disable PHP's `allow_url_fopen` which will prevent the fetching of external files via URLs as a temporary workaround for the SSRF aspect of the vulnerability.
CWE description: The web server receives a URL or similar request from an upstream component and retrieves the contents of this URL, but it does not sufficiently ensure that the request is being sent to the expected destination.
CVSS v3 base score: 7.1
Published: 2023-08-16T21:15Z
Repository: https://github.com/flarum/framework
Language: PHP
Files changed: framework/core/js/src/forum/components/AvatarEditor.js, framework/core/src/Api/Controller/UploadFaviconController.php, framework/core/src/Api/Controller/UploadLogoController.php, framework/core/src/User/AvatarValidator.php, framework/core/src/User/Command/UploadAvatarHandler.php
Commit date: 2023-05-20 15:15:53 +0100
Commit message: fix: improve avatar upload functionality

Signed-off-by: Sami Mazouz <sychocouldy@gmail.com>

Diff: diff --git a/framework/core/js/src/forum/components/AvatarEditor.js b/framework/core/js/src/forum/components/AvatarEditor.js
index e28b617d09..7f92bdfff1 100644
--- a/framework/core/js/src/forum/components/AvatarEditor.js
+++ b/framework/core/js/src/forum/components/AvatarEditor.js
@@ -202,11 +202,11 @@ export default class AvatarEditor extends Component {
       .then(this.success.bind(this), this.failure.bind(this));
   }
 
   /**
    * After a successful upload/removal, push the updated user data into the
-   * store, and force a recomputation of the user's avatar color.
+   * store, and force a re-computation of the user's avatar color.
    *
    * @param {object} response
    * @protected
    */
   success(response) {
diff --git a/framework/core/src/Api/Controller/UploadFaviconController.php b/framework/core/src/Api/Controller/UploadFaviconController.php
index 525b396809..442a4c35ab 100644
--- a/framework/core/src/Api/Controller/UploadFaviconController.php
+++ b/framework/core/src/Api/Controller/UploadFaviconController.php
@@ -60,11 +60,11 @@ class UploadFaviconController extends UploadImageController
                     ':values' => 'jpeg,png,gif,webp',
                 ])
             ]);
         }
 
-        $encodedImage = $this->imageManager->make($file->getStream())->resize(64, 64, function ($constraint) {
+        $encodedImage = $this->imageManager->make($file->getStream()->getMetadata('uri'))->resize(64, 64, function ($constraint) {
             $constraint->aspectRatio();
             $constraint->upsize();
         })->encode('png');
 
         $this->fileExtension = 'png';
diff --git a/framework/core/src/Api/Controller/UploadLogoController.php b/framework/core/src/Api/Controller/UploadLogoController.php
index 8da214d126..6837377555 100644
--- a/framework/core/src/Api/Controller/UploadLogoController.php
+++ b/framework/core/src/Api/Controller/UploadLogoController.php
@@ -36,11 +36,11 @@ class UploadLogoController extends UploadImageController
     /**
      * {@inheritdoc}
      */
     protected function makeImage(UploadedFileInterface $file): Image
     {
-        $encodedImage = $this->imageManager->make($file->getStream())->heighten(60, function ($constraint) {
+        $encodedImage = $this->imageManager->make($file->getStream()->getMetadata('uri'))->heighten(60, function ($constraint) {
             $constraint->upsize();
         })->encode('png');
 
         return $encodedImage;
     }
diff --git a/framework/core/src/User/AvatarValidator.php b/framework/core/src/User/AvatarValidator.php
index 4bb55284d3..cf42ef45ca 100644
--- a/framework/core/src/User/AvatarValidator.php
+++ b/framework/core/src/User/AvatarValidator.php
@@ -85,11 +85,11 @@ class AvatarValidator extends AbstractValidator
         if (! in_array($guessedExtension, $allowedTypes)) {
             $this->raise('mimes', [':values' => implode(', ', $allowedTypes)]);
         }
 
         try {
-            $this->imageManager->make($file->getStream());
+            $this->imageManager->make($file->getStream()->getMetadata('uri'));
         } catch (NotReadableException $_e) {
             $this->raise('image');
         }
     }
 
diff --git a/framework/core/src/User/Command/UploadAvatarHandler.php b/framework/core/src/User/Command/UploadAvatarHandler.php
index 45d3341779..ae88442304 100644
--- a/framework/core/src/User/Command/UploadAvatarHandler.php
+++ b/framework/core/src/User/Command/UploadAvatarHandler.php
@@ -72,11 +72,11 @@ class UploadAvatarHandler
             $actor->assertCan('edit', $user);
         }
 
         $this->validator->assertValid(['avatar' => $command->file]);
 
-        $image = $this->imageManager->make($command->file->getStream());
+        $image = $this->imageManager->make($command->file->getStream()->getMetadata('uri'));
 
         $this->events->dispatch(
             new AvatarSaving($user, $actor, $image)
         );
 

Vulnerable code:    * store, and force a recomputation of the user's avatar color.
        $encodedImage = $this->imageManager->make($file->getStream())->resize(64, 64, function ($constraint) {
        $encodedImage = $this->imageManager->make($file->getStream())->heighten(60, function ($constraint) {
            $this->imageManager->make($file->getStream());
        $image = $this->imageManager->make($command->file->getStream());
Fixed code:    * store, and force a re-computation of the user's avatar color.
        $encodedImage = $this->imageManager->make($file->getStream()->getMetadata('uri'))->resize(64, 64, function ($constraint) {
        $encodedImage = $this->imageManager->make($file->getStream()->getMetadata('uri'))->heighten(60, function ($constraint) {
            $this->imageManager->make($file->getStream()->getMetadata('uri'));
        $image = $this->imageManager->make($command->file->getStream()->getMetadata('uri'));