From 2fbbbbe9a981ed90834ee838016a3842915a00bd Mon Sep 17 00:00:00 2001 From: FreddleSpl0it <75116288+FreddleSpl0it@users.noreply.github.com> Date: Wed, 2 Jul 2025 08:59:29 +0200 Subject: [PATCH] [Dovecot] Use Jinja2 sandbox for rendering quota and quarantine notifications --- data/Dockerfiles/dovecot/quarantine_notify.py | 26 ++++++++++++------- data/Dockerfiles/dovecot/quota_notify.py | 22 +++++++++++----- docker-compose.yml | 2 +- 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/data/Dockerfiles/dovecot/quarantine_notify.py b/data/Dockerfiles/dovecot/quarantine_notify.py index dfcb1f2c6..824d4092f 100755 --- a/data/Dockerfiles/dovecot/quarantine_notify.py +++ b/data/Dockerfiles/dovecot/quarantine_notify.py @@ -8,7 +8,8 @@ from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.utils import COMMASPACE, formatdate import jinja2 -from jinja2 import Template +from jinja2 import TemplateError +from jinja2.sandbox import SandboxedEnvironment import json import redis import time @@ -80,17 +81,22 @@ try: if len(meta_query) == 0: return msg_count = len(meta_query) + env = SandboxedEnvironment() if r.get('Q_HTML'): - try: - template = Template(r.get('Q_HTML')) - except: - print("Error: Cannot parse quarantine template, falling back to default template.") - with open('/templates/quarantine.tpl') as file_: - template = Template(file_.read()) + try: + template = env.from_string(r.get('Q_HTML')) + except Exception: + print("Error: Cannot parse quarantine template, falling back to default template.") + with open('/templates/quarantine.tpl') as file_: + template = env.from_string(file_.read()) else: - with open('/templates/quarantine.tpl') as file_: - template = Template(file_.read()) - html = template.render(meta=meta_query, username=rcpt, counter=msg_count, hostname=mailcow_hostname, quarantine_acl=quarantine_acl) + with open('/templates/quarantine.tpl') as file_: + template = env.from_string(file_.read()) + try: + html = template.render(meta=meta_query, username=rcpt, counter=msg_count, hostname=mailcow_hostname, quarantine_acl=quarantine_acl) + except (jinja2.exceptions.SecurityError, TemplateError) as ex: + print(f"SecurityError or TemplateError in template rendering: {ex}") + return text = html2text.html2text(html) count = 0 while count < 15: diff --git a/data/Dockerfiles/dovecot/quota_notify.py b/data/Dockerfiles/dovecot/quota_notify.py index 598134e22..99be7cc68 100755 --- a/data/Dockerfiles/dovecot/quota_notify.py +++ b/data/Dockerfiles/dovecot/quota_notify.py @@ -6,7 +6,7 @@ from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.utils import COMMASPACE, formatdate import jinja2 -from jinja2 import Template +from jinja2.sandbox import SandboxedEnvironment import redis import time import json @@ -33,16 +33,24 @@ while True: if r.get('QW_HTML'): try: - template = Template(r.get('QW_HTML')) - except: - print("Error: Cannot parse quarantine template, falling back to default template.") + env = SandboxedEnvironment() + template = env.from_string(r.get('QW_HTML')) + except Exception: + print("Error: Cannot parse quota template, falling back to default template.") with open('/templates/quota.tpl') as file_: - template = Template(file_.read()) + env = SandboxedEnvironment() + template = env.from_string(file_.read()) else: with open('/templates/quota.tpl') as file_: - template = Template(file_.read()) + env = SandboxedEnvironment() + template = env.from_string(file_.read()) + +try: + html = template.render(username=username, percent=percent) +except (jinja2.exceptions.SecurityError, jinja2.TemplateError) as ex: + print(f"SecurityError or TemplateError in template rendering: {ex}") + sys.exit(1) -html = template.render(username=username, percent=percent) text = html2text.html2text(html) try: diff --git a/docker-compose.yml b/docker-compose.yml index a67475316..6db20454e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -251,7 +251,7 @@ services: - sogo dovecot-mailcow: - image: ghcr.io/mailcow/dovecot:2.33 + image: ghcr.io/mailcow/dovecot:2.34 depends_on: - mysql-mailcow - netfilter-mailcow