CVE-2024-28191: Insufficient Information (NVD-CWE-noinfo)
value: Contao is an open source content management system. Starting in version 4.0.0 and prior to version 4.13.40 and 5.3.4, it is possible to inject insert tags in frontend forms if the output is structured in a very specific way. Contao versions 4.13.40 and 5.3.4 have a patch for this issue. As a workaround, do not output user data from frontend forms next to each other, always separate them by at least one character.
CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
Published: 2024-04-09T14:15Z
Repository: https://github.com/contao/contao
Language: PHP
Files changed: core-bundle/src/Resources/contao/library/Contao/Input.php, core-bundle/src/String/SimpleTokenParser.php, core-bundle/tests/String/SimpleTokenParserTest.php
Commit date: 2024-04-09 07:19:09 +0200
Commit message: Merge pull request from GHSA-747v-52c4-8vj8

# Conflicts:
#	core-bundle/src/String/SimpleTokenParser.php
#	core-bundle/tests/Contao/InputTest.php

Co-authored-by: Leo Feyer <1192057+leofeyer@users.noreply.github.com>
Diff: diff --git a/core-bundle/src/Resources/contao/library/Contao/Input.php b/core-bundle/src/Resources/contao/library/Contao/Input.php
index 978ee4d991e..73544b6d79b 100644
--- a/core-bundle/src/Resources/contao/library/Contao/Input.php
+++ b/core-bundle/src/Resources/contao/library/Contao/Input.php
@@ -962,11 +962,14 @@ class Input
 			}
 
 			return $varValue;
 		}
 
-		return str_replace(array('{{', '}}'), array('&#123;&#123;', '&#125;&#125;'), (string) $varValue);
+		$varValue = str_replace(array('{{', '}}'), array('&#123;&#123;', '&#125;&#125;'), (string) $varValue);
+
+		// Encode single curly braces at the beginning and end of the string
+		return preg_replace(array('/^(\s*)\{|\{(\s*)$/', '/^(\s*)\}|\}(\s*)$/'), array('$1&#123;$2', '$1&#125;$2'), $varValue);
 	}
 
 	/**
 	 * Fallback to the session form data if there is no post data
 	 *
diff --git a/core-bundle/src/String/SimpleTokenParser.php b/core-bundle/src/String/SimpleTokenParser.php
index 194504991bf..93f71ca72ee 100644
--- a/core-bundle/src/String/SimpleTokenParser.php
+++ b/core-bundle/src/String/SimpleTokenParser.php
@@ -10,10 +10,11 @@ declare(strict_types=1);
  * @license LGPL-3.0-or-later
  */
 
 namespace Contao\CoreBundle\String;
 
+use Contao\Input;
 use Contao\StringUtil;
 use Psr\Log\LoggerAwareInterface;
 use Psr\Log\LoggerAwareTrait;
 use Psr\Log\LogLevel;
 use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
@@ -126,11 +127,11 @@ class SimpleTokenParser implements LoggerAwareInterface
                     }
 
                     return '##'.$matches[1].'##';
                 }
 
-                return $data[$matches[1]];
+                return Input::encodeInsertTags($data[$matches[1]]);
             },
             $subject
         );
     }
 
diff --git a/core-bundle/tests/String/SimpleTokenParserTest.php b/core-bundle/tests/String/SimpleTokenParserTest.php
index 57ae75f14a4..9a4d407c130 100644
--- a/core-bundle/tests/String/SimpleTokenParserTest.php
+++ b/core-bundle/tests/String/SimpleTokenParserTest.php
@@ -143,20 +143,38 @@ class SimpleTokenParserTest extends TestCase
             'This is my {if value!==5.0}match{endif}',
             ['value' => 5.0],
             'This is my ',
         ];
 
+        yield 'Test regular curly braces do not get encoded' => [
+            '##token##',
+            ['token' => 'foo { bar } baz'],
+            'foo { bar } baz',
+        ];
+
         yield 'Test if-tags insertion not evaluated' => [
             '##token##',
             ['token' => '{if token=="foo"}'],
-            '{if token=="foo"}',
+            '&#123;if token=="foo"&#125;',
+        ];
+
+        yield 'Test insert tags insertion not possible' => [
+            '##token##',
+            ['token' => '{{date}}'],
+            '&#123;&#123;date&#125;&#125;',
         ];
 
         yield 'Test if-tags insertion not evaluated with multiple tokens' => [
             '##token1####token2####token3##',
             ['token1' => '{', 'token2' => 'if', 'token3' => ' token=="foo"}'],
-            '{if token=="foo"}',
+            '&#123;if token=="foo"&#125;',
+        ];
+
+        yield 'Test insert tags insertion not possible with multiple tokens' => [
+            '##token1####token2####token3##',
+            ['token1' => '{', 'token2' => '{date}', 'token3' => '}'],
+            '&#123;&#123;date&#125;&#125;',
         ];
 
         yield 'Test escaping works correctly' => [
             '{if value=="f\"oo"}match{endif}',
             ['value' => 'f"oo'],

Vulnerable code: 		return str_replace(array('{{', '}}'), array('&#123;&#123;', '&#125;&#125;'), (string) $varValue);
                return $data[$matches[1]];
            '{if token=="foo"}',
            '{if token=="foo"}',
Fixed code: 		$varValue = str_replace(array('{{', '}}'), array('&#123;&#123;', '&#125;&#125;'), (string) $varValue);

		// Encode single curly braces at the beginning and end of the string
		return preg_replace(array('/^(\s*)\{|\{(\s*)$/', '/^(\s*)\}|\}(\s*)$/'), array('$1&#123;$2', '$1&#125;$2'), $varValue);
use Contao\Input;
                return Input::encodeInsertTags($data[$matches[1]]);
        yield 'Test regular curly braces do not get encoded' => [
            '##token##',
            ['token' => 'foo { bar } baz'],
            'foo { bar } baz',
        ];

            '&#123;if token=="foo"&#125;',
        ];

        yield 'Test insert tags insertion not possible' => [
            '##token##',
            ['token' => '{{date}}'],
            '&#123;&#123;date&#125;&#125;',
            '&#123;if token=="foo"&#125;',
        ];

        yield 'Test insert tags insertion not possible with multiple tokens' => [
            '##token1####token2####token3##',
            ['token1' => '{', 'token2' => '{date}', 'token3' => '}'],
            '&#123;&#123;date&#125;&#125;',