VYPR
Medium severity6.4GHSA Advisory· Published May 21, 2025· Updated Apr 15, 2026

CVE-2025-48203

CVE-2025-48203

Description

The cs_seo extension through 9.2.0 for TYPO3 allows XSS.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
clickstorm/cs-seoPackagist
>= 9.0.0, < 9.3.09.3.0
clickstorm/cs-seoPackagist
>= 8.0.0, < 8.4.08.4.0
clickstorm/cs-seoPackagist
>= 7.0.0, < 7.5.07.5.0
clickstorm/cs-seoPackagist
>= 6.3.0, < 6.8.06.8.0

Affected products

1

Patches

1
1cf6c4082110

[SECUTRIY] escape JSON-LD output to prevent XSS #2025032510000016

https://github.com/clickstorm/cs_seomhirdesMay 20, 2025via ghsa
4 files changed · +73 15
  • Classes/Evaluation/TCA/JsonLdEvaluator.php+41 8 modified
    @@ -2,24 +2,57 @@
     
     namespace Clickstorm\CsSeo\Evaluation\TCA;
     
    +use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
    +
     class JsonLdEvaluator extends AbstractEvaluator
     {
    +    private static bool $alreadyValidated = false;
    +
         /**
          * Server-side validation/evaluation on saving the record
          *
          */
         public function evaluateFieldValue(string $value, string $is_in, bool &$set): string
         {
    -        if ($value && !isset($_REQUEST['tx_csseo_json_ld_eval_done'])) {
    -            $value = trim(preg_replace('#<script(.*?)>|</script>#is', '', $value));
    -            if ($value && json_decode($value, true) === null) {
    -                $this->addFlashMessage(
    -                    'LLL:EXT:cs_seo/Resources/Private/Language/locallang_db.xlf:evaluation.tca.json_ld.invalid_json'
    -                );
    -            }
    +        if (self::$alreadyValidated || empty($value)) {
    +            return $value;
    +        }
    +
    +        self::$alreadyValidated = true;
    +
    +        // Remove surrounding <script> tag if present
    +        $value = $this->stripScriptWrapper($value);
    +
    +        $decoded = json_decode($value, true);
    +
    +        if (json_last_error() !== JSON_ERROR_NONE) {
    +            $this->addFlashMessage(
    +                'LLL:EXT:cs_seo/Resources/Private/Language/locallang_db.xlf:evaluation.tca.json_ld.invalid_json'
    +            );
    +
    +            $invalidComment = LocalizationUtility::translate(
    +                'error.invalid_json_comment',
    +                'cs_seo'
    +            ) ?? '/* INVALID JSON */';
    +
    +            return $invalidComment . "\n" . $value;
             }
     
    -        $_REQUEST['tx_csseo_json_ld_eval_done'] = true;
    +        return $value;
    +    }
    +
    +    /**
    +     * Remove <script type="application/ld+json"> wrapper from pasted code
    +     */
    +    protected function stripScriptWrapper(string $value): string
    +    {
    +        // Normalize whitespace and remove script wrapper
    +        $value = trim($value);
    +
    +        // Match and extract the contents inside <script type="application/ld+json">...</script>
    +        if (preg_match('#<script[^>]*type=["\']application/ld\+json["\'][^>]*>(.*?)</script>#is', $value, $matches)) {
    +            return trim($matches[1]);
    +        }
     
             return $value;
         }
    
  • Classes/UserFunc/StructuredData.php+23 5 modified
    @@ -55,18 +55,36 @@ public function getJsonLdOfPageOrRecord(string $content, array $conf): string
     
             // overwrite json ld with record metadata
             if ($metaData) {
    -            $jsonLd = $metaData['json_ld'] ?? null;
    +            $jsonLd = $metaData['json_ld'] ?? '';
             }
     
    -        return $jsonLd ? $this->wrapWithLd($jsonLd) : '';
    +        // if empty return nothing
    +        if (empty($jsonLd)) {
    +            return '';
    +        }
    +
    +        // Try to decode the JSON string to ensure it's valid
    +        $tempJson = json_decode($jsonLd, true);
    +
    +        // Check if decoding was successful
    +        if (json_last_error() === JSON_ERROR_NONE) {
    +
    +            // Re-encode the array to sanitize any unexpected content
    +            $safeJson = json_encode($tempJson, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
    +
    +            return $this->wrapWithLd($safeJson);
    +        }
    +
    +        return '<!-- Invalid JSON-LD -->';
         }
     
         /**
          * Wraps $content with Json declaration
          */
         protected function wrapWithLd(string $content): string
         {
    -        return '<script type="application/ld+json">' . $content . '</script>';
    +        // Escape special characters to prevent breaking out of the script tag
    +        return '<script type="application/ld+json">' . htmlspecialchars($content, ENT_NOQUOTES | ENT_SUBSTITUTE, 'UTF-8') . '</script>';
         }
     
         public function getSiteSearch(string $content, array $conf): string
    @@ -93,7 +111,7 @@ public function getSiteSearch(string $content, array $conf): string
                 ],
             ];
     
    -        return $this->wrapWithLd(json_encode($siteSearch));
    +        return $this->wrapWithLd(json_encode($siteSearch, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
         }
     
         /**
    @@ -165,6 +183,6 @@ public function getBreadcrumb(string $conf, array $content): string
                 'itemListElement' => $breadcrumbItems,
             ];
     
    -        return $this->wrapWithLd(json_encode($structuredBreadcrumb));
    +        return $this->wrapWithLd(json_encode($structuredBreadcrumb, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
         }
     }
    
  • Resources/Private/Language/de.locallang.xlf+5 1 modified
    @@ -1,6 +1,6 @@
     <?xml version="1.0" encoding="UTF-8"?>
     <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
    -	<file source-language="en" target-language="de" datatype="plaintext" original="EXT:cs_seo/Resources/Private/Language/locallang.xlf" date="2024-05-17T07:49:36Z" product-name="cs_seo">
    +	<file source-language="en" target-language="de" datatype="plaintext" original="EXT:cs_seo/Resources/Private/Language/locallang.xlf" date="2025-04-15T10:00:55Z" product-name="cs_seo">
     		<header/>
     		<body>
     			<trans-unit id="date.format" resname="date.format">
    @@ -19,6 +19,10 @@
     				<source>The TypoScript of the current page could not be loaded.</source>
     				<target>Das TypoScript dieser Seite konnte nicht geladen werden.</target>
     			</trans-unit>
    +			<trans-unit id="error.invalid_json_comment" resname="error.invalid_json_comment">
    +				<source>INVALID JSON!</source>
    +				<target>UNGÜLTIGES JSON!</target>
    +			</trans-unit>
     			<trans-unit id="evaluation.description" resname="evaluation.description">
     				<source>Meta Description</source>
     				<target>Seitenbeschreibung</target>
    
  • Resources/Private/Language/locallang.xlf+4 1 modified
    @@ -1,6 +1,6 @@
     <?xml version="1.0" encoding="UTF-8"?>
     <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
    -	<file source-language="en" datatype="plaintext" original="EXT:cs_seo/Resources/Private/Language/locallang.xlf" date="2024-05-17T07:49:36Z" product-name="cs_seo">
    +	<file source-language="en" datatype="plaintext" original="EXT:cs_seo/Resources/Private/Language/locallang.xlf" date="2025-04-15T10:00:55Z" product-name="cs_seo">
     		<header/>
     		<body>
     			<trans-unit id="date.format" resname="date.format">
    @@ -15,6 +15,9 @@
     			<trans-unit id="error.no_tsfe" resname="error.no_tsfe">
     				<source>The TypoScript of the current page could not be loaded.</source>
     			</trans-unit>
    +			<trans-unit id="error.invalid_json_comment" resname="error.invalid_json_comment">
    +				<source>INVALID JSON!</source>
    +			</trans-unit>
     			<trans-unit id="evaluation.description" resname="evaluation.description">
     				<source>Meta Description</source>
     			</trans-unit>
    

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

5

News mentions

0

No linked articles in our index yet.