From c14c4fb658dae18deb53fe425ea18a476f5572e9 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 12 Aug 2025 09:12:54 +1200 Subject: [PATCH] [substitutions] Add some safe built-in functions to jinja parsing (#10178) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- esphome/components/substitutions/jinja.py | 24 ++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/esphome/components/substitutions/jinja.py b/esphome/components/substitutions/jinja.py index cf393d2a5d..c6e40a668d 100644 --- a/esphome/components/substitutions/jinja.py +++ b/esphome/components/substitutions/jinja.py @@ -25,6 +25,24 @@ def has_jinja(st): return detect_jinja_re.search(st) is not None +# SAFE_GLOBAL_FUNCTIONS defines a allowlist of built-in functions that are considered safe to expose +# in Jinja templates or other sandboxed evaluation contexts. Only functions that do not allow +# arbitrary code execution, file access, or other security risks are included. +# +# The following functions are considered safe: +# - ord: Converts a character to its Unicode code point integer. +# - chr: Converts an integer to its corresponding Unicode character. +# - len: Returns the length of a sequence or collection. +# +# These functions were chosen because they are pure, have no side effects, and do not provide access +# to the file system, environment, or other potentially sensitive resources. +SAFE_GLOBAL_FUNCTIONS = { + "ord": ord, + "chr": chr, + "len": len, +} + + class JinjaStr(str): """ Wraps a string containing an unresolved Jinja expression, @@ -66,7 +84,11 @@ class Jinja: self.env.add_extension("jinja2.ext.do") self.env.globals["math"] = math # Inject entire math module self.context_vars = {**context_vars} - self.env.globals = {**self.env.globals, **self.context_vars} + self.env.globals = { + **self.env.globals, + **self.context_vars, + **SAFE_GLOBAL_FUNCTIONS, + } def expand(self, content_str): """