T05 · Unauthorized Access and Privilege Escalation
Error
- Location
- scripts/generate.py:410
- Finding
- Entity Name Path Traversal Allows Writes Outside the Flutter Project<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate.py:410-419` **Vulnerability Type**: Path traversal and unauthorized filesystem write **Risk Level**: High ### Vulnerable Code ```python def cmd_model(project: str, feature: str, entity: dict): root = _validate_project_root(project) feat = _validate_feature(feature) pkg = _get_package_name(root) name = entity["name"] snake = _snake(name) db_dir = root / "lib" / feat / "database" models_dir = db_dir / "models" repo_file = db_dir / f"{snake}_repository.dart" print(f"\n📦 项目: {pkg} 功能模块: {feature} 实体: {name}\n") # 创建 Model 文件 _write(models_dir / f"{snake}_model.dart", gen_model(entity)) ``` The relevant input validation only verifies that the JSON object contains `name` and `fields`: ```python entity = json.loads(args.entity) if not isinstance(entity, dict) or "name" not in entity or "fields" not in entity: print("[错误] --entity JSON 结构非法,需包含 name 和 fields 字段") sys.exit(1) cmd_model(args.project, args.feature, entity) ``` The transformation applied to the name does not remove path components: ```python def _snake(name): return re.sub(r"(?<!^)(?=[A-Z])", "_", name).lower() ``` ### Technical Analysis Repository mode protects its `--name` argument with `_validate_name()`, but model mode directly takes `entity["name"]` from attacker-controlled JSON and uses it in output paths. No equivalent call to `_validate_name()` occurs. The `_snake()` function only inserts underscores before uppercase letters and converts the value to lowercase. It does not reject `/`, `\`, `..`, absolute path syntax, or control characters. Consequently, the following path construction can retain traversal components: ```python models_dir / f"{snake}_model.dart" ``` `_write()` then creates missing parent directories and writes the generated content: ```python def _write(path: Path, content: str, overwrite=False): path.parent.mkdir(parents=True, exist ...[truncated 2032 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Validate model entity names before using them in source code or paths: ```python name = _validate_name(entity["name"]) ``` 2. Enforce the same strict identifier policy consistently across repository and model modes. Entity names should be valid PascalCase Dart identifiers and must not contain dots, separators, whitespace, quotes, or control characters. 3. Resolve each destination and verify that it remains under the approved directory before creating directories or writing: ```python def _safe_child(base: Path, relative: str) -> Path: base = base.resolve() destination = (base / relative).resolve() try: destination.relative_to(base) except ValueError: raise ValueError(f"Output path escapes destination directory: {destination}") return destination ``` 4. Apply containment checks to both `model_file` and `repo_file`, rather than relying solely on input validation. 5. Avoid calling `mkdir()` until after containment validation succeeds. 6. Add regression tests covering `../`, nested traversal, absolute paths, backslashes, mixed separators, encoded or Unicode separator variants, and valid PascalCase names. ]]>
