VYPR
Moderate severityNVD Advisory· Published Feb 26, 2025· Updated Mar 12, 2025

Relative Path Traversal in assets file upload

CVE-2022-25773

Description

This advisory addresses a file placement vulnerability that could allow assets to be uploaded to unintended directories on the server.

  • Improper Limitation of a Pathname to a Restricted Directory: A vulnerability exists in the asset upload functionality that allows users to upload files to directories outside of the intended temporary directory.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
mautic/corePackagist
< 5.2.35.2.3

Affected products

1

Patches

1
e6aaad99f399

Merge pull request from GHSA-4w2w-36vm-c8hf

https://github.com/mautic/mauticNick VanpraetFeb 25, 2025via ghsa
2 files changed · +63 1
  • app/bundles/AssetBundle/EventListener/UploadSubscriber.php+1 1 modified
    @@ -39,7 +39,7 @@ public function onPostUpload(PostUploadEvent $event): void
         {
             $request   = $event->getRequest()->request;
             $response  = $event->getResponse();
    -        $tempId    = $request->get('tempId');
    +        $tempId    = basename($request->get('tempId'));
             $file      = $event->getFile();
             $config    = $event->getConfig();
             $uploadDir = $config['storage']['directory'];
    
  • app/bundles/AssetBundle/Tests/Controller/AssetControllerFunctionalTest.php+62 0 modified
    @@ -12,6 +12,7 @@
     use Mautic\UserBundle\Entity\User;
     use Mautic\UserBundle\Model\RoleModel;
     use PHPUnit\Framework\Assert;
    +use Symfony\Component\HttpFoundation\File\UploadedFile;
     use Symfony\Component\HttpFoundation\Request;
     use Symfony\Component\HttpFoundation\Response;
     
    @@ -202,6 +203,67 @@ public function getValuesProvider(): \Generator
             ];
         }
     
    +    public function testAssetUploadPathTraversal(): void
    +    {
    +        $client    = $this->client;
    +        $container = $this->getContainer();
    +
    +        // Get CSRF token
    +        $csrfToken = $container->get('security.csrf.token_manager')->getToken('mautic_ajax_post')->getValue();
    +
    +        // Create a temporary file
    +        $tempFile = tempnam(sys_get_temp_dir(), 'test_');
    +        file_put_contents($tempFile, '111');
    +
    +        // Prepare the file for upload
    +        $uploadedFile = new UploadedFile(
    +            $tempFile,
    +            'test.txt',
    +            'text/plain',
    +            null,
    +            true
    +        );
    +
    +        $tmpDir = 'tmp_'.substr(md5(uniqid()), 0, 13);
    +        $client->request(
    +            'POST',
    +            '/s/_uploader/asset/upload',
    +            ['tempId' => '../../'.$tmpDir],
    +            ['file'   => $uploadedFile],
    +            [
    +                'HTTP_X-Requested-With' => 'XMLHttpRequest',
    +                'HTTP_X-CSRF-Token'     => $csrfToken,
    +            ]
    +        );
    +
    +        $response = $client->getResponse();
    +
    +        // Assert response is successful
    +        $this->assertEquals(Response::HTTP_OK, $response->getStatusCode());
    +
    +        // Decode JSON response
    +        $responseData = json_decode($response->getContent(), true);
    +
    +        // Assert the response contains expected keys
    +        $this->assertArrayHasKey('tmpFileName', $responseData);
    +
    +        // Assert file was created in the correct directory
    +        $expectedDir      = $container->getParameter('mautic.upload_dir').join('/', ['', 'tmp', $tmpDir]);
    +        $expectedFilePath = join('/', [$expectedDir, $responseData['tmpFileName']]);
    +        $this->assertFileExists($expectedFilePath);
    +
    +        // Clean up
    +        if (file_exists($expectedFilePath)) {
    +            unlink($expectedFilePath);
    +        }
    +        if (is_dir($expectedDir)) {
    +            rmdir($expectedDir);
    +        }
    +        if (file_exists($tempFile)) {
    +            unlink($tempFile);
    +        }
    +    }
    +
         private function getUser(string $username): User
         {
             $repository = $this->em->getRepository(User::class);
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.