Version in base suite: 3.1.7-2 Base version: python-dynaconf_3.1.7-2 Target version: python-dynaconf_3.1.7-2+deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/p/python-dynaconf/python-dynaconf_3.1.7-2.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/p/python-dynaconf/python-dynaconf_3.1.7-2+deb13u1.dsc changelog | 6 ++ patches/CVE-2026-33154.patch | 127 +++++++++++++++++++++++++++++++++++++++++++ patches/series | 1 3 files changed, 134 insertions(+) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpxkq_i0m6/python-dynaconf_3.1.7-2.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpxkq_i0m6/python-dynaconf_3.1.7-2+deb13u1.dsc: no acceptable signature found diff -Nru python-dynaconf-3.1.7/debian/changelog python-dynaconf-3.1.7/debian/changelog --- python-dynaconf-3.1.7/debian/changelog 2022-10-28 17:43:27.000000000 +0000 +++ python-dynaconf-3.1.7/debian/changelog 2026-06-21 21:39:27.000000000 +0000 @@ -1,3 +1,9 @@ +python-dynaconf (3.1.7-2+deb13u1) trixie; urgency=medium + + * CVE-2026-33154 (Closes: #1131476) + + -- Moritz Mühlenhoff Sun, 21 Jun 2026 23:39:27 +0200 + python-dynaconf (3.1.7-2) unstable; urgency=medium [ Debian Janitor ] diff -Nru python-dynaconf-3.1.7/debian/patches/CVE-2026-33154.patch python-dynaconf-3.1.7/debian/patches/CVE-2026-33154.patch --- python-dynaconf-3.1.7/debian/patches/CVE-2026-33154.patch 1970-01-01 00:00:00.000000000 +0000 +++ python-dynaconf-3.1.7/debian/patches/CVE-2026-33154.patch 2026-06-21 21:39:21.000000000 +0000 @@ -0,0 +1,127 @@ +From 2fbb45ee36b8c0caa5b924fe19f3c1a5e8603fa7 Mon Sep 17 00:00:00 2001 +From: Pedro Brochado +Date: Fri, 13 Mar 2026 16:24:45 -0300 +Subject: [PATCH] Fix @jinja and @format templating vulnerabilities + +--- python-dynaconf-3.1.7.orig/dynaconf/base.py ++++ python-dynaconf-3.1.7/dynaconf/base.py +@@ -368,6 +368,13 @@ class Settings: + return parse_conf_data(result, tomlfy=True, box_settings=self) + return result + ++ # Still keys left, but current result/parent is not a data container ++ if keys and not isinstance(result, (dict, list)): ++ result_type = type(result).__name__ ++ raise AttributeError( ++ f"Invalid dotted lookup in {dotted_key}. {name} is a {result_type}" ++ ) ++ + # If we've still got key elements to traverse, let's do that. + return self._dotted_get( + ".".join(keys), default=default, parent=result, cast=cast, **kwargs +@@ -429,7 +436,7 @@ class Settings: + self.unset(key) + self.execute_loaders(key=key) + +- data = (parent or self.store).get(key, default) ++ data = _get_with_default(parent or self.store, key, default) + if cast: + data = get_converter(cast, data, box_settings=self) + return data +@@ -1216,3 +1223,21 @@ RESERVED_ATTRS = ( + "_validate_exclude", + ] + ) ++ ++# These are special fields defined by Dynaconf, but users can access it ++_PUBLIC_PROPERTIES = [name for name, _ in inspect.getmembers(Settings, lambda ++ x: isinstance(x, property))] ++ ++ ++def _get_with_default(data: dict | list, key: str, default): ++ if isinstance(data, dict): ++ return data.get(key, default) ++ elif isinstance(data, list): ++ if not key.isdigit(): ++ raise ValueError(f"Expected integer, got: {key}") ++ try: ++ return data[int(key)] ++ except KeyError: ++ return default ++ else: ++ raise AttributeError(f"Unknown data container type: {type(data)}") +--- python-dynaconf-3.1.7.orig/dynaconf/utils/parse_conf.py ++++ python-dynaconf-3.1.7/dynaconf/utils/parse_conf.py +@@ -1,6 +1,7 @@ + import json + import os + import re ++import string + import warnings + from functools import wraps + +@@ -12,9 +13,10 @@ from dynaconf.utils.boxing import DynaBo + from dynaconf.vendor import toml + + try: +- from jinja2 import Environment ++ import jinja2 ++ from jinja2.sandbox import SandboxedEnvironment + +- jinja_env = Environment() ++ jinja_env = SandboxedEnvironment() + for p_method in ("abspath", "realpath", "relpath", "dirname", "basename"): + jinja_env.filters[p_method] = getattr(os.path, p_method) + except ImportError: # pragma: no cover +@@ -142,18 +144,48 @@ class BaseFormatter: + return str(self.token) + + +-def _jinja_formatter(value, **context): ++def _jinja_formatter(value: str, **context) -> str: + if jinja_env is None: # pragma: no cover + raise ImportError( + "jinja2 must be installed to enable '@jinja' settings in dynaconf" + ) +- return jinja_env.from_string(value).render(**context) ++ try: ++ return jinja_env.from_string(value).render(**context) ++ except jinja2.exceptions.SecurityError: ++ warnings.warn(f"Unsafe access attempt to: {value}") ++ return "" ++ ++ ++class SafeFormatter(string.Formatter): ++ def get_field(self, field_name, args, context): ++ self._validate_key_exists(field_name, context) ++ return super().get_field(field_name, args, context) ++ ++ def _validate_key_exists(self, field_name: str, context): ++ if not field_name.lower().startswith("this"): ++ return ++ from dynaconf.base import _PUBLIC_PROPERTIES ++ ++ field_name = field_name.replace("[", ".") ++ field_name = field_name.replace("]", "") ++ context_name, _, key = field_name.partition(".") ++ # these are accesible by the user, but are not considered setting keys ++ # e.g, settings.current_env ++ if key in _PUBLIC_PROPERTIES: ++ return ++ # allow only existing setting keys ++ if key not in context[context_name]: ++ raise AttributeError(key) ++ ++ ++def _format_formatter(input: str, **context) -> str: ++ return SafeFormatter().format(input, **context) + + + class Formatters: + """Dynaconf builtin formatters""" + +- python_formatter = BaseFormatter(str.format, "format") ++ python_formatter = BaseFormatter(_format_formatter, "format") + jinja_formatter = BaseFormatter(_jinja_formatter, "jinja") + + diff -Nru python-dynaconf-3.1.7/debian/patches/series python-dynaconf-3.1.7/debian/patches/series --- python-dynaconf-3.1.7/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 +++ python-dynaconf-3.1.7/debian/patches/series 2026-06-21 21:39:10.000000000 +0000 @@ -0,0 +1 @@ +CVE-2026-33154.patch