Security: two issues on the agents create remote-template path (fix branch attached)
Reported to the Google OSS VRP (g.co/vulnz), which validated it and asked for a fix as a PR. External PRs appear to be disabled on this mirror repo (CONTRIBUTING.md notes PRs aren't accepted), so I'm filing here with a ready-to-import fix branch.
Fix branch: main...aaronjmars:agents-cli:fix/security-template-symlink-and-path-traversal
File: src/google/agents/cli/scaffold/utils/template.py (+32 lines, no behavior change for legitimate templates)
In both cases the attacker is a malicious or compromised remote template repository, and the victim is a developer who runs agents create against it.
1. HIGH — symlink following → arbitrary local file read (CWE-59 / CWE-61 / CWE-200)
copy_files() copies template files with is_dir() + shutil.copy2, both of which dereference symlinks, and should_skip() has no symlink guard. Remote template files are copied after cookiecutter runs, so nothing mediates them.
A malicious template can ship a symlink pointing outside the template, e.g.:
creds -> ~/.ssh/id_rsa
env -> ~/.config/gcloud/application_default_credentials.json
On agents create, the contents of those local files are copied into the generated project as ordinary files. The developer then typically git adds, commits, and pushes the new project — silently exfiltrating SSH keys / cloud credentials / .env secrets.
Fix: should_skip() skips symlinks entirely (never follows them) and logs a warning.
2. MEDIUM — path traversal via remote manifest agent_directory (CWE-22)
validate_agent_directory_name() early-returns for non-python languages. A remote manifest with language: go|java|typescript and agent_directory: "../../.." is therefore never validated, and traverses out of the intended output directory when joined into write paths (project_template / agent_directory).
Fix: before the language-specific checks, reject .. components, absolute paths, drive-qualified paths, and a leading ~ for all languages. Legitimate nested relative directories still validate — notably the built-in Java template's agent_directory: "src/main/java".
Testing
- Traversal validation —
app, agent, src/main/java, my_agent still pass; ../../../etc, ..\..\Windows, /etc/cron.d/x, ~/.ssh, C:\Windows, foo/../../bar are rejected across go/java/typescript; python identifier rules unchanged.
- Symlink copy — before/after harness with a
creds -> secret symlink: original copies the secret's contents into the generated project; patched skips the symlink and nothing leaks.
Notes
- Happy to sign the Google CLA (cla.developers.google.com) if the fix is imported, and to adjust to whatever contribution form you prefer.
- Detected by Aeon.
Security: two issues on the
agents createremote-template path (fix branch attached)Reported to the Google OSS VRP (g.co/vulnz), which validated it and asked for a fix as a PR. External PRs appear to be disabled on this mirror repo (
CONTRIBUTING.mdnotes PRs aren't accepted), so I'm filing here with a ready-to-import fix branch.Fix branch: main...aaronjmars:agents-cli:fix/security-template-symlink-and-path-traversal
File:
src/google/agents/cli/scaffold/utils/template.py(+32 lines, no behavior change for legitimate templates)In both cases the attacker is a malicious or compromised remote template repository, and the victim is a developer who runs
agents createagainst it.1. HIGH — symlink following → arbitrary local file read (CWE-59 / CWE-61 / CWE-200)
copy_files()copies template files withis_dir()+shutil.copy2, both of which dereference symlinks, andshould_skip()has no symlink guard. Remote template files are copied after cookiecutter runs, so nothing mediates them.A malicious template can ship a symlink pointing outside the template, e.g.:
On
agents create, the contents of those local files are copied into the generated project as ordinary files. The developer then typicallygit adds, commits, and pushes the new project — silently exfiltrating SSH keys / cloud credentials /.envsecrets.Fix:
should_skip()skips symlinks entirely (never follows them) and logs a warning.2. MEDIUM — path traversal via remote manifest
agent_directory(CWE-22)validate_agent_directory_name()early-returns for non-python languages. A remote manifest withlanguage: go|java|typescriptandagent_directory: "../../.."is therefore never validated, and traverses out of the intended output directory when joined into write paths (project_template / agent_directory).Fix: before the language-specific checks, reject
..components, absolute paths, drive-qualified paths, and a leading~for all languages. Legitimate nested relative directories still validate — notably the built-in Java template'sagent_directory: "src/main/java".Testing
app,agent,src/main/java,my_agentstill pass;../../../etc,..\..\Windows,/etc/cron.d/x,~/.ssh,C:\Windows,foo/../../barare rejected across go/java/typescript; python identifier rules unchanged.creds -> secretsymlink: original copies the secret's contents into the generated project; patched skips the symlink and nothing leaks.Notes