T09 · Insecure Skill Coding Practices
- Location
studio/server.py:135- Finding
Unvalidated skill identifiers and manifest names permit workspace path traversal
- Content
View full analysis
= 3 else None con = self._con() try: if len(parts) == 2: # POST /api/skills -> create skill b = self._body() try: sid = db.create_skill(con, b["slug"], b["name"]) except Exception: return _json(self, 409, {"error": "exists or invalid"}) return _json(self, 201, {"id": sid, "slug": b["slug"]}) if len(parts) == 3: # GET one skill (handled in GET); POST here is invalid return _json(self, 405, {"error": "method not allowed"}) if len(parts) == 4 and parts[3] == "versions": # add version b = self._body() try: vid = db.add_version(con, slug, b["version"], json.dumps(b.get("manifest", {}))) # scaffold real skill files on disk so test/publish have something to run workspace.scaffold(data_dir, slug, b.get("manifest", {})) ``` ```python # studio/workspace.py:42-63 def skill_dir(data_dir: str, slug: str) -> str: return os.path.join(data_dir, "skills", slug) def _tool_name(manifest: dict, slug: str) -> str: base = (manifest.get("name") or slug).lower().replace(" ", "_").replace("-", "_") return f"{base}.py" def scaffold(data_dir: str, slug: str, manifest: dict) -> str: """Create/update the skill folder from a manifest. Returns the folder path.""" d = skill_dir(data_dir, slug) os.makedirs(d, exist_ok=True) body = f"# {manifest.get('name', slug)}\n\n{manifest.get('description', '')}\n" with open(os.path.join(d, "SKILL.md"), "w", encoding="utf-8") as f: f.write(skills.manifest_to_skill_md(manifest, body=body)) tool = _tool_name(manifest, slug) with open(os.path.join(d, tool) ...[truncated 3009 chars]- Remediation
View remediation
