Headline
CVE-2023-3393: Prevent twig from calling unsafe functions (#1337) · FOSSBilling/FOSSBilling@47343fb
Code Injection in GitHub repository fossbilling/fossbilling prior to 0.5.1.
Expand Up @@ -35,17 +35,11 @@ public function getDi(): ?\Pimple\Container public function getFilters() { return [ /** * ‘trans’ filter rewrite same filter from Symfony\Bridge\Twig\Extension\TranslationExtension * for compatible with outdated php-gettext library. * * TODO: Use Symfony\Component\Translation\Loader\MoFileLoader and remove php-gettext hardcoded library. */ ‘trans’ => new TwigFilter('trans’, ‘__trans’),
‘alink’ => new TwigFilter('alink’, [$this, ‘twig_bb_admin_link_filter’], [‘is_safe’ => [‘html’]]),
‘link’ => new TwigFilter('link’, [$this, ‘twig_bb_client_link_filter’], [‘is_safe’ => [‘html’]]), ‘autolink’ => new TwigFilter('autolink’, [$this, ‘twig_autolink_filter’]),
‘gravatar’ => new TwigFilter('gravatar’, [$this, ‘twig_gravatar_filter’]),
Expand All @@ -54,7 +48,6 @@ public function getFilters() ‘truncate’ => new TwigFilter('truncate’, [$this, ‘twig_truncate_filter’], [‘needs_environment’ => true]),
‘timeago’ => new TwigFilter('timeago’, [$this, ‘twig_timeago_filter’]),
‘daysleft’ => new TwigFilter('daysleft’, [$this, ‘twig_daysleft_filter’]),
‘size’ => new TwigFilter('size’, [$this, ‘twig_size_filter’]), Expand All @@ -65,27 +58,23 @@ public function getFilters()
‘period_title’ => new TwigFilter('period_title’, [$this, ‘twig_period_title’], [‘needs_environment’ => true, ‘is_safe’ => [‘html’]]),
‘autolink’ => new TwigFilter('autolink’, [$this, ‘twig_autolink_filter’]),
‘img_tag’ => new TwigFilter('img_tag’, [$this, ‘twig_img_tag’], [‘needs_environment’ => false, ‘is_safe’ => [‘html’]]),
‘script_tag’ => new TwigFilter('script_tag’, [$this, ‘twig_script_tag’], [‘needs_environment’ => false, ‘is_safe’ => [‘html’]]),
‘stylesheet_tag’ => new TwigFilter('stylesheet_tag’, [$this, ‘twig_stylesheet_tag’], [‘needs_environment’ => false, ‘is_safe’ => [‘html’]]),
‘mod_asset_url’ => new TwigFilter('mod_asset_url’, [$this, ‘twig_mod_asset_url’]),
‘asset_url’ => new TwigFilter('asset_url’, [$this, ‘twig_asset_url’], [‘needs_environment’ => true, ‘is_safe’ => [‘html’]]),
‘library_url’ => new TwigFilter('library_url’, [$this, ‘twig_library_url’], [‘is_safe’ => [‘html’]]),
‘money’ => new TwigFilter('money’, [$this, ‘twig_money’], [‘needs_environment’ => true, ‘is_safe’ => [‘html’]]),
‘money_without_currency’ => new TwigFilter('money_without_currency’, [$this, ‘twig_money_without_currency’], [‘needs_environment’ => true, ‘is_safe’ => [‘html’]]),
‘money_convert’ => new TwigFilter('money_convert’, [$this, ‘twig_money_convert’], [‘needs_environment’ => true, ‘is_safe’ => [‘html’]]),
‘money_convert_without_currency’ => new TwigFilter('money_convert_without_currency’, [$this, ‘money_convert_without_currency’], [‘needs_environment’ => true, ‘is_safe’ => [‘html’]]),
// We override these default twig filters so we can explicitly disable it from calling certain functions that may leak data or allow commands to be executed on the system. ‘filter’ => new TwigFilter('filter’, [$this, ‘filteredFilter’]), ‘map’ => new TwigFilter('map’, [$this, ‘filteredMap’]), ‘reduce’ => new TwigFilter('reduce’, [$this, ‘filteredReduce’]), ‘sort’ => new TwigFilter('sort’, [$this, ‘filteredSort’]), ]; }
Expand Down Expand Up @@ -318,4 +307,62 @@ public function twig_truncate_filter(Twig\Environment $env, $value, $length = 30
return $value; }
public function filteredFilter($array, $arrow) { if (!$arrow instanceof Closure) { return; }
return array_filter($array, $arrow, \ARRAY_FILTER_USE_BOTH); }
public function filteredMap($array, $arrow) { if (!$arrow instanceof Closure) { return; }
$r = []; foreach ($array as $k => $v) { $r[$k] = $arrow($v, $k); }
return $r; }
public function filteredReduce($array, $arrow, $initial = null) { if (!$arrow instanceof Closure) { return; }
$accumulator = $initial; foreach ($array as $key => $value) { $accumulator = $arrow($accumulator, $value, $key); }
return $accumulator; }
public function filteredSort($array, $arrow) { if (!$arrow instanceof Closure) { return; }
if ($array instanceof \Traversable) { $array = iterator_to_array($array); } elseif (!\is_array($array)) { return $array; }
if (null !== $arrow) { uasort($array, $arrow); } else { asort($array); }
return $array; } }