T09 · Insecure Skill Coding Practices
- Location
scripts/capabilities/customer_list/cmd.py:165- Finding
Arbitrary Accessible Directory Enumeration Through File-Read Error Diagnostics
- Content
View full analysis
str: """构建文件未找到时的诊断提示,帮助区分目录错配 vs 写未落盘。""" scratch = os.environ.get('NEWTON_SCRATCH_DIR') or "" temp = os.environ.get('TEMP') or "" parts = [ "。可能原因:", "1) 写文件与调用使用了不同的临时目录(NEWTON_SCRATCH_DIR 与 %TEMP% 指向不同路径);", "2) 写文件命令未成功落盘(exit≠0/超时),但下一步未检查直接读取;", "3) 使用了相对路径、/tmp 或 %TEMP% 字面量,未使用写入时输出的绝对路径。", f"当前 NEWTON_SCRATCH_DIR={scratch or '未设置'};TEMP={temp or '未设置'}。", ] # 列出目标路径所在目录的现有文件,帮助定位是目录错配还是写未落盘 try: dir_path = os.path.dirname(os.path.abspath(path)) if os.path.isabs(path) else os.getcwd() files = sorted(os.listdir(dir_path)) if files: sample = files[:20] parts.append(f"目标目录 {dir_path} 现有文件:{', '.join(sample)}{' 等' if len(files) > 20 else ''}。") else: parts.append(f"目标目录 {dir_path} 为空目录。") except Exception as e: parts.append(f"无法列出目标目录内容:{e}。") parts.append("推荐:在同一条 python -c 内完成写文件和调用;若必须分步,请先 print(绝对路径) 并使用该路径。") return "".join(parts) ``` The resulting diagnostic is returned to the caller from the filter and sort file error handlers: ```python except Exception as e: print_output(False, f"❌ 无法读取 --filters-file {args.filters_file}: {e}{_build_file_not_found_hint(args.filters_file)}", {}) ``` ```python except Exception as e: print_output(False, f"❌ 无法读取 --sorts-file {args.sorts_file}: {e}{_build_file_not_found_hint(args.sorts_file)}", {}) ``` ### Technical Analysis The `--filters-file` and `--sorts-file` arguments accept caller-controlled paths. If reading one of those paths fails, `_build_file_not_found_hint()` derives the containing directory and calls `os.listdir()` on it. The resulting user-visible diagnostic include ...[truncated 1851 chars]- Remediation
View remediation
str: return "Unable to read the specified JSON file. Verify that the path exists and is accessible." ``` 2. Do not expose `NEWTON_SCRATCH_DIR`, `TEMP`, absolute directory paths, directory contents, or raw filesystem exception details. 3. Restrict file arguments to an approved scratch directory: ```python allowed_root = Path( os.environ.get("NEWTON_SCRATCH_DIR") or tempfile.gettempdir() ).resolve() requested = Path(path).resolve() if requested != allowed_root and allowed_root not in requested.parents: raise ParamError("The input file must be located in the approved scratch directory.") ``` 4. Require a regular file and reject directories, special devices, and symlinks where they are unnecessary: ```python if not requested.is_file() or requested.is_symlink(): raise ParamError("The input path must reference a regular JSON file.") ``` 5. Log detailed diagnostics only to a protected local log at an appropriate level. Return a generic error to the Agent or user. 6. Add tests confirming that paths outside the approved directory do not cause directory enumeration or reveal environment values. ]]>
