T09 · Insecure Skill Coding Practices
- Location
scripts/lib/storage.py:23- Finding
Predictable Temporary File Permits Symlink-Based File Overwrite
- Content
View full analysis
Vulnerability Details
File Location:
scripts/lib/storage.py:23-27
Vulnerability Type: Unsafe temporary-file handling
Risk Level: MediumVulnerable Code
python def _atomic_save(path, data): ensure_dir() tmp = path + ".tmp" with open(tmp, "w", encoding="utf-8") as f: json.dump(data, f, indent=2, ensure_ascii=False) os.replace(tmp, path)Technical Analysis
The
_atomic_savefunction uses a fixed temporary-file name derived by appending.tmpto the destination path. It opens that path with the normal"w"mode, which neither creates the file exclusively nor prevents symbolic-link traversal.If another local process can write to
~/.openclaw/workspace/memory/chart/, it can createcharts.json.tmpas a symbolic link to a file writable by the account running the skill. When the skill saves chart metadata,open()follows the symbolic link and truncates the target before writing JSON data. The subsequentos.replace()operation does not undo the modification already made through the link.Attack Path
- An attacker obtains write access to the chart storage directory under the victim account.
- The attacker creates
charts.json.tmpas a symbolic link to another file that the victim account can write. - The attacker waits for or induces execution of
make_chart.py, which eventually callssave_charts(). _atomic_save()opens the predictable temporary path in write mode.- The operating system follows the symbolic link, truncating the linked target and replacing its contents with chart metadata.
- The target file is corrupted or overwritten under the privileges of the account running the skill.
Impact Assessment
Successful exploitation permits corruption or overwrite of an arbitrary file writable by the skill's operating-system account. This could cause loss of user data or alter user-level configuration, depending on the selected ta ...[truncated 261 chars]
- Remediation
View remediation
Remediation Suggestions
- Create the temporary file securely and unpredictably in the destination directory with
tempfile.NamedTemporaryFile(delete=False, dir=destination_directory, mode="w", encoding="utf-8"). - Ensure the temporary file is created exclusively and is not a symbolic link.
- Flush buffered data and call
os.fsync()before atomically replacing the destination when durability is required. - Place
os.replace()in a guarded workflow and remove the temporary file on failure. - Enforce owner-only permissions on the storage directory and metadata files, such as
0700for directories and0600for files. - Where supported, use secure descriptor-based operations or no-follow semantics to further reduce symbolic-link race risks.
A hardened implementation should resemble:
python import os import tempfile def _atomic_save(path, data): ensure_dir() directory = os.path.dirname(path) tmp_path = None try: with tempfile.NamedTemporaryFile( mode="w", encoding="utf-8", dir=directory, prefix=".charts-", suffix=".tmp", delete=False, ) as f: tmp_path = f.name json.dump(data, f, indent=2, ensure_ascii=False) f.flush() os.fsync(f.fileno()) os.replace(tmp_path, path) tmp_path = None finally: if tmp_path is not None: try: os.unlink(tmp_path) except FileNotFoundError: pass- Create the temporary file securely and unpredictably in the destination directory with
