T09 · Insecure Skill Coding Practices
- Location
scripts/main.py:17- Finding
Predictable Home-Directory File Write Follows Symbolic Links and Uses Unrestricted Permissions
- Content
View full analysis
Vulnerability Details
File Location:
scripts/main.py, lines 17–18 and 29–30
Vulnerability Type: Unsafe persistent file handling
Risk Level: MediumVulnerable Code
python def __init__(self, data_file="~/.openclaw/equipment_log.json"): self.data_file = Path(data_file).expanduser() self.data_file.parent.mkdir(parents=True, exist_ok=True) self.equipment = self._load() def _save(self): with open(self.data_file, 'w') as f: json.dump(self.equipment, f, indent=2)Technical Analysis
The application stores persistent equipment records at the predictable path
~/.openclaw/equipment_log.json. The write operation uses Python's ordinaryopen(..., 'w'), which follows symbolic links and truncates an existing destination. The application does not verify that the destination is a regular file owned by the invoking user, reject symbolic links, perform an atomic replacement, or explicitly apply restrictive permissions such as0600.Consequently, an attacker who can manipulate the user's
~/.openclawdirectory or destination file could create a symbolic link fromequipment_log.jsonto another file writable by the victim. When the victim adds an equipment record, the linked file would be truncated and replaced with JSON data.The resulting file permissions also depend on the process umask. Equipment names and locations may contain operationally sensitive information, so relying solely on the ambient umask could expose these records to other local users.
This behavior also conflicts with the documentation's statement that output files are saved to the workspace: the implementation writes persistently to the user's home directory.
Attack Path
- A local attacker obtains the ability to create or replace
~/.openclaw/equipment_log.json, such as through incorrectly configured directory permissions or prior access under the same account. - The attacker creates a symboli ...[truncated 1456 chars]
- A local attacker obtains the ability to create or replace
- Remediation
View remediation
Remediation Suggestions
- Store records in a clearly documented, application-specific data directory with restrictive permissions rather than implicitly writing to an unrestricted home-directory path.
- Create
~/.openclawwith mode0700and the data file with mode0600, without relying exclusively on the process umask. - Reject symbolic-link destinations using
Path.is_symlink()and perform secure descriptor-based checks immediately before writing to reduce time-of-check/time-of-use exposure. - Where supported, open files with
os.open()usingO_NOFOLLOW,O_CREAT, and an explicit restrictive mode. - Write to a securely created temporary file in the same directory, flush and synchronize it, and atomically replace the verified destination with
os.replace(). - Before replacing an existing file, verify that it is a regular file and is owned by the expected user.
- Validate the loaded JSON structure and handle malformed or attacker-modified records without exposing stack traces.
- Update
SKILL.mdto accurately disclose the persistent home-directory write, or change the implementation so output is restricted to the documented workspace.
