bug: Dockerfile injection via unsanitized docker.env dict values
Describe the bug
Values supplied through the legacy docker.env dict (e.g. bentofile.yaml → docker.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_packages→bash_quoteinbase_debian.j2base_image→normalize_lineinbase.j2- list-form env (
env: ["K=V"]) → regex-validated inDockerOptions._convert_env(build_config.py) - the new
envs/BentoEnvSchemapath →normalize_line+bash_quoteinbase_v2.j2
The dict form (build_config.py) is converted with zero validation:
return {str(k): str(v) for k, v in env.items()}and rendered in base.j2 (SETUP_BENTO_ENVARS) as:
ARG {{ key }}={{ value }}
ENV {{ key }}=${{ key }}Root cause (source)
src/bentoml/_internal/container/frontend/dockerfile/templates/base.j2:46-48src/bentoml/_internal/container/frontend/dockerfile/templates/base_v2.j2:70src/bentoml/_internal/bento/build_config.py(_convert_env, dict branch)
To reproduce
bentofile.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):
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=$XThe 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)
Source: bentoml/BentoML