VYPR
Moderate severityNVD Advisory· Published May 14, 2024· Updated Aug 2, 2024

TYPO3 vulnerable to Cross-Site Scripting in ShowImageController

CVE-2024-34357

Description

TYPO3 is an enterprise content management system. Starting in version 9.0.0 and prior to versions 9.5.48 ELTS, 10.4.45 ELTS, 11.5.37 LTS, 12.4.15 LTS, and 13.1.1, failing to properly encode user-controlled values in file entities, the ShowImageController (_eID tx_cms_showpic_) is vulnerable to cross-site scripting. Exploiting this vulnerability requires a valid backend user account with access to file entities. TYPO3 versions 9.5.48 ELTS, 10.4.45 ELTS, 11.5.37 LTS, 12.4.15 LTS, 13.1.1 fix the problem described.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

TYPO3's ShowImageController fails to encode user-controlled file properties, leading to stored XSS for backend users with file access.

Vulnerability

Analysis

CVE-2024-34357 is a cross-site scripting (XSS) vulnerability in the TYPO3 content management system, affecting the ShowImageController (accessible via the _eID tx_cms_showpic_ endpoint). The root cause is the failure to properly encode user-controlled values in file entities before rendering them in the controller's output. This means that file properties such as title, alternative text, or other metadata can contain malicious HTML/JavaScript that is not sanitized, leading to XSS when the image is displayed [1].

Attack

Vector and Prerequisites

Exploitation requires a valid backend user account that has access to file entities. An attacker with such privileges can inject arbitrary JavaScript into file properties (e.g., title or alternative). When another user—or the attacker themselves—views an image via the ShowImageController, the injected script executes in the context of the victim's browser session. The attack does not require any special network position; it can be performed within the TYPO3 backend interface [1].

Impact

Successful exploitation allows an attacker to execute arbitrary JavaScript in the browser of any user who triggers the image display. This can lead to actions such as stealing session cookies, performing administrative actions on behalf of the victim, defacing the backend interface, or exfiltrating sensitive information. The vulnerability is considered high severity due to the potential for account takeover in a multi-user backend environment [1].

Mitigation

The TYPO3 project has released patched versions: 9.5.48 ELTS, 10.4.45 ELTS, 11.5.37 LTS, 12.4.15 LTS, and 13.1.1. The fix ensures that all file properties are properly encoded before being output, as demonstrated in the security commit that updated the ShowImageController to escape attributes like title, alt, and src [3][4]. Users are strongly advised to update to a patched version immediately.

AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
typo3/cms-corePackagist
>= 9.0.0, < 9.5.489.5.48
typo3/cms-corePackagist
>= 10.0.0, < 10.4.4510.4.45
typo3/cms-corePackagist
>= 11.0.0, < 11.5.3711.5.37
typo3/cms-corePackagist
>= 12.0.0, < 12.4.1512.4.15
typo3/cms-corePackagist
>= 13.0.0, < 13.1.113.1.1

Affected products

2

Patches

3
b31d05d1da3e

[SECURITY] Encode all file properties in tx_cms_showpic output

https://github.com/TYPO3/typo3Oliver HaderMay 14, 2024via ghsa
2 files changed · +34 26
  • typo3/sysext/frontend/Classes/Controller/ShowImageController.php+9 14 modified
    @@ -106,11 +106,6 @@ class ShowImageController
     </html>
     EOF;
     
    -    /**
    -     * @var string
    -     */
    -    protected $imageTag = '<img src="###publicUrl###" alt="###alt###" title="###title###" width="###width###" height="###height###" />';
    -
         /**
          * Init function, setting the input vars in the global space.
          *
    @@ -166,17 +161,17 @@ public function initialize()
         public function main()
         {
             $processedImage = $this->processImage();
    -        $imageTagMarkers = [
    -            '###publicUrl###' => htmlspecialchars($processedImage->getPublicUrl() ?? ''),
    -            '###alt###' => htmlspecialchars($this->file->getProperty('alternative') ?: $this->title),
    -            '###title###' => htmlspecialchars($this->file->getProperty('title') ?: $this->title),
    -            '###width###' => $processedImage->getProperty('width'),
    -            '###height###' => $processedImage->getProperty('height'),
    +        $imageAttributes = [
    +            'src' => $processedImage->getPublicUrl() ?? '',
    +            'alt' => $this->file->getProperty('alternative') ?: $this->title,
    +            'title' => $this->file->getProperty('title') ?: $this->title,
    +            'width' => (string)$processedImage->getProperty('width'),
    +            'height' => (string)$processedImage->getProperty('height'),
             ];
    -        $this->imageTag = str_replace(array_keys($imageTagMarkers), array_values($imageTagMarkers), $this->imageTag);
    +
             $markerArray = [
    -            '###TITLE###' => $this->file->getProperty('title') ?: $this->title,
    -            '###IMAGE###' => $this->imageTag,
    +            '###TITLE###' => htmlspecialchars($this->file->getProperty('title') ?: $this->title),
    +            '###IMAGE###' => sprintf('<img %s>', GeneralUtility::implodeAttributes($imageAttributes, true)),
                 '###BODY###' => $this->bodyTag,
             ];
     
    
  • typo3/sysext/frontend/Tests/Functional/Controller/ShowImageControllerTest.php+25 12 modified
    @@ -96,12 +96,14 @@ public static function contentIsGeneratedForLocalFilesDataProvider(): \Generator
         public function contentIsGeneratedForLocalFiles(int $fileId, array $queryParams): void
         {
             $storageDriver = 'Local';
    +        $expectedSrc = '/fileadmin/local-file/' . $fileId . '?&test=""';
    +        $expectedTitle = '</title></head></html><!-- "fileProperty::title" -->';
     
             $this->storage->expects(self::atLeastOnce())
                 ->method('getDriverType')
                 ->willReturn($storageDriver);
             $file = $this->buildFile('/local-file/' . $fileId, $this->storage);
    -        $processedFile = $this->buildProcessedFile('/fileadmin/local-file/' . $fileId);
    +        $processedFile = $this->buildProcessedFile($expectedSrc);
             $this->resourceFactory->expects(self::atLeastOnce())
                 ->method('getFileObject')
                 ->with($fileId)
    @@ -112,16 +114,17 @@ public function contentIsGeneratedForLocalFiles(int $fileId, array $queryParams)
     
             $request = $this->buildRequest($queryParams);
             $response = $this->subject->processRequest($request);
    -        $document = (new HTML5())->loadHTML((string)$response->getBody());
    +        $responseBody = (string)$response->getBody();
    +        $document = (new HTML5())->loadHTML($responseBody);
     
             $titles = $document->getElementsByTagName('title');
             $images = $document->getElementsByTagName('img');
    -        self::assertSame('fileProperty::title', $titles->item(0)->nodeValue);
    -        self::assertSame('/fileadmin/local-file/13', $images->item(0)->getAttribute('src'));
    -        self::assertSame('fileProperty::alternative', $images->item(0)->getAttribute('alt'));
    -        self::assertSame('fileProperty::title', $images->item(0)->getAttribute('title'));
    -        self::assertSame('processedProperty::width', $images->item(0)->getAttribute('width'));
    -        self::assertSame('processedProperty::height', $images->item(0)->getAttribute('height'));
    +        self::assertSame($expectedTitle, $titles->item(0)->nodeValue);
    +        self::assertSame($expectedSrc, $images->item(0)->getAttribute('src'));
    +        self::assertSame($expectedTitle, $images->item(0)->getAttribute('title'));
    +        self::assertSame('<!-- "fileProperty::alternative" -->', $images->item(0)->getAttribute('alt'));
    +        self::assertSame('<!-- "processedProperty::width" -->', $images->item(0)->getAttribute('width'));
    +        self::assertSame('<!-- "processedProperty::height" -->', $images->item(0)->getAttribute('height'));
         }
     
         /**
    @@ -144,7 +147,12 @@ private function buildFile(string $identifier, ResourceStorage $storage): FileIn
             $file->method('getIdentifier')
                 ->willReturn($identifier);
             $file->method('getProperty')
    -            ->willReturnCallback($this->buildRoundTripClosure('fileProperty'));
    +            ->willReturnCallback(
    +                $this->buildRoundTripClosure(
    +                    'fileProperty',
    +                    ['title' => '</title></head></html>']
    +                )
    +            );
     
             return $file;
         }
    @@ -165,10 +173,15 @@ private function buildProcessedFile(string $publicUrl): ProcessedFile&MockObject
             return $processedFile;
         }
     
    -    private function buildRoundTripClosure(string $prefix): \Closure
    +    private function buildRoundTripClosure(string $prefix, array $prependMap = []): \Closure
         {
    -        return static function (string ...$args) use ($prefix): string {
    -            return sprintf('%s::%s', $prefix, implode(',', $args));
    +        return static function (string $name) use ($prefix, $prependMap): string {
    +            return sprintf(
    +                '%s<!-- "%s::%s" -->',
    +                $prependMap[$name] ?? '',
    +                $prefix,
    +                $name
    +            );
             };
         }
     }
    
d77464238135

[SECURITY] Encode all file properties in tx_cms_showpic output

https://github.com/TYPO3/typo3Oliver HaderMay 14, 2024via ghsa
2 files changed · +28 15
  • typo3/sysext/frontend/Classes/Controller/ShowImageController.php+3 3 modified
    @@ -168,12 +168,12 @@ public function main()
                 '###publicUrl###' => htmlspecialchars($processedImage->getPublicUrl() ?? ''),
                 '###alt###' => htmlspecialchars($this->file->getProperty('alternative') ?: $this->title),
                 '###title###' => htmlspecialchars($this->file->getProperty('title') ?: $this->title),
    -            '###width###' => $processedImage->getProperty('width'),
    -            '###height###' => $processedImage->getProperty('height'),
    +            '###width###' => htmlspecialchars((string)$processedImage->getProperty('width')),
    +            '###height###' => htmlspecialchars((string)$processedImage->getProperty('height')),
             ];
             $this->imageTag = str_replace(array_keys($imageTagMarkers), array_values($imageTagMarkers), $this->imageTag);
             $markerArray = [
    -            '###TITLE###' => $this->file->getProperty('title') ?: $this->title,
    +            '###TITLE###' => htmlspecialchars($this->file->getProperty('title') ?: $this->title),
                 '###IMAGE###' => $this->imageTag,
                 '###BODY###' => $this->bodyTag,
             ];
    
  • typo3/sysext/frontend/Tests/Functional/Controller/ShowImageControllerTest.php+25 12 modified
    @@ -93,12 +93,14 @@ public static function contentIsGeneratedForLocalFilesDataProvider(): \Generator
         public function contentIsGeneratedForLocalFiles(int $fileId, array $queryParams): void
         {
             $storageDriver = 'Local';
    +        $expectedSrc = '/fileadmin/local-file/' . $fileId . '?&test=""';
    +        $expectedTitle = '</title></head></html><!-- "fileProperty::title" -->';
     
             $this->storage->expects(self::atLeastOnce())
                 ->method('getDriverType')
                 ->willReturn($storageDriver);
             $file = $this->buildFile('/local-file/' . $fileId, $this->storage);
    -        $processedFile = $this->buildProcessedFile('/fileadmin/local-file/' . $fileId);
    +        $processedFile = $this->buildProcessedFile($expectedSrc);
             $this->resourceFactory->expects(self::atLeastOnce())
                 ->method('getFileObject')
                 ->with($fileId)
    @@ -109,16 +111,17 @@ public function contentIsGeneratedForLocalFiles(int $fileId, array $queryParams)
     
             $request = $this->buildRequest($queryParams);
             $response = $this->subject->processRequest($request);
    -        $document = (new HTML5())->loadHTML((string)$response->getBody());
    +        $responseBody = (string)$response->getBody();
    +        $document = (new HTML5())->loadHTML($responseBody);
     
             $titles = $document->getElementsByTagName('title');
             $images = $document->getElementsByTagName('img');
    -        self::assertSame('fileProperty::title', $titles->item(0)->nodeValue);
    -        self::assertSame('/fileadmin/local-file/13', $images->item(0)->getAttribute('src'));
    -        self::assertSame('fileProperty::alternative', $images->item(0)->getAttribute('alt'));
    -        self::assertSame('fileProperty::title', $images->item(0)->getAttribute('title'));
    -        self::assertSame('processedProperty::width', $images->item(0)->getAttribute('width'));
    -        self::assertSame('processedProperty::height', $images->item(0)->getAttribute('height'));
    +        self::assertSame($expectedTitle, $titles->item(0)->nodeValue);
    +        self::assertSame($expectedSrc, $images->item(0)->getAttribute('src'));
    +        self::assertSame($expectedTitle, $images->item(0)->getAttribute('title'));
    +        self::assertSame('<!-- "fileProperty::alternative" -->', $images->item(0)->getAttribute('alt'));
    +        self::assertSame('<!-- "processedProperty::width" -->', $images->item(0)->getAttribute('width'));
    +        self::assertSame('<!-- "processedProperty::height" -->', $images->item(0)->getAttribute('height'));
         }
     
         /**
    @@ -141,7 +144,12 @@ private function buildFile(string $identifier, ResourceStorage $storage): FileIn
             $file->method('getIdentifier')
                 ->willReturn($identifier);
             $file->method('getProperty')
    -            ->willReturnCallback($this->buildRoundTripClosure('fileProperty'));
    +            ->willReturnCallback(
    +                $this->buildRoundTripClosure(
    +                    'fileProperty',
    +                    ['title' => '</title></head></html>']
    +                )
    +            );
     
             return $file;
         }
    @@ -162,10 +170,15 @@ private function buildProcessedFile(string $publicUrl): ProcessedFile&MockObject
             return $processedFile;
         }
     
    -    private function buildRoundTripClosure(string $prefix): \Closure
    +    private function buildRoundTripClosure(string $prefix, array $prependMap = []): \Closure
         {
    -        return static function (string ...$args) use ($prefix): string {
    -            return sprintf('%s::%s', $prefix, implode(',', $args));
    +        return static function (string $name) use ($prefix, $prependMap): string {
    +            return sprintf(
    +                '%s<!-- "%s::%s" -->',
    +                $prependMap[$name] ?? '',
    +                $prefix,
    +                $name
    +            );
             };
         }
     }
    
376474904f6b

[SECURITY] Encode all file properties in tx_cms_showpic output

https://github.com/TYPO3/typo3Oliver HaderMay 14, 2024via ghsa
1 file changed · +3 3
  • typo3/sysext/frontend/Classes/Controller/ShowImageController.php+3 3 modified
    @@ -166,12 +166,12 @@ public function main()
                 '###publicUrl###' => htmlspecialchars($processedImage->getPublicUrl() ?? ''),
                 '###alt###' => htmlspecialchars($this->file->getProperty('alternative') ?: $this->title),
                 '###title###' => htmlspecialchars($this->file->getProperty('title') ?: $this->title),
    -            '###width###' => $processedImage->getProperty('width'),
    -            '###height###' => $processedImage->getProperty('height'),
    +            '###width###' => htmlspecialchars((string)$processedImage->getProperty('width')),
    +            '###height###' => htmlspecialchars((string)$processedImage->getProperty('height')),
             ];
             $this->imageTag = str_replace(array_keys($imageTagMarkers), array_values($imageTagMarkers), $this->imageTag);
             $markerArray = [
    -            '###TITLE###' => $this->file->getProperty('title') ?: $this->title,
    +            '###TITLE###' => htmlspecialchars($this->file->getProperty('title') ?: $this->title),
                 '###IMAGE###' => $this->imageTag,
                 '###BODY###' => $this->bodyTag,
             ];
    

Vulnerability mechanics

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

References

7

News mentions

0

No linked articles in our index yet.