Skip to content

[SECURITY] apc import copies skill directories without name sanitization #28

@FZ2000

Description

@FZ2000

Severity: P2

Summary

The apc import command copies skill directories from an export archive using raw filesystem names (src.name) without calling sanitize_skill_name(). This creates an asymmetry with apc install, which enforces the regex ^[A-Za-z0-9][A-Za-z0-9_\-]{0,63}$.

A crafted export archive can install skills with names that would be rejected by apc install.

Affected Code

src/export_import.py:

for src in sorted(import_skills_dir.iterdir()):
    if src.is_dir() and (src / "SKILL.md").exists():
        dst = skills_dir / src.name    # <-- no sanitize_skill_name() call
        if dst.exists():
            shutil.rmtree(dst)
        shutil.copytree(src, dst)

Compare to apc install (src/install.py), which calls sanitize_skill_name(skill["name"]) before writing.

Problematic Names Importable via Crafted Archive

  • .hidden-skill (dotfile in ~/.apc/skills/)
  • Skills with spaces or special characters in directory names
  • Names longer than 64 characters
  • Names starting with digits or underscores

Impact

  • Inconsistent state in the skills directory with names that violate the expected invariant
  • Dotfile skill directories could interfere with tool detection or glob patterns
  • May bypass future enforcement that relies on the regex invariant being maintained
  • While full path traversal via ../ is prevented by the OS (can't have / in filename), the weaker invariants allow edge cases

Recommended Fix

from skills import sanitize_skill_name

for src in sorted(import_skills_dir.iterdir()):
    if src.is_dir() and (src / "SKILL.md").exists():
        try:
            safe_name = sanitize_skill_name(src.name)
        except ValueError as e:
            warning(f"Skipping skill with invalid name {src.name!r}: {e}")
            continue
        dst = skills_dir / safe_name
        if dst.exists():
            shutil.rmtree(dst)
        shutil.copytree(src, dst)
        count += 1

References

  • CWE-20: Improper Input Validation

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingsecuritySecurity vulnerability

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions