T09 · Insecure Skill Coding Practices
- Location
scripts/manage_emojis.py:65- Finding
Unsanitized User Identifier Allows Filesystem Path Traversal
- Content
View full analysis
Tuple[str, str]: """ 创建新版本(保存头像) 返回:(userid, version_path) """ if userid is None: userid = self.generate_userid() # 创建版本文件夹:__ timestamp = int(time.time()) # 查找该 userid 的最大 seq existing_versions = [] for item in self.assets_public.iterdir(): if item.is_dir() and item.name.startswith(f"{userid}_"): parts = item.name.split('_') if len(parts) >= 3: seq = int(parts[-1]) existing_versions.append((seq, item)) seq = 1 if existing_versions: seq = max(seq, *[v[0] for v in existing_versions]) + 1 version_dir = self.assets_public / f"{userid}_{timestamp}_{seq}" version_dir.mkdir(parents=True, exist_ok=True) # 保存头像 avatar_dest = version_dir / "avatar.jpg" shutil.copy2(avatar_path, avatar_dest) # 更新索引 self.index["users"][userid] = { "latest_version": version_dir.name, "versions": [v[1].name for v in sorted(existing_versions, key=lambda x: x[0])] + [version_dir.name], "avatar_path": str(avatar_dest) } ``` ```python # scripts/manage_emojis.py:127-140 sorted_versions = sorted( versions, key=lambda v: int(v.split('_')[-1]) ) to_delete = sorted_versions[:-max_versions] for v in to_delete: v_path = self.assets_public / v if v_path.exists(): shutil.rmtree(v_path) prin ...[truncated 2699 chars]- Remediation
View remediation
str: if not USER_ID_PATTERN.fullmatch(userid): raise ValueError("Invalid user identifier") return userid ``` 2. Reject absolute paths, path separators, `.` components, and `..` components even if future identifier formats become more permissive. 3. Resolve each destination and verify that it remains beneath the intended root: ```python root = self.assets_public.resolve() destination = (root / directory_name).resolve() if destination != root and root not in destination.parents: raise ValueError("Destination escapes the asset directory") ``` 4. Apply the same containment check immediately before `mkdir()`, `copy2()`, and `rmtree()` operations. 5. Validate every version name loaded from `index.json`. Prefer storing opaque version identifiers rather than filesystem paths. 6. Before recursive deletion, require that the target: - Is a direct child of `assets/public`; - Matches the expected version naming pattern; - Is not a symbolic link; - Resolves beneath the asset root. 7. Treat index files as security-sensitive state. Use restrictive file permissions, atomic writes, schema validation, and integrity protection where appropriate. 8. Add tests covering absolute paths, nested paths, `../` traversal, symbolic links, malformed index entries, and identifiers containing platform-specific separators. ]]>
