Context
Minor hardening items in the skill-install path, grouped from the 2026-07-06 audit. Path traversal in multi-file installs is already correctly blocked (absolute paths and .. rejected, internal/skillinstall/installer.go:206-209) — these are the residual edges.
Bugs
- Supporting file named
SKILL.md overwrites the rendered primary. In writeBodies (installer.go:195), the primary SKILL.md (frontmatter-fixed + preamble-injected) is written, then supporting files are written verbatim — a server-supplied supporting file with path SKILL.md clobbers it, removing the execution preamble and the name: normalization. Fix: reject/skip supporting files whose cleaned path is SKILL.md (case-insensitively; also consider rejecting skill.md on case-insensitive filesystems).
- Supporting file path
. or empty aborts the whole tree install. A path that cleans to . makes os.WriteFile fail on the directory and the entire skill install errors out. Fix: validate cleaned paths are non-empty relative file paths before writing; skip invalid entries with a warning rather than failing the tree.
- Double prefix:
PrefixedName() = "praxis-" + Name unconditionally (internal/skillcatalog/skillcatalog.go:67, same in agentcatalog.go:61) — a server skill already named praxis-foo installs as praxis-praxis-foo. Fix: don't re-prefix names already starting with praxis- (or reject them server-side; see the meta-skill collision issue for the related namespace question).
Acceptance
Table-driven tests in skillinstall covering: supporting file named SKILL.md (skipped, primary intact), path ./empty (skipped with warning, rest of tree installs), server name praxis-foo (no double prefix).
Context
Minor hardening items in the skill-install path, grouped from the 2026-07-06 audit. Path traversal in multi-file installs is already correctly blocked (absolute paths and
..rejected,internal/skillinstall/installer.go:206-209) — these are the residual edges.Bugs
SKILL.mdoverwrites the rendered primary. InwriteBodies(installer.go:195), the primary SKILL.md (frontmatter-fixed + preamble-injected) is written, then supporting files are written verbatim — a server-supplied supporting file with pathSKILL.mdclobbers it, removing the execution preamble and thename:normalization. Fix: reject/skip supporting files whose cleaned path isSKILL.md(case-insensitively; also consider rejectingskill.mdon case-insensitive filesystems)..or empty aborts the whole tree install. A path that cleans to.makesos.WriteFilefail on the directory and the entire skill install errors out. Fix: validate cleaned paths are non-empty relative file paths before writing; skip invalid entries with a warning rather than failing the tree.PrefixedName()="praxis-" + Nameunconditionally (internal/skillcatalog/skillcatalog.go:67, same inagentcatalog.go:61) — a server skill already namedpraxis-fooinstalls aspraxis-praxis-foo. Fix: don't re-prefix names already starting withpraxis-(or reject them server-side; see the meta-skill collision issue for the related namespace question).Acceptance
Table-driven tests in
skillinstallcovering: supporting file named SKILL.md (skipped, primary intact), path./empty (skipped with warning, rest of tree installs), server namepraxis-foo(no double prefix).