T09 · Insecure Skill Coding Practices
- Location
scripts/init-user-profile.py:19- Finding
Unvalidated User Identifier Enables File Creation and Overwrite Outside the Profile Directory
- Content
View full analysis
Vulnerability Details
File Location:
scripts/init-user-profile.py, lines 19-24, 53-57, 67-71, 90-91, and 107-111
Vulnerability Type: Path traversal and unsafe file overwrite
Risk Level: HighVulnerable Code
python base_dir = os.path.expanduser("~/.openclaw/workspace/memory/intj-users") os.makedirs(base_dir, exist_ok=True) profile_path = os.path.join(base_dir, f"{user_id}-profile.md") with open(profile_path, 'w', encoding='utf-8') as f: f.write(profile_content) sessions_path = os.path.join(base_dir, f"{user_id}-sessions.md") with open(sessions_path, 'w', encoding='utf-8') as f: f.write(sessions_content) actions_path = os.path.join(base_dir, f"{user_id}-actions.md") with open(actions_path, 'w', encoding='utf-8') as f: f.write(actions_content)python user_id = sys.argv[1] user_name = sys.argv[2] if len(sys.argv) > 2 else "Unknown user" init_user_profile(user_id, user_name)Technical Analysis
The script accepts
user_iddirectly from a command-line argument and incorporates it into three filesystem paths without validation or canonicalization. Python'sos.path.join()does not guarantee that the resulting path remains underbase_dir:- An absolute second path component causes the base path to be discarded.
- Components containing
../can traverse outside the intended directory. - Filesystem links can redirect a path to another location.
- Path separators and platform-specific path syntax are not rejected.
Each destination is opened with mode
w. This creates the file if it does not exist and truncates it if it does. Therefore, a crafted identifier can cause writes outside~/.openclaw/workspace/memory/intj-users/, subject to the operating-system permissions of the process.The attacker cannot choose completely arbitrary contents because the script writes predefined profile templates containing the supplied identifier and name. However ...[truncated 1708 chars]
- Remediation
View remediation
Remediation Suggestions
-
Enforce a strict allowlist for identifiers before constructing any path:
python import re if not re.fullmatch(r"[A-Za-z0-9_-]{1,128}", user_id): raise ValueError("Invalid user identifier") -
Resolve and verify every destination remains within the intended base directory:
python from pathlib import Path base_dir = ( Path.home() / ".openclaw" / "workspace" / "memory" / "intj-users" ).resolve() destination = (base_dir / f"{user_id}-profile.md").resolve() if destination.parent != base_dir: raise ValueError("Profile path escapes the storage directory") -
Explicitly reject absolute paths, path separators,
.components,..components, null bytes, and platform-specific alternate separators. -
Use exclusive creation mode, such as
x, when an existing profile must not be overwritten. If updates are required, verify ownership and use an atomic replacement strategy. -
Avoid running the initializer with elevated privileges.
-
Protect against symbolic-link redirection by refusing links and, where supported, opening files with no-follow semantics.
-
Add automated tests covering absolute paths, traversal sequences, Unicode separator variants, excessive identifier lengths, and symbolic links.
-
