T05 · Unauthorized Access and Privilege Escalation
- Location
scripts/graph_manager.py:41- Finding
Path Traversal Enables Unauthorized JSON File Access
- Content
View full analysis
str: """获取图谱文件路径""" return os.path.join(self.storage_dir, f"{pipeline_id}.json") ``` The resulting path is used directly for reading, writing, and deleting files: ```python graph_path = self._get_graph_path(pipeline_id) if os.path.exists(graph_path): try: with open(graph_path, 'r', encoding='utf-8') as f: data = json.load(f) self.cache[pipeline_id] = data return data except (json.JSONDecodeError, Exception): pass ``` ```python def _save_graph(self, pipeline_id: str, data: Dict): """保存图谱数据""" graph_path = self._get_graph_path(pipeline_id) self.cache[pipeline_id] = data with open(graph_path, 'w', encoding='utf-8') as f: json.dump(data, f, ensure_ascii=False, indent=2) ``` ```python def delete_graph(self, pipeline_id: str) -> Dict: """删除图谱""" if pipeline_id in self.cache: del self.cache[pipeline_id] graph_path = self._get_graph_path(pipeline_id) if os.path.exists(graph_path): os.remove(graph_path) return {"success": True, "message": "图谱已删除"} return {"success": False, "error": "图谱不存在"} ``` ### Technical Analysis The application incorporates `pipeline_id` directly into a filesystem path without validating its format or confirming that the normalized path remains inside `data/graphs`. `os.path.join()` does not prevent traversal. A value containing parent-directory components such as `../pipeline_state` produces a path equivalent to: ```text data/graphs/../pipeline_state.json ``` After filesystem normalization, this refers to: ```text data/pipeline_state.json ``` The `.json` suffix limits the primitiv ...[truncated 1717 chars]- Remediation
View remediation
None: if not isinstance(pipeline_id, str) or not PIPELINE_ID_PATTERN.fullmatch(pipeline_id): raise ValueError("Invalid pipeline identifier") ``` 2. Resolve and verify canonical path containment: ```python def _get_graph_path(self, pipeline_id: str) -> str: self._validate_pipeline_id(pipeline_id) base = os.path.realpath(self.storage_dir) candidate = os.path.realpath(os.path.join(base, f"{pipeline_id}.json")) if os.path.commonpath([base, candidate]) != base: raise ValueError("Graph path escapes the storage directory") return candidate ``` 3. Explicitly reject: - `..` components. - `/` and `\` path separators. - Absolute paths. - Null bytes and unexpected Unicode separator variants. 4. Defend against symbolic-link attacks by ensuring the storage directory is trusted and, where supported, opening files with no-follow semantics. 5. Apply authorization checks so a caller may only access graph files belonging to its own pipeline or tenant. 6. Use atomic writes with restrictive permissions to reduce corruption and unintended disclosure. ]]>
