#5656·BentoML

bug: Dockerfile injection via unsanitized docker.env dict values

Author: ammmanismCreated Jul 11, 2026Updated Aug 22, 2026

Describe the bug

Values supplied through the legacy docker.env dict (e.g. bentofile.yamldocker.env: {KEY: VALUE}) are interpolated into the generated Dockerfile without sanitization. A value containing a newline character breaks out of the ARG/ENV line and injects an arbitrary Dockerfile instruction (e.g. RUN ...), which executes during docker build. The base_v2.j2 template has the same flaw — it applies bash_quote but that filter does not remove newlines (it wraps the value in single quotes, but the Dockerfile lexer treats the physical newline as a line break regardless).

This is an asymmetry with sibling paths already hardened:

  • system_packagesbash_quote in base_debian.j2
  • base_imagenormalize_line in base.j2
  • list-form env (env: ["K=V"]) → regex-validated in DockerOptions._convert_env (build_config.py)
  • the new envs / BentoEnvSchema path → normalize_line + bash_quote in base_v2.j2

The dict form (build_config.py) is converted with zero validation:

python
return {str(k): str(v) for k, v in env.items()}

and rendered in base.j2 (SETUP_BENTO_ENVARS) as:

jinja
ARG {{ key }}={{ value }}
ENV {{ key }}=${{ key }}

Root cause (source)

  • src/bentoml/_internal/container/frontend/dockerfile/templates/base.j2:46-48
  • src/bentoml/_internal/container/frontend/dockerfile/templates/base_v2.j2:70
  • src/bentoml/_internal/bento/build_config.py (_convert_env, dict branch)

To reproduce

bentofile.yaml:

yaml
service: "service:Summarization"
docker:
  env:
    X: "a
RUN echo PWNED_VIA_ENV_INJECTION
"

Run bentoml build and inspect the generated Dockerfile.

Minimal Python reproduction (no Docker needed — renders the Dockerfile directly):

python
import tempfile
from pathlib import Path
from bentoml._internal.bento.build_config import DockerOptions, CondaOptions
from bentoml._internal.container.generate import generate_containerfile

payload = "a\nRUN echo PWNED_VIA_ENV_INJECTION\n"
tmp = Path(tempfile.mkdtemp())
(tmp / "bento").mkdir()
df = generate_containerfile(
    DockerOptions(env={"X": payload}, python_version="3.11", distro="debian"),
    str(tmp), conda=CondaOptions(), bento_fs=tmp / "bento",
)
print("Injection present:", "\nRUN echo PWNED_VIA_ENV_INJECTION" in df)

Actual generated Dockerfile snippet (vulnerable):

ARG X=a
RUN echo PWNED_VIA_ENV_INJECTION

ENV X=$X

The RUN echo PWNED_VIA_ENV_INJECTION step executes during docker build.

Expected behavior

Env values must be sanitized (newlines / control characters stripped, values quoted) so they cannot produce new Dockerfile instructions — matching the hardening already applied to system_packages, base_image, and the envs / BentoEnvSchema path. A legitimate value such as {"GREETING": "hello world"} should render as ARG GREETING='hello world'.

Environment

bentoml: 1.4.39.post2+g73c4dbea.d20260710
python: 3.12.10
platform: Windows-11-10.0.26200-SP0 (build-backend agnostic)
commit: 73c4dbea (HEAD, origin/main)

Impact

High — arbitrary command execution at image-build time from untrusted / CI-templated env values. Even non-malicious multi-line env values silently break the build. Affects every bentoml build / containerize user using the docker.env dict (the default path for bentofile.yaml).

Related

  • PR #5603 — fixed base_image normalize_line (same class)
  • PR #79fbea5a — fixed system_packages bash_quote (same class)
  • PR #5614 — validates only the new envs[*].name POSIX regex (different field; does not touch legacy values)
  • Distinct from #5615 (FileSchema str-decode)