T09 · Insecure Skill Coding Practices
Error
- Location
- main.py:88
- Finding
- Channel-Controlled Directory Traversal in Download Destination<![CDATA[ ## Vulnerability Details **File Location**: `main.py`, lines 88–95 and 127–132 **Vulnerability Type**: Directory traversal and insufficient destination-path validation **Risk Level**: High ### Vulnerable Code ```python # Extract the text of the message to use as a header msg_text = msg.inner_text() # --- HEADER DETECTION --- # If message has text, split by newlines. # We assume the first line (if it doesn't contain 'http' or 'publicearn') is the category header. if msg_text: lines = [line.strip() for line in msg_text.split('\n') if line.strip()] if lines: first_line = lines[0] # Heuristic: If it looks like a title (no URLs, reasonable length) if "http" not in first_line and "publicearn" not in first_line and len(first_line) < 60: sanitized_header = sanitize_name(first_line) if sanitized_header: current_folder = sanitized_header ``` ```python # Create target directory based on the current header target_dir = os.path.join(base_dir, current_folder) if not os.path.exists(target_dir): os.makedirs(target_dir) file_path = os.path.join(target_dir, safe_filename) ``` The relevant sanitizer is: ```python def sanitize_name(text): """Removes emojis, illegal OS characters, and trims whitespace for safe folder/file names.""" # Remove emojis and special characters, keep alphanumeric, spaces, and basic punctuation clean_text = re.sub(r'[^\w\s\-\.]', '', text) return re.sub(r'[\\/*?:"<>|]', "", clean_text).strip() ``` ### Technical Analysis Folder names are derived from Telegram message content, which can be controlled by a channel administrator or anyone otherwise able to publish messages in the selected channel. Although `sanitize_name()` removes path separators, it explicitly permits periods and does not reject the special path components `.` and `..`. Consequently, a message whose first nonempty line is `..` sets `current_folder` to `..`. The expression `os.path.jo ...[truncated 2304 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Explicitly reject empty names, `.` and `..` after sanitization. 2. Resolve the base directory and destination using `os.path.realpath()` or `pathlib.Path.resolve()`. 3. Verify containment before creating a directory or saving a file: ```python from pathlib import Path base_path = Path(download_directory).resolve() def safe_child(base: Path, folder: str, filename: str) -> Path: if folder in {"", ".", ".."}: raise ValueError("Invalid folder name") destination = (base / folder / filename).resolve() if not destination.is_relative_to(base): raise ValueError("Destination escapes the configured download directory") return destination ``` 4. Reject absolute paths and all path separators before path construction, even if the current sanitizer is expected to remove them. 5. Refuse to follow symbolic links in destination components. Where supported, use descriptor-based filesystem operations and no-follow flags to reduce time-of-check/time-of-use risks. 6. Use `mkdir(parents=True, exist_ok=True)` only after containment validation. 7. Avoid silently replacing existing files. Use exclusive file creation or generate a collision-safe filename. 8. Add tests for `..`, `.`, Unicode path edge cases, symbolic links, absolute paths, and nested traversal attempts. ]]>
