VYPR
High severity7.3NVD Advisory· Published May 28, 2024· Updated Apr 15, 2026

CVE-2024-35226

CVE-2024-35226

Description

Smarty is a template engine for PHP, facilitating the separation of presentation (HTML/CSS) from application logic. In affected versions template authors could inject php code by choosing a malicious file name for an extends-tag. Sites that cannot fully trust template authors should update asap. All users are advised to update. There is no patch for users on the v3 branch. There are no known workarounds for this vulnerability.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
smarty/smartyPackagist
>= 5.0.0, < 5.1.15.1.1
smarty/smartyPackagist
>= 3.0.0, < 4.5.34.5.3

Patches

1
0be92bc8a6fb

Merge pull request from GHSA-4rmg-292m-wg3w

https://github.com/smarty-php/smartySimon WisselinkMay 28, 2024via ghsa
11 files changed · +96 76
  • changelog/GHSA-4rmg-292m-wg3w.md+2 0 added
    @@ -0,0 +1,2 @@
    +- Fixed a code injection vulnerability in extends-tag. This addresses CVE-2024-35226.
    +- Added `$smarty->setCacheModifiedCheck()` setter for cache_modified_check
    \ No newline at end of file
    
  • src/Compiler/Template.php+27 11 modified
    @@ -403,21 +403,37 @@ public function compileTemplateSource(\Smarty\Template $template, \Smarty\Compil
     			}
     			// get template source
     			if (!empty($this->template->getSource()->components)) {
    -				// we have array of inheritance templates by extends: resource
    -				// generate corresponding source code sequence
    -				$_content =
    -					ExtendsTag::extendsSourceArrayCode($this->template);
    +
    +				$_compiled_code = '<?php $_smarty_tpl->getInheritance()->init($_smarty_tpl, true); ?>';
    +
    +				$i = 0;
    +				$reversed_components = array_reverse($this->template->getSource()->components);
    +				foreach ($reversed_components as $source) {
    +					$i++;
    +					if ($i === count($reversed_components)) {
    +						$_compiled_code .= '<?php $_smarty_tpl->getInheritance()->endChild($_smarty_tpl); ?>';
    +					}
    +					$_compiled_code .= $this->compileTag(
    +						'include',
    +						[
    +							var_export($source->resource, true),
    +							['scope' => 'parent'],
    +						]
    +					);
    +				}
    +				$_compiled_code = $this->smarty->runPostFilters($_compiled_code, $this->template);
     			} else {
     				// get template source
     				$_content = $this->template->getSource()->getContent();
    +				$_compiled_code = $this->smarty->runPostFilters(
    +					$this->doCompile(
    +						$this->smarty->runPreFilters($_content, $this->template),
    +						true
    +					),
    +					$this->template
    +				);
     			}
    -			$_compiled_code = $this->smarty->runPostFilters(
    -				$this->doCompile(
    -					$this->smarty->runPreFilters($_content, $this->template),
    -					true
    -				),
    -				$this->template
    -			);
    +
     		} catch (\Exception $e) {
     			if ($this->smarty->debugging) {
     				$this->smarty->getDebug()->end_compile($this->template);
    
  • src/Compile/Tag/ExtendsTag.php+2 62 modified
    @@ -32,7 +32,7 @@ class ExtendsTag extends Inheritance {
     	 *
     	 * @var array
     	 */
    -	protected $optional_attributes = ['extends_resource'];
    +	protected $optional_attributes = [];
     
     	/**
     	 * Attribute definition: Overwrites base class.
    @@ -64,29 +64,7 @@ public function compile($args, \Smarty\Compiler\Template $compiler, $parameter =
     		}
     		// add code to initialize inheritance
     		$this->registerInit($compiler, true);
    -		$file = trim($_attr['file'], '\'"');
    -		if (strlen($file) > 8 && substr($file, 0, 8) === 'extends:') {
    -			// generate code for each template
    -			$files = array_reverse(explode('|', substr($file, 8)));
    -			$i = 0;
    -			foreach ($files as $file) {
    -				if ($file[0] === '"') {
    -					$file = trim($file, '".');
    -				} else {
    -					$file = "'{$file}'";
    -				}
    -				$i++;
    -				if ($i === count($files) && isset($_attr['extends_resource'])) {
    -					$this->compileEndChild($compiler);
    -				}
    -				$this->compileInclude($compiler, $file);
    -			}
    -			if (!isset($_attr['extends_resource'])) {
    -				$this->compileEndChild($compiler);
    -			}
    -		} else {
    -			$this->compileEndChild($compiler, $_attr['file']);
    -		}
    +		$this->compileEndChild($compiler, $_attr['file']);
     		return '';
     	}
     
    @@ -106,42 +84,4 @@ private function compileEndChild(\Smarty\Compiler\Template $compiler, $template
     			(isset($template) ?	", {$template}, \$_smarty_current_dir" : '') . ");\n?>"
     		);
     	}
    -
    -	/**
    -	 * Add code for including subtemplate to end of template
    -	 *
    -	 * @param \Smarty\Compiler\Template $compiler
    -	 * @param string $template subtemplate name
    -	 *
    -	 * @throws \Smarty\CompilerException
    -	 * @throws \Smarty\Exception
    -	 */
    -	private function compileInclude(\Smarty\Compiler\Template $compiler, $template) {
    -		$compiler->getParser()->template_postfix[] = new \Smarty\ParseTree\Tag(
    -			$compiler->getParser(),
    -			$compiler->compileTag(
    -				'include',
    -				[
    -					$template,
    -					['scope' => 'parent'],
    -				]
    -			)
    -		);
    -	}
    -
    -	/**
    -	 * Create source code for {extends} from source components array
    -	 *
    -	 * @param \Smarty\Template $template
    -	 *
    -	 * @return string
    -	 */
    -	public static function extendsSourceArrayCode(\Smarty\Template $template) {
    -		$resources = [];
    -		foreach ($template->getSource()->components as $source) {
    -			$resources[] = $source->resource;
    -		}
    -		return $template->getLeftDelimiter() . 'extends file=\'extends:' . join('|', $resources) .
    -			'\' extends_resource=true' . $template->getRightDelimiter();
    -	}
     }
    
  • src/Smarty.php+9 0 modified
    @@ -2211,5 +2211,14 @@ private function returnOrCreateTemplate($template, $cache_id = null, $compile_id
     		return $template;
     	}
     
    +	/**
    +	 * Sets if Smarty should check If-Modified-Since headers to determine cache validity.
    +	 * @param bool $cache_modified_check
    +	 * @return void
    +	 */
    +	public function setCacheModifiedCheck($cache_modified_check): void {
    +		$this->cache_modified_check = (bool) $cache_modified_check;
    +	}
    +
     }
     
    
  • tests/UnitTests/TemplateSource/_Issues/419/ExtendsIssue419Test.php+7 0 modified
    @@ -32,4 +32,11 @@ public function testextends419()
             $this->assertEquals('child', $this->smarty->fetch('extends:001_parent.tpl|001_child.tpl'));
         }
     
    +    public function testextendsSecurity()
    +    {
    +        $this->expectException(\Smarty\Exception::class);
    +        $this->expectExceptionMessageMatches('/Unable to load.*/');
    +        $this->assertEquals('child', $this->smarty->fetch('string:{include "001_parent.tpl\', var_dump(shell_exec(\'ls\')), 1, 2, 3);}}?>"}'));
    +    }
    +
     }
    
  • tests/UnitTests/TemplateSource/TagTests/BockExtend/CompileBlockExtendsTest.php+33 3 modified
    @@ -1193,8 +1193,38 @@ public function dataTestBlockNocache()
             );
         }
     
    -	public function testBlockWithAssign() {
    -		$this->assertEquals('Captured content is: Content with lots of html here', $this->smarty->fetch('038_child.tpl'));
    -	}
    +    public function testBlockWithAssign() {
    +        $this->assertEquals('Captured content is: Content with lots of html here', $this->smarty->fetch('038_child.tpl'));
    +    }
    +
    +    /**
    +     * Test escaping of file parameter
    +     */
    +    public function testEscaping()
    +    {
    +        $this->expectException(\Smarty\Exception::class);
    +        $this->expectExceptionMessageMatches('/Unable to load.*/');
    +        $this->assertEquals('hello world', $this->smarty->fetch('escaping.tpl'));
    +    }
    +
    +    /**
    +     * Test escaping of file parameter 2
    +     */
    +    public function testEscaping2()
    +    {
    +        $this->expectException(\Smarty\Exception::class);
    +        $this->expectExceptionMessageMatches('/Unable to load.*/');
    +        $this->assertEquals('hello world', $this->smarty->fetch('escaping2.tpl'));
    +    }
    +
    +    /**
    +     * Test escaping of file parameter 3
    +     */
    +    public function testEscaping3()
    +    {
    +        $this->expectException(\Smarty\Exception::class);
    +        $this->expectExceptionMessageMatches('/Unable to load.*/');
    +        $this->assertEquals('hello world', $this->smarty->fetch('escaping3.tpl'));
    +    }
     
     }
    
  • tests/UnitTests/TemplateSource/TagTests/BockExtend/templates/escaping2.tpl+1 0 added
    @@ -0,0 +1 @@
    +{extends 'extends:"helloworld.tpl\', var_dump(shell_exec(\'ls\')), 1, 2, 3);}}?>'}
    \ No newline at end of file
    
  • tests/UnitTests/TemplateSource/TagTests/BockExtend/templates/escaping3.tpl+1 0 added
    @@ -0,0 +1 @@
    +{extends file='extends:"helloworld.tpl'|cat:"', var_dump(shell_exec('ls')), 1, 2, 3);}}?>"}
    \ No newline at end of file
    
  • tests/UnitTests/TemplateSource/TagTests/BockExtend/templates/escaping.tpl+1 0 added
    @@ -0,0 +1 @@
    +{extends "extends:helloworld.tpl', var_dump(shell_exec('ls')), 1, 2, 3);}}?>"}
    \ No newline at end of file
    
  • tests/UnitTests/TemplateSource/TagTests/Include/CompileIncludeTest.php+12 0 modified
    @@ -82,6 +82,18 @@ public function testSpacing_001V3($merge, $caching, $text)
             $this->assertEquals('I1I2I3', $content, $text);
         }
     
    +    /**
    +     * test template name escaping
    +     */
    +    public function testIncludeFilenameEscaping()
    +    {
    +        $this->expectException(\Smarty\Exception::class);
    +        $this->expectExceptionMessageMatches('/Unable to load.*/');
    +        $tpl = $this->smarty->createTemplate('test_include_security.tpl');
    +        $content = $this->smarty->fetch($tpl);
    +        $this->assertEquals("hello world", $content);
    +    }
    +
         /**
          * test standard output
          *
    
  • tests/UnitTests/TemplateSource/TagTests/Include/templates/test_include_security.tpl+1 0 added
    @@ -0,0 +1 @@
    +{include file="helloworld.tpl', var_dump(shell_exec('ls')), 1, 2, 3);}}?>"}
    

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.