T09 · Insecure Skill Coding Practices
- Location
src/mcp_server.py:31- Finding
Path Traversal Enables Constrained Local File Disclosure
- Content
View full analysis
dict: """加载知识库""" kb_path = KNOWLEDGE_DIR / f'{chip.lower()}_kb.json' if not kb_path.exists(): raise FileNotFoundError(f"知识库不存在: {kb_path}") with open(kb_path, 'r', encoding='utf-8') as f: return json.load(f) ``` ```python periph_upper = peripheral.upper() template_file = TEMPLATE_MAP.get( periph_upper, f'{peripheral.lower()}_init.c' ) template_path = TEMPLATES_DIR / template_file if template_path.exists(): template = template_path.read_text() ``` ### Technical Analysis The MCP client controls the `chip` and `peripheral` parameters. These values are incorporated directly into filesystem paths without an identifier allowlist, separator rejection, canonicalization, or verification that the resolved path remains under `knowledge/` or `templates/`. Python's `pathlib` does not automatically confine paths to the directory represented by the left operand. Inputs containing `../` components can therefore escape the intended directories. The generated suffixes constrain exploitation: - Knowledge-base targets must end in `_kb.json` and contain valid JSON. Subsequent operations may additionally require the expected knowledge-base structure. - Template targets must end in `_init.c`. The template path is the more direct disclosure route because the selected file is read as text and returned by `generate_code`. The flaw does not permit unrestricted arbitrary-file reading, but it can disclose readable files whose paths satisfy the generated naming convention. Raw exception messages may also expose server filesystem paths. ### Attack Path 1. An attacker obtains permission to call the exposed MCP tools. 2. The attacker calls `generate_code` with an unrecognize ...[truncated 1150 chars]- Remediation
View remediation
dict: key = chip.upper() if key not in KB_FILES: raise ValueError("Unsupported chip") with KB_FILES[key].open("r", encoding="utf-8") as file: return json.load(file) ``` 2. Do not derive fallback template paths from untrusted peripheral names. Require the requested peripheral to exist in `TEMPLATE_MAP`. 3. If dynamic paths are necessary, reject absolute paths, path separators, null bytes, and `..` components. 4. Resolve and enforce directory containment before reading: ```python base = TEMPLATES_DIR.resolve() candidate = (base / template_file).resolve() if not candidate.is_relative_to(base): raise ValueError("Invalid template path") ``` 5. Return generic client-facing errors and log detailed exceptions locally rather than exposing absolute filesystem paths. 6. Add regression tests covering `../`, absolute paths, nested traversal, mixed separators, encoded traversal strings, and unsupported identifiers. ]]>
