You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
security: alias path traversal in CommandRegistrar.register_commands() for flat agents #2229
Free-form aliases (permitted since #2125 / 4deb90f) can contain path separators that escape the agent commands directory when registered by flat-file agents (claude, gemini, copilot, etc.).
Root cause
`CommandRegistrar._compute_output_name()` returns the alias name unchanged for non-SKILL.md agents:
```python
if agent_config["extension"] != "/SKILL.md":
return cmd_name # alias returned as-is
```
`alias_file.parent.mkdir(parents=True, exist_ok=True)` will even create the parent directories.
Not affected
SKILL.md agents (codex, kimi) are safe — `_compute_output_name` replaces `.` with `-` and prepends `speckit-`, neutralising traversal sequences.
Suggested fix
Validate alias strings against a safe identifier pattern before writing, or resolve `alias_file` and assert it stays within `commands_dir` before writing.
Hi @mbachorik and @mnriem — I'm preparing a PR for this and wanted to confirm one design choice before opening it.
While reproducing #2229 on current main, I found two remaining unguarded write paths in addition to the alias case discussed in the issue:
The primary command write path in CommandRegistrar.register_commands()
write_copilot_prompt(), which writes {cmd_name}.prompt.md under .github/prompts/
My current patch applies the same containment check pattern to all three write sites.
The only design question is symlink handling:
A lexical path check would block .. / absolute-path traversal, but still allow writes through pre-planted symlinks under the commands directory.
A resolved-path containment check (resolve() + is_relative_to()) also blocks symlink escapes, but disallows intentionally symlinked subdirectories such as .claude/skills/shared -> /team/shared-skills.
My default is the resolved-path check, because it matches the alias guard already merged in b67b285 and closes the symlink escape vector as well.
Would you like this fix to block symlink escapes too, or should it preserve intentionally symlinked subdirectories and only block lexical traversal?
I can implement either version cleanly; I just wanted to confirm the intended policy before sending the PR.
Activity
chordpli commentedon Apr 21, 2026
Hi @mbachorik and @mnriem — I'm preparing a PR for this and wanted to confirm one design choice before opening it.
While reproducing #2229 on current
main, I found two remaining unguarded write paths in addition to the alias case discussed in the issue:CommandRegistrar.register_commands()write_copilot_prompt(), which writes{cmd_name}.prompt.mdunder.github/prompts/My current patch applies the same containment check pattern to all three write sites.
The only design question is symlink handling:
../ absolute-path traversal, but still allow writes through pre-planted symlinks under the commands directory.resolve()+is_relative_to()) also blocks symlink escapes, but disallows intentionally symlinked subdirectories such as.claude/skills/shared -> /team/shared-skills.My default is the resolved-path check, because it matches the alias guard already merged in
b67b285and closes the symlink escape vector as well.Would you like this fix to block symlink escapes too, or should it preserve intentionally symlinked subdirectories and only block lexical traversal?
I can implement either version cleanly; I just wanted to confirm the intended policy before sending the PR.
mnriem commentedon Apr 21, 2026
Pick whichever one is safer, but the most backwards compatible. There are plenty of extensions now so we should not disrupt them unless we have to
fix(agents): block directory traversal in command write paths (github…
fix(agents): block directory traversal in command write paths (#2229) (…
fix(agents): block directory traversal in command write paths (github…
mbachorik commentedon Apr 22, 2026
I'm sorry to be late to the party (was offline in plane). Thanks for taking care of this!
fix(agents): block directory traversal in command write paths (github…