T09 · Insecure Skill Coding Practices
- Location
scripts/init_master.py:23- Finding
User-Controlled Path Traversal and File Overwrite
- Content
View full analysis
Vulnerability Details
File Location:
scripts/init_master.py, lines 23–27
Vulnerability Type: Path traversal leading to arbitrary file creation or overwrite
Risk Level: MediumVulnerable Code
python config_dir = Path.home() / ".zhua" / "distributed" config_dir.mkdir(parents=True, exist_ok=True) config_file = config_dir / f"{name}.json" with open(config_file, "w") as f: json.dump(config, f, indent=2, ensure_ascii=False)The value reaching this code is supplied directly through the command-line interface:
python parser.add_argument("--name", type=str, default="zhua-master", help="实例名称") args = parser.parse_args() init_master(args.name)Technical Analysis
The user-controlled
namevalue is incorporated directly into a filesystem path without validation or normalization. Python'spathlibdoes not prevent path components such as../from escaping the intended~/.zhua/distributeddirectory.For example, a name of
../../.config/application/settingsproduces a path equivalent to:text ~/.zhua/distributed/../../.config/application/settings.jsonThis resolves outside the intended configuration directory. The file is then opened with mode
w, which creates a missing file or truncates an existing file. The operation also follows a symbolic link if the selected destination is a symlink.The fixed
.jsonsuffix restricts the set of practical targets, but does not prevent overwriting writable JSON files or creating files in writable directories. No check confirms that the resolved destination remains beneath~/.zhua/distributed.Attack Path
-
An attacker or untrusted automation controls the
--nameargument. -
The attacker supplies a traversal value, for example:
bash python3 scripts/init_master.py \ --name '../../.config/application/settings' -
The script concatenates the value with the configuration d ...[truncated 1359 chars]
-
- Remediation
View remediation
Remediation Suggestions
-
Enforce a strict allowlist for instance names. If names are identifiers rather than paths, accept only a small safe character set:
python import re if not re.fullmatch(r"[A-Za-z0-9_-]+", name): raise ValueError( "Instance name may contain only letters, digits, underscores, and hyphens" ) -
Resolve both the base directory and destination, then verify containment before writing:
python config_dir = (Path.home() / ".zhua" / "distributed").resolve() config_dir.mkdir(parents=True, exist_ok=True) config_file = (config_dir / f"{name}.json").resolve() if config_file.parent != config_dir: raise ValueError("Invalid instance name") -
If overwriting existing configurations is not required, use exclusive creation mode (
"x") instead of"w"to prevent silent truncation. -
Defend against symbolic-link targets. On supported platforms, open files using low-level flags such as
O_NOFOLLOW, verify the opened file withfstat, and then write through the validated descriptor. -
Create configuration files with restrictive permissions appropriate for their contents, such as mode
0600, and use an atomic temporary-file-plus-rename strategy for legitimate updates. -
Add tests covering
../, absolute-path-like values, embedded separators, symlink destinations, existing files, and valid identifier names.
-
