From 0a9e20615ec9a468d398a0d3a52e0462d5c3ba98 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 30 Aug 2024 10:33:57 -1000 Subject: [PATCH] Limit maximum template render output to 256KiB (#124946) * Limit maximum template render output to 256KiB fixes #124931 256KiB is likely to still block the event loop for an unreasonable amont of time but its likely someone is using the template engine for large blocks of data so we want a limit which still allows that but has a reasonable safety to prevent the system from crashing down * Update homeassistant/helpers/template.py --- homeassistant/helpers/template.py | 6 ++++++ tests/helpers/test_template.py | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/homeassistant/helpers/template.py b/homeassistant/helpers/template.py index e090e0de2d1..0a980db30b4 100644 --- a/homeassistant/helpers/template.py +++ b/homeassistant/helpers/template.py @@ -149,6 +149,7 @@ CACHED_TEMPLATE_STATES = 512 EVAL_CACHE_SIZE = 512 MAX_CUSTOM_TEMPLATE_SIZE = 5 * 1024 * 1024 +MAX_TEMPLATE_OUTPUT = 256 * 1024 # 256KiB CACHED_TEMPLATE_LRU: LRU[State, TemplateState] = LRU(CACHED_TEMPLATE_STATES) CACHED_TEMPLATE_NO_COLLECT_LRU: LRU[State, TemplateState] = LRU(CACHED_TEMPLATE_STATES) @@ -604,6 +605,11 @@ class Template: except Exception as err: raise TemplateError(err) from err + if len(render_result) > MAX_TEMPLATE_OUTPUT: + raise TemplateError( + f"Template output exceeded maximum size of {MAX_TEMPLATE_OUTPUT} characters" + ) + render_result = render_result.strip() if not parse_result or self.hass and self.hass.config.legacy_templates: diff --git a/tests/helpers/test_template.py b/tests/helpers/test_template.py index 0676ae21ab7..f585b5c3260 100644 --- a/tests/helpers/test_template.py +++ b/tests/helpers/test_template.py @@ -6281,3 +6281,10 @@ def test_unzip(hass: HomeAssistant, col, expected) -> None: ).async_render({"col": col}) == expected ) + + +def test_template_output_exceeds_maximum_size(hass: HomeAssistant) -> None: + """Test template output exceeds maximum size.""" + tpl = template.Template("{{ 'a' * 1024 * 257 }}", hass) + with pytest.raises(TemplateError): + tpl.async_render()