T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/figma_common.py:34
- Finding
- Unsanitized Figma File Key Allows Cache Path Traversal<![CDATA[ ## Vulnerability Details **File Location**: `scripts/figma_common.py:34-50` **Vulnerability Type**: Path traversal and unintended filesystem writes **Risk Level**: Medium ### Vulnerable Code ```python def cache_path(file_key: str) -> Path: p = CACHE_DIR / file_key p.mkdir(parents=True, exist_ok=True) return p def api_get(path: str, file_key: str = "", use_cache: bool = True, params: dict = None) -> dict: """GET from Figma API with retry, backoff, and ETag caching.""" url = f"{FIGMA_API}{path}" hdrs = headers() etag_file = None cache_file = None if use_cache and file_key: cp = cache_path(file_key) safe = path.replace("/", "_").strip("_") cache_file = cp / f"{safe}.json" etag_file = cp / f"{safe}.etag" ``` The response and ETag are subsequently written to these paths: ```python if cache_file: cache_file.write_text(json.dumps(data, sort_keys=True)) if etag_file and "ETag" in resp.headers: etag_file.write_text(resp.headers["ETag"]) ``` ### Technical Analysis The `file_key` value originates from the command-line `--file-key` argument and is directly combined with `.figma-cache` as a filesystem path. The implementation does not reject absolute paths, path separators, or traversal components such as `..`. In Python, combining a `Path` with an absolute second operand discards the preceding base path. Relative traversal components can similarly cause the resolved path to leave `.figma-cache`. A successful API request can therefore cause response JSON and ETag data to be written outside the intended cache boundary. The generated filenames are derived from the API path and have fixed `.json` or `.etag` suffixes, which limits arbitrary filename control but does not prevent unauthorized directory creation or unintended file replacement. ### Attack Path 1. An attacker or untrusted automation supplies a crafted value such as an absolute path or a file key containing `../`. 2. A p ...[truncated 923 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Validate `file_key` against the documented Figma key format and reject path separators, absolute paths, empty values, and traversal components. 2. Use a filesystem-safe cache identifier, such as a SHA-256 digest of the file key, rather than the raw value. 3. Resolve the candidate cache path and verify that it remains under the resolved cache root before creating directories or writing files. 4. Apply the same containment validation to cache filenames derived from API paths. 5. Use restrictive directory and file permissions where supported. Example hardening: ```python def cache_path(file_key: str) -> Path: if not re.fullmatch(r"[A-Za-z0-9_-]+", file_key): raise ValueError("Invalid Figma file key") root = CACHE_DIR.resolve() cache_id = hashlib.sha256(file_key.encode()).hexdigest() target = (root / cache_id).resolve() if target.parent != root: raise ValueError("Cache path escapes cache directory") target.mkdir(parents=True, exist_ok=True) return target ``` ]]>
