VYPR
Low severityNVD Advisory· Published Apr 9, 2024· Updated Aug 2, 2024

Contao may have unencoded insert tags in the frontend

CVE-2024-28191

Description

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.

AI Insight

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

CVE-2024-28191 allows insert tag injection in Contao CMS frontend forms when user output is adjacent, patched in versions 4.13.40 and 5.3.4.

Vulnerability

Details CVE-2024-28191 is an insert tag injection vulnerability in Contao CMS (versions 4.0.0 to before 4.13.40 and 5.3.4). The root cause is insufficient encoding of insert tags when user input is output in frontend forms without any separating characters. The fix involves encoding curly braces that could be misinterpreted as insert tag delimiters [1][3][4].

Exploitation

An attacker can exploit this vulnerability by submitting crafted input through frontend forms. The attack requires that the output places user-supplied data directly adjacent to each other (e.g., two separate form fields output consecutively). No authentication is needed as frontend forms are typically public. The specific structure needed makes exploitation non-trivial but possible [1].

Impact

Successful exploitation allows an attacker to inject arbitrary insert tags into the rendered page. In Contao, insert tags can include dynamic content, execute PHP code, or retrieve sensitive information. This could lead to information disclosure, privilege escalation, or remote code execution, depending on the tags used [1].

Mitigation

Contao has released patches in versions 4.13.40 and 5.3.4 that properly encode insert tags in all contexts. As a workaround, administrators should ensure that user data from different form fields is not output consecutively; insert at least one character (e.g., a space) between them. Users are strongly advised to update to the latest patched version [1][3][4].

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
contao/core-bundlePackagist
>= 4.0.0, < 4.13.404.13.40
contao/core-bundlePackagist
>= 5.0.0-RC1, < 5.3.45.3.4

Affected products

2

Patches

2
474a2fc25f1d

Merge pull request from GHSA-747v-52c4-8vj8

https://github.com/contao/contaoMartin AuswögerApr 9, 2024via ghsa
4 files changed · +34 10
  • core-bundle/contao/library/Contao/Input.php+4 1 modified
    @@ -1059,7 +1059,10 @@ public static function encodeInsertTags($varValue)
     			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);
     	}
     
     	/**
    
  • core-bundle/src/String/SimpleTokenParser.php+2 1 modified
    @@ -12,6 +12,7 @@
     
     namespace Contao\CoreBundle\String;
     
    +use Contao\Input;
     use Psr\Log\LoggerAwareInterface;
     use Psr\Log\LoggerAwareTrait;
     use Psr\Log\LogLevel;
    @@ -108,7 +109,7 @@ function (array $matches) use ($data) {
                         return '##'.$matches[1].'##';
                     }
     
    -                return $data[$matches[1]];
    +                return Input::encodeInsertTags($data[$matches[1]]);
                 },
                 $subject,
             );
    
  • core-bundle/tests/Contao/InputTest.php+8 6 modified
    @@ -168,8 +168,8 @@ public function testBackendRoundtrip(string $source, string $expected, string|nu
          */
         public function testEncodesInsertTags(): void
         {
    -        $source = '{{ foo }}';
    -        $encoded = '&#123;&#123; foo &#125;&#125;';
    +        $source = ' {{ foo }} { bar } ';
    +        $encoded = ' &#123;&#123; foo &#125;&#125; { bar &#125; ';
     
             $_GET = $_POST = $_COOKIE = [
                 'key' => $source,
    @@ -327,14 +327,14 @@ public function encodeInputProvider(): \Generator
          *
          * @group legacy
          */
    -    public function testEncodeNoneMode(string $source, string $expected, string|null $expectedEncoded = null): void
    +    public function testEncodeNoneMode(string $source, string $expected, string|null $expectedEncoded = null, string|null $expectedEncodedDouble = null): void
         {
             $expectedEncoded ??= $expected;
     
             $this->assertSame($expected, Input::encodeInput($source, InputEncodingMode::encodeNone, false));
             $this->assertSame($expectedEncoded, Input::encodeInput($source, InputEncodingMode::encodeNone));
             $this->assertSame($expected.$expected, Input::encodeInput($source.$source, InputEncodingMode::encodeNone, false));
    -        $this->assertSame($expectedEncoded.$expectedEncoded, Input::encodeInput($source.$source, InputEncodingMode::encodeNone));
    +        $this->assertSame($expectedEncodedDouble ?? $expectedEncoded.$expectedEncoded, Input::encodeInput($source.$source, InputEncodingMode::encodeNone));
     
             System::getContainer()->set('request_stack', $stack = new RequestStack());
             $stack->push(new Request([], ['key' => $source]));
    @@ -355,10 +355,12 @@ public function encodeNoneModeProvider(): \Generator
             yield ['foo', 'foo'];
             yield ['\X \0 \X', '\X &#92;0 \X'];
             yield ["a\rb\r\nc\n\rd\ne", "a\nb\nc\n\nd\ne"];
    -        yield ['{}', '{}'];
    +        yield ['{}', '{}', '&#123;&#125;', '&#123;}{&#125;'];
             yield ['{{}}', '{{}}', '&#123;&#123;&#125;&#125;'];
    -        yield ['{{{}}}', '{{{}}}', '&#123;&#123;{&#125;&#125;}'];
    +        yield ['{{{}}}', '{{{}}}', '&#123;&#123;{&#125;&#125;&#125;', '&#123;&#123;{&#125;&#125;}&#123;&#123;{&#125;&#125;&#125;'];
             yield ['{{{{}}}}', '{{{{}}}}', '&#123;&#123;&#123;&#123;&#125;&#125;&#125;&#125;'];
    +        yield ['{ start {and} end }', '{ start {and} end }', '&#123; start {and} end &#125;', '&#123; start {and} end }{ start {and} end &#125;'];
    +        yield ["\n\t { foo }\n\t ", "\n\t { foo }\n\t ", "\n\t &#123; foo &#125;\n\t ", "\n\t &#123; foo }\n\t \n\t { foo &#125;\n\t "];
             yield ["\0", "\u{FFFD}"];
             yield ["\x80", "\u{FFFD}"];
             yield ["\xFF", "\u{FFFD}"];
    
  • core-bundle/tests/String/SimpleTokenParserTest.php+20 2 modified
    @@ -145,16 +145,34 @@ public function parseSimpleTokensProvider(): \Generator
                 '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' => [
    
388859dcf110

Merge pull request from GHSA-747v-52c4-8vj8

https://github.com/contao/contaoMartin AuswögerApr 9, 2024via ghsa
3 files changed · +26 4
  • core-bundle/src/Resources/contao/library/Contao/Input.php+4 1 modified
    @@ -964,7 +964,10 @@ public static function encodeInsertTags($varValue)
     			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);
     	}
     
     	/**
    
  • core-bundle/src/String/SimpleTokenParser.php+2 1 modified
    @@ -12,6 +12,7 @@
     
     namespace Contao\CoreBundle\String;
     
    +use Contao\Input;
     use Contao\StringUtil;
     use Psr\Log\LoggerAwareInterface;
     use Psr\Log\LoggerAwareTrait;
    @@ -128,7 +129,7 @@ function (array $matches) use ($data) {
                         return '##'.$matches[1].'##';
                     }
     
    -                return $data[$matches[1]];
    +                return Input::encodeInsertTags($data[$matches[1]]);
                 },
                 $subject
             );
    
  • core-bundle/tests/String/SimpleTokenParserTest.php+20 2 modified
    @@ -145,16 +145,34 @@ public function parseSimpleTokensProvider(): \Generator
                 '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' => [
    

Vulnerability mechanics

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

References

6

News mentions

0

No linked articles in our index yet.