T09 · Insecure Skill Coding Practices
Error
- Location
- lib/tqcenter.py:725
- Finding
- Path Traversal Enables Arbitrary File Deletion and Overwrite<![CDATA[ ## Vulnerability Details **File Location**: `lib/tqcenter.py`, lines 725–770 and 775–833 **Vulnerability Type**: Path traversal and unrestricted file overwrite **Risk Level**: High ### Vulnerable Code ```python with open(xml_filename, "w", encoding="gbk") as f: f.write(xml_content) json_dir = os.path.join(tdx_root_path, r"T0002\cloud_cache\list") os.makedirs(json_dir, exist_ok=True) for g_idx in range(group_count): current_df = df_list[g_idx] jsn_file = jsn_filenames[g_idx] col_header = ["date"] + [ f"code_g{g_idx + 1}_t1_{j}" for j, _ in enumerate(current_df.columns[1:], 1) ] data_rows = [] for _, row in current_df.iterrows(): date_str = ( row.iloc[0].strftime("%Y-%m-%d") if pd.api.types.is_datetime64_any_dtype(current_df.iloc[:, 0]) else str(row.iloc[0]) ) vals = [] for v in row.iloc[1:]: try: vals.append(float(v)) except: vals.append(str(v) if pd.notna(v) else "") data_rows.append([date_str] + vals) with open(jsn_file, "w", encoding="utf-8") as f: json.dump( [{"colheader": col_header, "data": data_rows}], f, ensure_ascii=False, indent=2 ) jsn_target = os.path.join(json_dir, jsn_file) if os.path.exists(jsn_target): os.remove(jsn_target) shutil.move(jsn_file, jsn_target) xml_dir = os.path.join(tdx_root_path, r"T0002\cloud_cfg") os.makedirs(xml_dir, exist_ok=True) xml_target = os.path.join(xml_dir, xml_filename) if os.path.exists(xml_target): os.remove(xml_target) shutil.move(xml_filename, xml_target) ``` The SP filename is handled in the same unsafe manner: ```python pad_dir = os.path.join(tdx_root_path, r"T0002\pad") os.makedirs(pad_dir, exist_ok=True) sp_file = f"{sp_name}.sp" if sp_name else "python.sp" sp_path = os.path.join(pad_dir, sp_file) with open(sp_path, "w", enco ...[truncated 2295 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Permit only basename-style filenames: - Reject absolute paths. - Reject `/`, `\`, `..`, drive prefixes, and null bytes. - Apply conservative character restrictions such as `^[A-Za-z0-9_-]+\.xml$`. 2. Enforce the expected extension independently for each output: - XML files must end in `.xml`. - JSON files must end in `.jsn` or the documented extension. - SP files must end in `.sp`. 3. Resolve and verify every destination before writing: ```python def safe_destination(root: Path, supplied_name: str, extension: str) -> Path: if Path(supplied_name).name != supplied_name: raise ValueError("Only simple filenames are permitted") if not supplied_name.lower().endswith(extension): raise ValueError(f"Filename must end with {extension}") root = root.resolve() destination = (root / supplied_name).resolve() destination.relative_to(root) return destination ``` 4. Write directly to a validated destination rather than first creating a file in the current working directory. 5. Use a securely created temporary file in the validated target directory and perform an atomic `os.replace()` only after serialization succeeds. 6. Do not automatically delete an existing file unless replacement is explicitly requested and authorized. 7. Run the exporter under a low-privilege account that has write access only to the required TongdaXin data directories. 8. Add automated tests covering absolute paths, Windows drive paths, UNC paths, mixed separators, encoded traversal, and repeated `..` components. ]]>
