GHSA-v959-cwq9-7hr6 BentoML: SSTI via Unsandboxed Jinja2 in Dockerfile Generation
SummaryThe 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.DetailsThe vulnerability exists in the `generate_containerfile()` function at `src/bentoml/_internal/container/generate.py:155-157`: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:****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`:**Attacker exports** the bento as a `.bento` or `.tar.gz` archive and distributes it (via S3, HTTP, direct sharing, etc.).**Victim imports** the bento with `bentoml import bento.tar` — no validation of template content is performed.**Victim containerizes** with `bentoml containerize`. The `construct_containerfile()` function (`__init__.py:198-204`) detects the template and sets the path:**`generate_containerfile()`** (`generate.py:181-192`) loads the attacker-controlled template into the unsandboxed Environment and renders it at line 202:**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`:****Step 2: Create `bentofile.yaml` referencing the template:****Step 3: Attacker builds and exports:****Step 4: Victim imports and containerizes:****Step 5: Verify host code execution:**The SSTI payload executes on the host during template rendering, before any Docker container is created.**Standalone verification that the Jinja2 Environment allows code execution:**ImpactAn attacker who distributes a malicious bento archive can achieve **arbitrary code execution on the host machine** of any user who imports and containerizes the bento. This gives the attacker:Full access to the host filesystem (source code, credentials, SSH keys, cloud tokens)Ability to install backdoors or pivot to other systemsAccess to environment variables containing secrets (API keys, database credentials)Potential supply chain compromise if the victim's machine is a CI/CD runnerThe attack is particularly dangerous because:Users may reasonably expect `bentoml containerize` to be a safe build operationThe malicious template is embedded inside the bento archive and not visible without manual inspectionExecution happens on the host, not inside a Docker container, bypassing all isolationRecommended FixReplace the unsandboxed `jinja2.Environment` with `jinja2.sandbox.SandboxedEnvironment` and remove the dangerous `jinja2.ext.do` and `jinja2.ext.debug` extensions, which are unnecessary for Dockerfile template rendering.In `src/bentoml/_internal/container/generate.py`, change lines 155-157:Additionally, review the second unsandboxed Environment in `build_config.py:499-504` which also uses `jinja2.ext.debug`:
CVSS v3.1 score: 8.8