T09 · Insecure Skill Coding Practices
- Location
game_engine.py:260- Finding
Path Traversal in Save and Load Operations
- Content
View full analysis
Vulnerability Details
File Location:
game_engine.py, lines 260–271
Vulnerability Type: Path traversal and unrestricted filesystem access
Risk Level: MediumVulnerable Code
python def _save_game(self, save_name: str = "default") -> None: """保存游戏进度""" save_file = os.path.join(self.save_path, f"{save_name}.json") with open(save_file, "w", encoding="utf-8") as f: json.dump(self.game_state, f, ensure_ascii=False, indent=2) def _load_game(self, save_name: str = "default") -> None: """加载游戏进度""" save_file = os.path.join(self.save_path, f"{save_name}.json") if os.path.exists(save_file): with open(save_file, "r", encoding="utf-8") as f: self.game_state = json.load(f)Technical Analysis
The
_save_gameand_load_gamemethods interpolate the caller-controlledsave_namevalue directly into a filesystem path. The code neither restricts the value to a safe filename format nor verifies that the resolved path remains insideself.save_path.A value containing parent-directory components, such as
../../target, can escape the configured save directory. Depending on platform path semantics, an absolutesave_namemay also causeos.path.join()to discard the intended base directory.The forced
.jsonsuffix limits the reachable filenames but does not prevent traversal. These methods are nominally private and the current command processor invokes them only with the default value; therefore, direct exploitation requires another integration, extension, or caller to expose attacker-controlled save-slot names.Attack Path
- An application integrates
TextAdventureEngineand exposes custom save-slot names to an untrusted user. - The attacker supplies a traversal value such as
../../some/writable/location/target. _save_game()or_load_game()appends.jsonand combines the result withself.save_path.- The operating system resolves the
..components, causing acces ...[truncated 1116 chars]
- An application integrates
- Remediation
View remediation
Remediation Suggestions
- Restrict save names to a conservative identifier format, such as
^[A-Za-z0-9_-]+$, and reject empty names, path separators, drive prefixes, absolute paths, and.or..components. - Resolve both the save directory and candidate file to canonical absolute paths, then verify that the candidate remains beneath the save directory before opening it.
- Use
pathlib.Pathfor explicit path handling:
python import re from pathlib import Path def _get_save_file(self, save_name: str) -> Path: if not re.fullmatch(r"[A-Za-z0-9_-]+", save_name): raise ValueError("Invalid save name") base = Path(self.save_path).resolve() candidate = (base / f"{save_name}.json").resolve() if candidate.parent != base: raise ValueError("Save path escapes the save directory") return candidate- Use the validated helper in both
_save_game()and_load_game(). - Treat loaded save data as untrusted. Validate its schema, required keys, field types, string lengths, list sizes, and numeric ranges before assigning it to
self.game_state. - Handle missing, malformed, oversized, or incompatible JSON files with controlled error reporting rather than leaving the engine in an invalid state.
- If multiple users can run the application, isolate save directories per user and apply restrictive filesystem permissions.
- Restrict save names to a conservative identifier format, such as
