T09 · Insecure Skill Coding Practices
- Location
scripts/feed/source/handlers/common.py:33- Finding
Arbitrary Filesystem Writes Through Unsanitized Knowledge Source Keys
- Content
View full analysis
Dict[str, str]: """Normalise a parsed row into the source dict handlers expect.""" key = row["key"] handler = row["handler"].lower() url = row["feed url"] name = ( row.get("name") or row.get("source") or row.get("name / source") or key ) author = row.get("author") or name return { "key": key, "name": name, "author": author, "handler": handler, "url": url, } ``` `scripts/feed/source/handlers/common.py:33-39`: ```python def source_dir(source_key: str) -> Path: return KNOWLEDGE_DIR / source_key def images_dir(source_key: str) -> Path: d = source_dir(source_key) / "images" d.mkdir(parents=True, exist_ok=True) return d ``` `scripts/feed/source/handlers/rss.py:19-24,57-63`: ```python def crawl(source: dict, max_articles: int = 0, recrawl: bool = False) -> int: key = source["key"] name = source["name"] author = source["author"] feed_url = source["url"] out_dir = source_dir(key) out_dir.mkdir(parents=True, exist_ok=True) # ... fm = build_frontmatter(title, date, url, key, name, author) dest.write_text(fm + content, encoding="utf-8") saved += 1 ``` ### Technical Analysis The source key is parsed directly from the user-controlled `knowledge/index.md` table and is not constrained to a safe filename format. `pathlib` discards the left operand when the right operand is absolute, and relative components such as `../` are a ...[truncated 1941 chars]- Remediation
View remediation
str: if not SAFE_SOURCE_KEY.fullmatch(value): raise ValueError(f"Invalid source key: {value!r}") return value ``` 2. Resolve every destination and enforce containment: ```python def safe_child(base: Path, *parts: str) -> Path: root = base.resolve() candidate = root.joinpath(*parts).resolve() if not candidate.is_relative_to(root): raise ValueError("Path escapes the configured data directory") return candidate ``` 3. Apply containment checks to article directories, image directories, and final files immediately before directory creation or writing. 4. Reject absolute keys, empty keys, dot components, path separators, and encoded traversal sequences. 5. Avoid overwriting existing files by default. Use exclusive creation or an atomic temporary file followed by a checked rename. 6. Add tests for `../`, absolute paths, repeated separators, symbolic-link escapes, and platform-specific path syntax. ]]>
