T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/lib/storage.py:24
- Finding
- Insecure Permissions and Predictable Temporary Files for Sensitive Travel Data## Vulnerability Details **File Location**: `scripts/init_storage.py:6-13`; `scripts/lib/storage.py:6-12`; `scripts/lib/storage.py:24-29` **Vulnerability Type**: Plaintext sensitive-data storage, unmanaged filesystem permissions, and unsafe temporary-file handling **Risk Level**: Medium ### Vulnerable Code `scripts/init_storage.py:6-13`: ```python HOTEL_DIR = os.path.expanduser("~/.openclaw/workspace/memory/hotel") TRIPS_FILE = os.path.join(HOTEL_DIR, "trips.json") HOTELS_FILE = os.path.join(HOTEL_DIR, "hotels.json") PREFS_FILE = os.path.join(HOTEL_DIR, "preferences.json") def write_json_if_missing(path, payload): if not os.path.exists(path): with open(path, "w", encoding="utf-8") as f: json.dump(payload, f, indent=2, ensure_ascii=False) ``` `scripts/lib/storage.py:6-12`: ```python HOTEL_DIR = os.path.expanduser("~/.openclaw/workspace/memory/hotel") TRIPS_FILE = os.path.join(HOTEL_DIR, "trips.json") HOTELS_FILE = os.path.join(HOTEL_DIR, "hotels.json") PREFS_FILE = os.path.join(HOTEL_DIR, "preferences.json") def ensure_dir(): os.makedirs(HOTEL_DIR, exist_ok=True) ``` `scripts/lib/storage.py:24-29`: ```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 skill stores destinations, travel dates, budgets, purposes, notes, hotel candidates, and reusable preferences as plaintext JSON. The storage directory and files are created without explicit restrictive modes. Their effective permissions therefore depend on the process umask and any pre-existing directory permissions. `os.makedirs(..., exist_ok=True)` also does not correct an existing directory that has overly permissive permissions. Likewise, ordinary `open(path, "w")` creation uses permissions derived from the current u ...[truncated 2782 chars]
- Remediation
- ## Remediation Suggestions 1. Create and enforce the storage directory as owner-only: ```python os.makedirs(HOTEL_DIR, mode=0o700, exist_ok=True) os.chmod(HOTEL_DIR, 0o700) ``` 2. Create initial data files with mode `0600` by using `os.open` with explicit flags and permissions rather than relying on the process umask: ```python fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600) with os.fdopen(fd, "w", encoding="utf-8") as f: json.dump(payload, f, indent=2, ensure_ascii=False) ``` 3. Replace the fixed `.tmp` name with a securely created temporary file in the same directory: ```python import tempfile directory = os.path.dirname(path) fd, tmp = tempfile.mkstemp(prefix=".hotel-", suffix=".tmp", dir=directory) try: os.fchmod(fd, 0o600) with os.fdopen(fd, "w", encoding="utf-8") as f: json.dump(data, f, indent=2, ensure_ascii=False) f.flush() os.fsync(f.fileno()) os.replace(tmp, path) os.chmod(path, 0o600) finally: if os.path.exists(tmp): os.unlink(tmp) ``` 4. Validate that the storage directory is a real directory owned by the current user and is not a symbolic link before writing. 5. Check and repair permissions on existing JSON files during initialization. Refuse to operate, or issue a clear warning, if ownership or directory permissions are unsafe. 6. Consider minimizing sensitive free-form notes and documenting that the files are plaintext. If stronger local confidentiality is required, use operating-system-backed encryption or a suitable protected credential/data store.
